Version 4.6.0
This commit is contained in:
1 parent
f79dcf067a
commit
517a5e1f70
2036 files changed
+110041
-26162
No files matched your search
@@ -157,7 +157,23 @@ class _Application extends \IPS\Application
|
||||
/* Save installed domain to spam defense whitelist */
|
||||
$domain = rtrim( str_replace( 'www.', '', parse_url( \IPS\Settings::i()->base_url, PHP_URL_HOST ) ), '/' );
|
||||
\IPS\Db::i()->insert( 'core_spam_whitelist', array( 'whitelist_type' => 'domain', 'whitelist_content' => $domain, 'whitelist_date' => time(), 'whitelist_reason' => 'Invision Community Domain' ) );
|
||||
|
||||
|
||||
/* Generate VAPID keys for web push notifications */
|
||||
try
|
||||
{
|
||||
$vapid = \IPS\Notification::generateVapidKeys();
|
||||
\IPS\Settings::i()->changeValues( array( 'vapid_public_key' => $vapid['publicKey'], 'vapid_private_key' => $vapid['privateKey'] ) );
|
||||
}
|
||||
catch (\Exception $ex)
|
||||
{
|
||||
\IPS\Log::log( $ex, 'create_vapid_keys' );
|
||||
}
|
||||
|
||||
/* Install default ranks, rules and badges */
|
||||
\IPS\core\Achievements\Rule::importXml( $this->getApplicationPath() . "/data/achievements/rules.xml" );
|
||||
\IPS\core\Achievements\Rank::importXml( $this->getApplicationPath() . "/data/achievements/ranks.xml" );
|
||||
\IPS\core\Achievements\Badge::importXml( $this->getApplicationPath() . "/data/achievements/badges.xml" );
|
||||
|
||||
if ( \IPS\CIC2 )
|
||||
{
|
||||
\IPS\Cicloud\postInstall();
|
||||
@@ -177,7 +193,8 @@ class _Application extends \IPS\Application
|
||||
return (
|
||||
$module->key == 'system'
|
||||
and
|
||||
\in_array( $controller, array( 'login', 'register', 'lostpass', 'terms', 'ajax', 'privacy', 'editor', 'language', 'theme', 'redirect', 'guidelines', 'announcement', 'metatags', 'marketplace' ) )
|
||||
\in_array( $controller, array( 'login', 'register', 'lostpass', 'terms', 'ajax', 'privacy', 'editor',
|
||||
'language', 'theme', 'redirect', 'guidelines', 'announcement', 'metatags', 'marketplace', 'serviceworker', 'offline' ) )
|
||||
)
|
||||
or
|
||||
(
|
||||
@@ -207,12 +224,16 @@ class _Application extends \IPS\Application
|
||||
'announcement', // Announcements can be useful when the site is offline
|
||||
'redirect', // When email tracking is enabled we pass through here
|
||||
'marketplace', // Remote services needs to send data back
|
||||
'metatags', // Manifest
|
||||
'serviceworker', // Service Worker
|
||||
'offline', // Service Worker offline page
|
||||
) )
|
||||
or
|
||||
(
|
||||
$controller === 'ajax' and
|
||||
( $do === 'states' OR // Makes sure address input still works within the ACP otherwise the form to turn site back online is broken
|
||||
$do === 'passwordStrength' ) // Makes sure the password strength meter still works because it is used in the AdminCP and registration
|
||||
$do === 'passwordStrength' OR // Makes sure the password strength meter still works because it is used in the AdminCP and registration
|
||||
$do === 'getCsrfKey' ) // Makes sure we can still fetch the correct CSRF key for the ajax replacement
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
@@ -132,7 +132,7 @@ class _Follow
|
||||
$class = 'IPS\Member\Club';
|
||||
}
|
||||
|
||||
if ( !$class )
|
||||
if ( !$class or !array_key_exists( $args['app'], \IPS\Application::applications() ) )
|
||||
{
|
||||
throw new \IPS\Api\GraphQL\SafeException( 'NOT_FOUND', 'GQL/0001/4', 404 );
|
||||
}
|
||||
@@ -150,19 +150,23 @@ class _Follow
|
||||
{
|
||||
if ( \in_array( 'IPS\Node\Model', class_parents( $class ) ) )
|
||||
{
|
||||
$thing = $class::loadAndCheckPerms( $args['id'] );
|
||||
$thing = $class::loadAndCheckPerms( (int) $args['id'] );
|
||||
}
|
||||
elseif ( $class == 'IPS\Member\Club' )
|
||||
{
|
||||
$thing = $class::loadAndCheckPerms( $args['id'] );
|
||||
$thing = $class::loadAndCheckPerms( (int) $args['id'] );
|
||||
}
|
||||
elseif ( $class != "IPS\Member" )
|
||||
{
|
||||
$thing = $class::loadAndCheckPerms( $args['id'] );
|
||||
$thing = $class::loadAndCheckPerms( (int) $args['id'] );
|
||||
}
|
||||
else
|
||||
{
|
||||
$thing = $class::load( $args['id'] );
|
||||
if( !$class instanceof \IPS\Content\Followable )
|
||||
{
|
||||
throw new \OutOfRangeException;
|
||||
}
|
||||
$thing = $class::load( (int) $args['id'] );
|
||||
}
|
||||
}
|
||||
catch ( \OutOfRangeException $e )
|
||||
|
||||
@@ -65,10 +65,10 @@ class _SessionEnd
|
||||
throw new \IPS\Api\GraphQL\SafeException( 'NOT_LOGGED_IN', 'GQL/0001/6', 403 );
|
||||
}
|
||||
|
||||
\IPS\Db::i()->delete( 'core_oauth_server_access_tokens', array( 'member_id=? AND access_token=?', \IPS\Member::loggedIn()->member_id, \IPS\Dispatcher::i()->accessToken['access_token'] ) );
|
||||
\IPS\Db::i()->update( 'core_oauth_server_access_tokens', array( 'status' => 'revoked' ), array( 'member_id=? AND access_token=?', \IPS\Member::loggedIn()->member_id, \IPS\Dispatcher::i()->accessToken['access_token'] ) );
|
||||
if ( isset( \IPS\Dispatcher::i()->accessToken['device_key'] ) )
|
||||
{
|
||||
\IPS\Db::i()->delete( 'core_oauth_server_access_tokens', array( 'member_id=? AND device_key=?', \IPS\Member::loggedIn()->member_id, \IPS\Dispatcher::i()->accessToken['device_key'] ) );
|
||||
\IPS\Db::i()->update( 'core_oauth_server_access_tokens', array( 'status' => 'revoked' ), array( 'member_id=? AND device_key=?', \IPS\Member::loggedIn()->member_id, \IPS\Dispatcher::i()->accessToken['device_key'] ) );
|
||||
}
|
||||
|
||||
if ( isset( $args['token'] ) and $args['token'] )
|
||||
|
||||
@@ -116,6 +116,11 @@ class _Unfollow
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( !$class or !array_key_exists( $args['app'], \IPS\Application::applications() ) )
|
||||
{
|
||||
throw new \IPS\Api\GraphQL\SafeException( 'NOT_FOUND', 'GQL/0001/7', 404 );
|
||||
}
|
||||
|
||||
/* Get our return info ready */
|
||||
$return = array(
|
||||
@@ -131,11 +136,11 @@ class _Unfollow
|
||||
{
|
||||
if ( $class != "IPS\Member" )
|
||||
{
|
||||
$thing = $class::loadAndCheckPerms( $follow['follow_rel_id'] );
|
||||
$thing = $class::loadAndCheckPerms( (int) $follow['follow_rel_id'] );
|
||||
}
|
||||
else
|
||||
{
|
||||
$thing = $class::load( $follow['follow_rel_id'] );
|
||||
$thing = $class::load( (int) $follow['follow_rel_id'] );
|
||||
}
|
||||
|
||||
/* Unfollow club areas */
|
||||
|
||||
@@ -116,7 +116,7 @@ class _UploadAttachment
|
||||
$file = \IPS\File::get( 'core_Attachment', $url );
|
||||
|
||||
/* If it's got an image extension, check it's actually a valid image */
|
||||
if ( \in_array( $ext, \IPS\Image::$imageExtensions ) )
|
||||
if ( \in_array( $ext, \IPS\Image::supportedExtensions() ) )
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -142,7 +142,7 @@ class _UploadAttachment
|
||||
else
|
||||
{
|
||||
/* If it's got an image extension, check it's actually a valid image */
|
||||
if ( \in_array( $ext, \IPS\Image::$imageExtensions ) )
|
||||
if ( \in_array( $ext, \IPS\Image::supportedExtensions() ) )
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief GraphQL: Stats query
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Community Suite
|
||||
* @since 21 Sept 2020
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\core\api\GraphQL\Queries;
|
||||
use GraphQL\Type\Definition\ObjectType;
|
||||
use IPS\Api\GraphQL\TypeRegistry;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stats query for GraphQL API
|
||||
*/
|
||||
class _Stats
|
||||
{
|
||||
/*
|
||||
* @brief Query description
|
||||
*/
|
||||
public static $description = "Returns community stats";
|
||||
|
||||
/*
|
||||
* Query arguments
|
||||
*/
|
||||
public function args()
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the query return type
|
||||
*/
|
||||
public function type()
|
||||
{
|
||||
return \IPS\core\api\GraphQL\TypeRegistry::stats();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves this query
|
||||
*
|
||||
* @param mixed Value passed into this resolver
|
||||
* @param array Arguments
|
||||
* @param array Context values
|
||||
* @return \IPS\core\Stream
|
||||
*/
|
||||
public function resolve($val, $args, $context)
|
||||
{
|
||||
return $val;
|
||||
}
|
||||
}
|
||||
@@ -52,6 +52,7 @@ abstract class _Query
|
||||
'popularContributors' => new \IPS\core\api\GraphQL\Queries\PopularContributors(),
|
||||
'search' => new \IPS\core\api\GraphQL\Queries\Search(),
|
||||
'settings' => new \IPS\core\api\GraphQL\Queries\Settings(),
|
||||
'stats' => new \IPS\core\api\GraphQL\Queries\Stats(),
|
||||
'stream' => new \IPS\core\api\GraphQL\Queries\Stream(),
|
||||
'streams' => new \IPS\core\api\GraphQL\Queries\Streams(),
|
||||
];
|
||||
|
||||
@@ -58,6 +58,7 @@ class _TypeRegistry
|
||||
protected static $reportReason;
|
||||
protected static $search;
|
||||
protected static $searchResult;
|
||||
protected static $stats;
|
||||
protected static $stream;
|
||||
protected static $tag;
|
||||
protected static $settings;
|
||||
@@ -319,6 +320,14 @@ class _TypeRegistry
|
||||
return self::$search ?: (self::$search = new \IPS\core\api\GraphQL\Types\SearchType());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return StatsType
|
||||
*/
|
||||
public static function stats()
|
||||
{
|
||||
return self::$stats ?: (self::$stats = new \IPS\core\api\GraphQL\Types\StatsType());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return StreamType
|
||||
*/
|
||||
|
||||
@@ -79,7 +79,7 @@ class _MemberType extends ObjectType
|
||||
'type' => TypeRegistry::string(),
|
||||
'description' => "Returns the member's title",
|
||||
'resolve' => function( $member, $args, $context, $info ) {
|
||||
return $member->member_title;
|
||||
return null;
|
||||
}
|
||||
],
|
||||
'timezone' => [
|
||||
|
||||
@@ -97,9 +97,6 @@ class _SettingsType extends ObjectType
|
||||
'allow_reg_target' => [
|
||||
'type' => TypeRegistry::string()
|
||||
],
|
||||
'disable_anonymous' => [
|
||||
'type' => TypeRegistry::boolean()
|
||||
],
|
||||
'allow_result_view' => [
|
||||
'type' => TypeRegistry::boolean()
|
||||
],
|
||||
|
||||
@@ -0,0 +1,148 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief GraphQL: Stats Type
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Community Suite
|
||||
* @since 21 Sep 2020
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\core\api\GraphQL\Types;
|
||||
use GraphQL\Type\Definition\ObjectType;
|
||||
use IPS\Api\GraphQL\TypeRegistry;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* StatsType for GraphQL API
|
||||
*/
|
||||
class _StatsType extends ObjectType
|
||||
{
|
||||
/**
|
||||
* Get object type
|
||||
*
|
||||
* @return ObjectType
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$config = [
|
||||
'name' => 'core_Stats',
|
||||
'description' => 'Statistics',
|
||||
'fields' => function () {
|
||||
return [
|
||||
'contentCount' => [
|
||||
'type' => TypeRegistry::int(),
|
||||
'description' => "Content count",
|
||||
'resolve' => function () {
|
||||
return ( isset( \IPS\Settings::i()->mobile_app_hide_stats ) && \IPS\Settings::i()->mobile_app_hide_stats ) ? NULL : static::getContentCount();
|
||||
}
|
||||
],
|
||||
'memberCount' => [
|
||||
'type' => TypeRegistry::int(),
|
||||
'description' => 'Member count',
|
||||
'resolve' => function () {
|
||||
return ( isset( \IPS\Settings::i()->mobile_app_hide_stats ) && \IPS\Settings::i()->mobile_app_hide_stats ) ? NULL : static::getMemberCount();
|
||||
}
|
||||
]
|
||||
];
|
||||
}
|
||||
];
|
||||
|
||||
parent::__construct($config);
|
||||
}
|
||||
|
||||
protected static function getContentCount()
|
||||
{
|
||||
$cacheKey = 'content_count';
|
||||
$total = 0;
|
||||
|
||||
try
|
||||
{
|
||||
return \IPS\Data\Cache::i()->getWithExpire( $cacheKey, TRUE );
|
||||
}
|
||||
catch( \OutOfRangeException $e ){}
|
||||
|
||||
foreach( \IPS\Application::enabledApplications() as $app )
|
||||
{
|
||||
foreach( $app->extensions( 'core', 'ContentRouter', TRUE, TRUE ) as $object )
|
||||
{
|
||||
foreach( $object->classes as $itemClass )
|
||||
{
|
||||
foreach( array( 'items', 'comments', 'reviews' ) as $type )
|
||||
{
|
||||
try
|
||||
{
|
||||
$classes = [];
|
||||
switch ( $type )
|
||||
{
|
||||
case 'items':
|
||||
$classes[] = $itemClass;
|
||||
break;
|
||||
case 'comments':
|
||||
if ( isset( $itemClass::$commentClass ) )
|
||||
{
|
||||
$classes[] = $itemClass::$commentClass;
|
||||
}
|
||||
if ( isset( $itemClass::$archiveClass ) )
|
||||
{
|
||||
$classes[] = $itemClass::$archiveClass;
|
||||
}
|
||||
break;
|
||||
case 'reviews':
|
||||
if ( isset( $itemClass::$reviewClass ) )
|
||||
{
|
||||
$classes[] = $itemClass::$reviewClass;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if ( $classes )
|
||||
{
|
||||
foreach ( $classes as $class )
|
||||
{
|
||||
$where = method_exists( $class, 'digestWhere' ) ? $class::digestWhere() : [];
|
||||
if ( isset( $class::$databaseColumnMap['approved'] ) )
|
||||
{
|
||||
$where[] = [ $class::$databasePrefix . $class::$databaseColumnMap['approved'] . '=1' ];
|
||||
}
|
||||
if ( isset( $class::$databaseColumnMap['hidden'] ) )
|
||||
{
|
||||
$where[] = [ $class::$databasePrefix . $class::$databaseColumnMap['hidden'] . '=0' ];
|
||||
}
|
||||
|
||||
$total += $class::db()->select( 'COUNT(*)', $class::$databaseTable, $where )->first();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch( \Exception $e ){}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
\IPS\Data\Cache::i()->storeWithExpire( $cacheKey, $total, \IPS\DateTime::create()->add( new \DateInterval('P1W') ), TRUE );
|
||||
|
||||
return $total;
|
||||
}
|
||||
|
||||
protected static function getMemberCount()
|
||||
{
|
||||
try
|
||||
{
|
||||
$memberCount = \IPS\Db::i()->select( 'COUNT(*)', 'core_members', array( 'completed=?', true ) )->first();
|
||||
return $memberCount;
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -699,7 +699,13 @@ class _clubs extends \IPS\Api\Controller
|
||||
try
|
||||
{
|
||||
$class = \IPS\Request::i()->class;
|
||||
$node = $class::load( \IPS\Request::i()->id );
|
||||
|
||||
if( !is_subclass_of( $class, "\IPS\Node\Model" ) )
|
||||
{
|
||||
throw new \OutOfRangeException;
|
||||
}
|
||||
|
||||
$node = $class::load( (int) \IPS\Request::i()->id );
|
||||
|
||||
if ( !$node->club() or $node->club()->id !== $club->id )
|
||||
{
|
||||
|
||||
@@ -30,13 +30,15 @@ class _hello extends \IPS\Api\Controller
|
||||
* @apiresponse string communityName The name of the community
|
||||
* @apiresponse string communityUrl The community URL
|
||||
* @apiresponse string ipsVersion The Invision Community version number
|
||||
* @apiresponse array applications The installed IPS Applications
|
||||
*/
|
||||
public function GETindex()
|
||||
{
|
||||
return new \IPS\Api\Response( 200, array(
|
||||
'communityName' => \IPS\Settings::i()->board_name,
|
||||
'communityUrl' => \IPS\Settings::i()->base_url,
|
||||
'ipsVersion' => \IPS\Application::load('core')->version
|
||||
) );
|
||||
'ipsApplications' => \IPS\Application::load('core')->version,
|
||||
'ipsApplications' => array_filter( array_keys( \IPS\Application::applications() ), function( $k ) { return \in_array( $k, \IPS\IPS::$ipsApps ); } )
|
||||
) );
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,14 @@ if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
*/
|
||||
class _members extends \IPS\Api\Controller
|
||||
{
|
||||
/**
|
||||
* @brief Parameters to mask in logs. Keys are the method names and values an array of field or request keys.
|
||||
*/
|
||||
public $parametersToMask = array(
|
||||
'POSTindex' => array( 'password' ),
|
||||
'POSTitem' => array( 'password' ),
|
||||
);
|
||||
|
||||
/**
|
||||
* GET /core/members
|
||||
* Get list of members
|
||||
@@ -134,8 +142,11 @@ class _members extends \IPS\Api\Controller
|
||||
{
|
||||
$existingUsername = \IPS\Member::load( \IPS\Request::i()->name, 'name' );
|
||||
if ( !$existingUsername->member_id )
|
||||
{
|
||||
$member->logHistory( 'core', 'display_name', array( 'old' => $member->name, 'new' => \IPS\Request::i()->name, 'by' => 'api' ) );
|
||||
{
|
||||
if ( $member->member_id )
|
||||
{
|
||||
$member->logHistory( 'core', 'display_name', array( 'old' => $member->name, 'new' => \IPS\Request::i()->name, 'by' => 'api' ) );
|
||||
}
|
||||
$member->name = \IPS\Request::i()->name;
|
||||
}
|
||||
else
|
||||
@@ -148,10 +159,15 @@ class _members extends \IPS\Api\Controller
|
||||
{
|
||||
$existingEmail = \IPS\Member::load( \IPS\Request::i()->email, 'email' );
|
||||
if ( !$existingEmail->member_id )
|
||||
{
|
||||
$member->logHistory( 'core', 'email_change', array( 'old' => $member->name, 'new' => \IPS\Request::i()->name, 'by' => 'api' ) );
|
||||
{
|
||||
/* Only do this if we are updating a member */
|
||||
if ( $member->member_id )
|
||||
{
|
||||
$member->logHistory( 'core', 'email_change', array( 'old' => $member->email, 'new' => \IPS\Request::i()->email, 'by' => 'api' ) );
|
||||
$member->invalidateSessionsAndLogins();
|
||||
}
|
||||
|
||||
$member->email = \IPS\Request::i()->email;
|
||||
$member->invalidateSessionsAndLogins();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -161,15 +177,50 @@ class _members extends \IPS\Api\Controller
|
||||
|
||||
if ( isset( \IPS\Request::i()->group ) )
|
||||
{
|
||||
try
|
||||
if( \is_array( \IPS\Request::i()->group ) )
|
||||
{
|
||||
$group = \IPS\Member\Group::load( \IPS\Request::i()->group );
|
||||
$member->member_group_id = $group->g_id;
|
||||
$groups = \IPS\Request::i()->group;
|
||||
$group = array_shift( $groups );
|
||||
|
||||
try
|
||||
{
|
||||
$group = \IPS\Member\Group::load( $group );
|
||||
$member->member_group_id = $group->g_id;
|
||||
}
|
||||
catch ( \OutOfRangeException $e )
|
||||
{
|
||||
throw new \IPS\Api\Exception( 'INVALID_GROUP', '1C292/6', 403 );
|
||||
}
|
||||
|
||||
if( \count( $groups ) )
|
||||
{
|
||||
if( !isset( \IPS\Request::i()->secondaryGroups ) )
|
||||
{
|
||||
\IPS\Request::i()->secondaryGroups = $groups;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( !\is_array( \IPS\Request::i()->secondaryGroups ) )
|
||||
{
|
||||
\IPS\Request::i()->secondaryGroups = array( \IPS\Request::i()->secondaryGroups );
|
||||
}
|
||||
\IPS\Request::i()->secondaryGroups = array_merge( \IPS\Request::i()->secondaryGroups , \IPS\Request::i()->group );
|
||||
}
|
||||
}
|
||||
}
|
||||
catch ( \OutOfRangeException $e )
|
||||
else
|
||||
{
|
||||
throw new \IPS\Api\Exception( 'INVALID_GROUP', '1C292/6', 403 );
|
||||
try
|
||||
{
|
||||
$group = \IPS\Member\Group::load( \IPS\Request::i()->group );
|
||||
$member->member_group_id = $group->g_id;
|
||||
}
|
||||
catch ( \OutOfRangeException $e )
|
||||
{
|
||||
throw new \IPS\Api\Exception( 'INVALID_GROUP', '1C292/6', 403 );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if( isset( \IPS\Request::i()->secondaryGroups ) AND \is_array( \IPS\Request::i()->secondaryGroups ) )
|
||||
@@ -202,7 +253,7 @@ class _members extends \IPS\Api\Controller
|
||||
{
|
||||
foreach( \IPS\Request::i()->rawProperties as $property => $value )
|
||||
{
|
||||
$member->$property = $value;
|
||||
$member->$property = \is_numeric( $value ) ? (int) $value : $value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -288,7 +339,7 @@ class _members extends \IPS\Api\Controller
|
||||
* @apiparam string name Username
|
||||
* @apiparam string email Email address
|
||||
* @apiparam string password Password (standard login handler only). If not provided, the member will be emailed to set one.
|
||||
* @apiparam int group Group ID number
|
||||
* @apiparam int|array group Group ID number ; if an array was provided, the first item will be used for the primary group and everything else for the secondary.
|
||||
* @apiparam string registrationIpAddress IP Address
|
||||
* @apiparam array secondaryGroups Secondary group IDs, or empty value to reset secondary groups
|
||||
* @apiparam object customFields Array of custom fields as fieldId => fieldValue
|
||||
@@ -339,7 +390,7 @@ class _members extends \IPS\Api\Controller
|
||||
* @apiparam string name Username
|
||||
* @apiparam string email Email address
|
||||
* @apiparam string password Password (standard login handler only)
|
||||
* @apiparam int group Group ID number
|
||||
* @apiparam int|array group Group ID number ; if an array was provided, the first item will be used for the primary group and everything else for the secondary.
|
||||
* @apiparam string registrationIpAddress IP Address
|
||||
* @apiparam array secondaryGroups Secondary group IDs, or empty value to reset secondary groups
|
||||
* @apiparam object customFields Array of custom fields as fieldId => fieldValue
|
||||
@@ -391,7 +442,7 @@ class _members extends \IPS\Api\Controller
|
||||
*
|
||||
* @apiclientonly
|
||||
* @apiparam string contentAction delete|hide|leave
|
||||
* @apiparam bool contentAnonymize Keep member name or anonymize content
|
||||
* @apiparam bool contentAnonymize Keep member name = 1, anonymize content = 0
|
||||
* @param int $id ID Number
|
||||
* @throws 1C292/2 INVALID_ID The member ID does not exist
|
||||
* @return void
|
||||
@@ -415,6 +466,9 @@ class _members extends \IPS\Api\Controller
|
||||
$member->delete( FALSE );
|
||||
break;
|
||||
case 'hide':
|
||||
$member->hideOrDeleteAllContent( 'hide' );
|
||||
$member->delete( TRUE, (bool) \IPS\Request::i()->contentAnonymize ?: FALSE );
|
||||
break;
|
||||
case 'leave':
|
||||
$member->delete( TRUE, (bool) \IPS\Request::i()->contentAnonymize ?: FALSE );
|
||||
break;
|
||||
@@ -516,12 +570,12 @@ class _members extends \IPS\Api\Controller
|
||||
{
|
||||
$classToFollow = 'IPS\\' . \IPS\Request::i()->followApp . '\\' . mb_ucfirst( \IPS\Request::i()->followArea );
|
||||
|
||||
if( !class_exists( $classToFollow ) )
|
||||
if( !class_exists( $classToFollow ) or !array_key_exists( \IPS\Request::i()->follow_app, \IPS\Application::applications() ) )
|
||||
{
|
||||
throw new \OutOfRangeException;
|
||||
}
|
||||
|
||||
$thingToFollow = $classToFollow::load( \IPS\Request::i()->followId );
|
||||
$thingToFollow = $classToFollow::load( (int) \IPS\Request::i()->followId );
|
||||
}
|
||||
catch( \Exception $e )
|
||||
{
|
||||
@@ -546,9 +600,34 @@ class _members extends \IPS\Api\Controller
|
||||
$follow->notify_do = ( isset( \IPS\Request::i()->followType ) AND \IPS\Request::i()->followType == 'none' ) ? 0 : ( ( isset( \IPS\Request::i()->followNotify ) ) ? (int) \IPS\Request::i()->followNotify : 1 );
|
||||
$follow->notify_freq = ( isset( \IPS\Request::i()->followType ) AND \in_array( \IPS\Request::i()->followType, array( 'none', 'immediate', 'daily', 'weekly' ) ) ) ? \IPS\Request::i()->followType : 'immediate';
|
||||
$follow->save();
|
||||
|
||||
|
||||
/* Delete cache */
|
||||
\IPS\Db::i()->delete( 'core_follow_count_cache', array( 'class=? AND id=?', $classToFollow, $follow->rel_id ) );
|
||||
|
||||
/* If we're following a member, add points */
|
||||
if ( $follow->app == 'core' and $follow->area == 'member' )
|
||||
{
|
||||
/* Give points */
|
||||
$receiver = \IPS\Member::load( $follow->rel_id );
|
||||
$receiver->achievementAction( 'core', 'FollowMember', [
|
||||
'giver' => \IPS\Member::load( $follow->member_id )
|
||||
] );
|
||||
}
|
||||
else if ( \in_array( 'IPS\Node\Model', class_parents( $classToFollow ) ) )
|
||||
{
|
||||
$member->achievementAction( 'core', 'FollowNode', $classToFollow::load( \IPS\Request::i()->followId ) );
|
||||
}
|
||||
else if ( \in_array( 'IPS\Content\Item', class_parents( $classToFollow ) ) )
|
||||
{
|
||||
$item = $classToFollow::load( \IPS\Request::i()->followId );
|
||||
$member->achievementAction( 'core', 'FollowContentItem', [
|
||||
'item' => $item,
|
||||
'author' => $item->author()
|
||||
] );
|
||||
}
|
||||
|
||||
/* If we're following a club, follow all nodes in the club automatically */
|
||||
if( $follow->app == 'core' and $follow->area == 'club' )
|
||||
if ( $follow->app == 'core' and $follow->area == 'club' )
|
||||
{
|
||||
$thing = \IPS\Member\Club::loadAndCheckPerms( $follow->rel_id );
|
||||
|
||||
@@ -576,6 +655,9 @@ class _members extends \IPS\Api\Controller
|
||||
$nodeFollow->notify_do = $follow->notify_do;
|
||||
$nodeFollow->notify_freq = $follow->notify_freq;
|
||||
$nodeFollow->save();
|
||||
|
||||
/* Delete cache */
|
||||
\IPS\Db::i()->delete( 'core_follow_count_cache', array( 'class=? AND id=?', $itemClass, $nodeFollow->rel_id ) );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -698,10 +780,10 @@ class _members extends \IPS\Api\Controller
|
||||
/* Return */
|
||||
return new \IPS\Api\PaginatedResponse(
|
||||
200,
|
||||
\IPS\Db::i()->select( '*', 'core_notifications', array( '`member`=?', $member->member_id ), "updated_time DESC" ),
|
||||
\IPS\Db::i()->select( '*', 'core_notifications', array( "`member`=? AND notification_app IN('" . implode( "','", array_keys( \IPS\Application::enabledApplications() ) ) . "')", $member->member_id ), "updated_time DESC" ),
|
||||
isset( \IPS\Request::i()->page ) ? \IPS\Request::i()->page : 1,
|
||||
'IPS\Notification\Inline',
|
||||
\IPS\Db::i()->select( 'COUNT(*)', 'core_notifications', array( '`member`=?', $member->member_id ) )->first(),
|
||||
\IPS\Db::i()->select( 'COUNT(*)', 'core_notifications', array( "`member`=? AND notification_app IN('" . implode( "','", array_keys( \IPS\Application::enabledApplications() ) ) . "')", $member->member_id ) )->first(),
|
||||
$this->member,
|
||||
isset( \IPS\Request::i()->perPage ) ? \IPS\Request::i()->perPage : NULL
|
||||
);
|
||||
@@ -824,6 +906,10 @@ class _members extends \IPS\Api\Controller
|
||||
* @throws 2C292/G NO_PERMISSION The authorized user does not have permission to warn the member
|
||||
* @throws 2C292/O INVALID_ID The member could not be found
|
||||
* @throws 1C292/Y MODERATOR_REQUIRED When not using an OAuth access token a moderator member ID must be supplied
|
||||
* @throws 1C292/Z INVALID_DATE An invalid datetime was supplied for the expire parameter
|
||||
* @throws 1C292/12 INVALID_DATE An invalid datetime was supplied for the suspend parameter
|
||||
* @throws 1C292/11 INVALID_DATE An invalid datetime was supplied for the restrictPosts parameter
|
||||
* @throws 1C292/10 INVALID_DATE An invalid datetime was supplied for the modQueue parameter
|
||||
* @note The warning will be issued as the current authorized user if using an OAuth access token, otherwise the 'moderator' parameter must be specified to indicate which moderator the warning should be issued from
|
||||
*/
|
||||
public function POSTitem_warnings( $id )
|
||||
@@ -878,7 +964,14 @@ class _members extends \IPS\Api\Controller
|
||||
}
|
||||
else
|
||||
{
|
||||
$options['warn_remove'] = new \IPS\DateTime( \IPS\Request::i()->expire );
|
||||
try
|
||||
{
|
||||
$options['warn_remove'] = new \IPS\DateTime( \IPS\Request::i()->expire );
|
||||
}
|
||||
catch( \Exception $e )
|
||||
{
|
||||
throw new \IPS\Api\Exception( 'INVALID_DATE', '1C292/Z', 404 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -886,11 +979,20 @@ class _members extends \IPS\Api\Controller
|
||||
{
|
||||
if( \IPS\Request::i()->modQueue == -1 )
|
||||
{
|
||||
$options['warn_punishment']['mq'] = \IPS\Request::i()->modQueue;
|
||||
$options['warn_punishment'][] = 'mq';
|
||||
$options['warn_mq'] = \IPS\Request::i()->modQueue;
|
||||
}
|
||||
else
|
||||
{
|
||||
$options['warn_punishment']['mq'] = new \IPS\DateTime( \IPS\Request::i()->modQueue );
|
||||
try
|
||||
{
|
||||
$options['warn_punishment'][] = 'mq';
|
||||
$options['warn_mq'] = new \IPS\DateTime( \IPS\Request::i()->modQueue );
|
||||
}
|
||||
catch( \Exception $e )
|
||||
{
|
||||
throw new \IPS\Api\Exception( 'INVALID_DATE', '1C292/10', 404 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -898,11 +1000,20 @@ class _members extends \IPS\Api\Controller
|
||||
{
|
||||
if( \IPS\Request::i()->restrictPosts == -1 )
|
||||
{
|
||||
$options['warn_punishment']['rpa'] = \IPS\Request::i()->restrictPosts;
|
||||
$options['warn_punishment'][] = 'rpa';
|
||||
$options['warn_rpa'] = \IPS\Request::i()->restrictPosts;
|
||||
}
|
||||
else
|
||||
{
|
||||
$options['warn_punishment']['rpa'] = new \IPS\DateTime( \IPS\Request::i()->restrictPosts );
|
||||
try
|
||||
{
|
||||
$options['warn_punishment'][] = 'rpa';
|
||||
$options['warn_rpa'] = new \IPS\DateTime( \IPS\Request::i()->restrictPosts );
|
||||
}
|
||||
catch( \Exception $e )
|
||||
{
|
||||
throw new \IPS\Api\Exception( 'INVALID_DATE', '1C292/11', 404 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -910,11 +1021,20 @@ class _members extends \IPS\Api\Controller
|
||||
{
|
||||
if( \IPS\Request::i()->suspend == -1 )
|
||||
{
|
||||
$options['warn_punishment']['suspend'] = \IPS\Request::i()->suspend;
|
||||
$options['warn_punishment'][] = 'suspend';
|
||||
$options['warn_suspend'] = \IPS\Request::i()->suspend;
|
||||
}
|
||||
else
|
||||
{
|
||||
$options['warn_punishment']['suspend'] = new \IPS\DateTime( \IPS\Request::i()->suspend );
|
||||
try
|
||||
{
|
||||
$options['warn_punishment'][] = 'suspend';
|
||||
$options['warn_suspend'] = new \IPS\DateTime( \IPS\Request::i()->suspend );
|
||||
}
|
||||
catch( \Exception $e )
|
||||
{
|
||||
throw new \IPS\Api\Exception( 'INVALID_DATE', '1C292/12', 404 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -971,7 +1091,7 @@ class _members extends \IPS\Api\Controller
|
||||
*
|
||||
* @param int $id ID Number
|
||||
* @param int $warningId Warning ID
|
||||
* @apiparam bool undoOnly Only undo the warning but do not delete it
|
||||
* @apiparam bool deleteOnly Delete the warning but do not revoke the consequences
|
||||
* @throws 2C292/P INVALID_ID The member could not be found
|
||||
* @throws 2C292/Q INVALID_WARNING The warning could not be loaded or the current authorized user does not have permission to delete the warning
|
||||
* @return void
|
||||
@@ -1003,13 +1123,13 @@ class _members extends \IPS\Api\Controller
|
||||
}
|
||||
|
||||
/* Revoke the warning */
|
||||
$warning->undo();
|
||||
|
||||
if( !isset( \IPS\Request::i()->undoOnly ) OR !\IPS\Request::i()->undoOnly )
|
||||
if( !isset( \IPS\Request::i()->deleteOnly ) OR !\IPS\Request::i()->deleteOnly )
|
||||
{
|
||||
$warning->delete();
|
||||
$warning->undo();
|
||||
}
|
||||
|
||||
$warning->delete();
|
||||
|
||||
return new \IPS\Api\Response( 200, NULL );
|
||||
}
|
||||
catch ( \OutOfRangeException $e )
|
||||
@@ -1070,4 +1190,48 @@ class _members extends \IPS\Api\Controller
|
||||
throw new \IPS\Api\Exception( 'INVALID_ID', '2C292/N', 404 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /core/members/{id}/achievements/{badge}/awardbadge
|
||||
* Acknowledge a warning
|
||||
*
|
||||
* @param int $id ID Number
|
||||
* @reqapiparam int $badgeId Badge to award
|
||||
* @param int $logId The ID number of the log in core_achievements_log which will tell us specifically what ACTION caused this (eg what post was made)
|
||||
* @param int $ruleId The ID number of the rule which matched that action which caused this badge to be awarded
|
||||
* @param array $actor If member is 'subject', 'other' or both
|
||||
* @param int $recognize The ID of the recognize table row (optional)
|
||||
* @return \IPS\Member
|
||||
* @throws 2C292/M INVALID_BADGE The badge could not be found //TODo error code
|
||||
* @throws 2C292/N INVALID_ID The member could not be found //TODo error code
|
||||
*/
|
||||
public function POSTitem_achievements_awardbadge( int $id, int $badgeId, int $logId, int $ruleId, array $actor, int $recognize=0 ): \IPS\Api\Response
|
||||
{
|
||||
try
|
||||
{
|
||||
/* Load member */
|
||||
$member = \IPS\Member::load( $id );
|
||||
if( !$member->member_id )
|
||||
{
|
||||
throw new \OutOfRangeException;
|
||||
}
|
||||
|
||||
/* Load the badge */
|
||||
try
|
||||
{
|
||||
$badge = \IPS\core\Achievements\Badge::load( $badgeId );
|
||||
}
|
||||
catch( \OutOfRangeException $e )
|
||||
{
|
||||
throw new \IPS\Api\Exception( 'INVALID_BADGE', '2C292/W', 404 ); //TODO error code
|
||||
}
|
||||
|
||||
$member->awardBadge($id, $badgeId, $logId,$ruleId,$actor,$recognize);
|
||||
return new \IPS\Api\Response( 200, $member->apiOutput( $this->member ) );
|
||||
}
|
||||
catch ( \OutOfRangeException $e )
|
||||
{
|
||||
throw new \IPS\Api\Exception( 'INVALID_ID', '2C292/N', 404 ); //TODO error code
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<badges><badge><manually_awarded>1</manually_awarded><title>Great Support</title><icon_name>GreatSupport.svg</icon_name><icon_data>PHN2ZyB3aWR0aD0iMTUwIiBoZWlnaHQ9IjE1MCIgdmlld0JveD0iMCAwIDE1MCAxNTAiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIxNTAiIGhlaWdodD0iMTUwIiByeD0iMTYiIGZpbGw9InVybCgjcGFpbnQwX2xpbmVhcikiLz4KPGcgb3BhY2l0eT0iMC4yIj4KPHJlY3QgeD0iMy41IiB5PSIzLjUiIHdpZHRoPSIxNDMiIGhlaWdodD0iMTQzIiByeD0iMTIuNSIgc3Ryb2tlPSJibGFjayIgc3Ryb2tlLXdpZHRoPSI3Ii8+CjwvZz4KPHBhdGggZD0iTTUwLjM4NDYgMzUuMDAwM0M0OS45NzY5IDM0Ljk5NDEgNDkuNTcyMSAzNS4wNzU3IDQ5LjE5MzcgMzUuMjQwNEM0OC44MTU0IDM1LjQwNTEgNDguNDcxIDM1LjY0OTYgNDguMTgwNiAzNS45NTk4QzQ3Ljg5MDIgMzYuMjY5OSA0Ny42NTk3IDM2LjYzOTUgNDcuNTAyMyAzNy4wNDdDNDcuMzQ0OSAzNy40NTQ2IDQ3LjI2MzkgMzcuODkxOSA0Ny4yNjM5IDM4LjMzMzZDNDcuMjYzOSAzOC43NzU0IDQ3LjM0NDkgMzkuMjEyNyA0Ny41MDIzIDM5LjYyMDJDNDcuNjU5NyA0MC4wMjc4IDQ3Ljg5MDIgNDAuMzk3MyA0OC4xODA2IDQwLjcwNzVDNDguNDcxIDQxLjAxNzYgNDguODE1NCA0MS4yNjIyIDQ5LjE5MzcgNDEuNDI2OUM0OS41NzIxIDQxLjU5MTYgNDkuOTc2OSA0MS42NzMyIDUwLjM4NDYgNDEuNjY2OVY0OS41NzdDNDkuMDI5OSA0OC44MjcgNDcuNTEwNyA0OC4zMzM2IDQ1Ljc2OTIgNDguMzMzNkMzOS44NTc5IDQ4LjMzMzYgMzUgNTMuNTk2MiAzNSA2MC4wMDAxQzM1IDY0LjUwNDEgMzcuNzExMyA2OC4wMDYzIDQwLjkyNTUgNzAuODc4OUM0NC4xMzk2IDczLjc1MTYgNDguMTYxIDc2LjE2ODkgNTIuMTM5NCA3OC4yMTYxQzU1LjY2NjkgODAuMDMxMyA1OS4wNzI2IDgxLjQ3OCA2MS44ODcgODIuNTk3NkM2NS42MjEgODguMDg0NiA2OC44NDYyIDkxLjY2NjUgNjguODQ2MiA5MS42NjY1SDgxLjE1MzhDODEuMTUzOCA5MS42NjY1IDg0LjM3OSA4OC4wODQ2IDg4LjExMyA4Mi41OTc2QzkwLjkyNzQgODEuNDc4IDk0LjMzMzEgODAuMDMxMyA5Ny44NjA2IDc4LjIxNjFDMTAxLjgzOSA3Ni4xNjg5IDEwNS44NiA3My43NTE2IDEwOS4wNzUgNzAuODc4OUMxMTIuMjg5IDY4LjAwNjMgMTE1IDY0LjUwNDEgMTE1IDYwLjAwMDFDMTE1IDUzLjU5NjIgMTEwLjE0MiA0OC4zMzM2IDEwNC4yMzEgNDguMzMzNkMxMDIuNDg5IDQ4LjMzMzYgMTAwLjk3IDQ4LjgyNyA5OS42MTU0IDQ5LjU3N1Y0MS42NjY5QzEwMC4wMjMgNDEuNjczMiAxMDAuNDI4IDQxLjU5MTYgMTAwLjgwNiA0MS40MjY5QzEwMS4xODUgNDEuMjYyMiAxMDEuNTI5IDQxLjAxNzYgMTAxLjgxOSA0MC43MDc1QzEwMi4xMSA0MC4zOTczIDEwMi4zNCA0MC4wMjc4IDEwMi40OTggMzkuNjIwMkMxMDIuNjU1IDM5LjIxMjcgMTAyLjczNiAzOC43NzU0IDEwMi43MzYgMzguMzMzNkMxMDIuNzM2IDM3Ljg5MTkgMTAyLjY1NSAzNy40NTQ2IDEwMi40OTggMzcuMDQ3QzEwMi4zNCAzNi42Mzk1IDEwMi4xMSAzNi4yNjk5IDEwMS44MTkgMzUuOTU5OEMxMDEuNTI5IDM1LjY0OTYgMTAxLjE4NSAzNS40MDUxIDEwMC44MDYgMzUuMjQwNEMxMDAuNDI4IDM1LjA3NTcgMTAwLjAyMyAzNC45OTQxIDk5LjYxNTQgMzUuMDAwM0g1MC4zODQ2Wk00NS43NjkyIDU1LjAwMDJDNDcuOTc0NCA1NS4wMDAyIDQ5Ljg2NjEgNTcuMDk0MSA1MS4zNTgyIDU5Ljk2NzZDNTEuMzgzNCA2MC4wMTYxIDUxLjM5OTUgNjAuMDYyMiA1MS40MjQzIDYwLjExMDhDNTIuNDQ3MiA2NC41NzI2IDU0LjEyOTQgNjguODg3MyA1Ni4wODc3IDcyLjgxOUM1NS42NDU4IDcyLjYwMTEgNTUuMjI2NSA3Mi40Mjg0IDU0Ljc4MzcgNzIuMjAwNUM1MS4wNjk4IDcwLjI4OTUgNDcuMzk4OCA2OC4wMTk0IDQ0Ljg0MzggNjUuNzM1OEM0Mi4yODg3IDYzLjQ1MjIgNDEuMTUzOCA2MS4zMjk1IDQxLjE1MzggNjAuMDAwMUM0MS4xNTM4IDU3LjE5NzQgNDMuMTgyMSA1NS4wMDAyIDQ1Ljc2OTIgNTUuMDAwMlpNMTA0LjIzMSA1NS4wMDAyQzEwNi44MTggNTUuMDAwMiAxMDguODQ2IDU3LjE5NzQgMTA4Ljg0NiA2MC4wMDAxQzEwOC44NDYgNjEuMzI5NSAxMDcuNzExIDYzLjQ1MjIgMTA1LjE1NiA2NS43MzU4QzEwMi42MDEgNjguMDE5NCA5OC45MzAyIDcwLjI4OTUgOTUuMjE2MyA3Mi4yMDA1Qzk0Ljc3MzUgNzIuNDI4NCA5NC4zNTQyIDcyLjYwMTEgOTMuOTEyMyA3Mi44MTlDOTUuODcwNiA2OC44ODczIDk3LjU1MjggNjQuNTcyNiA5OC41NzU3IDYwLjExMDhDOTguNjAwNSA2MC4wNjIyIDk4LjYxNjYgNjAuMDE2MSA5OC42NDE4IDU5Ljk2NzZDMTAwLjEzNCA1Ny4wOTQxIDEwMi4wMjYgNTUuMDAwMiAxMDQuMjMxIDU1LjAwMDJaTTY1Ljc2OTIgOTguMzMzMUM2Mi4zNjkyIDk4LjMzMzEgNTkuNjE1NCAxMDEuMzE2IDU5LjYxNTQgMTA1VjEwOC4zMzNDNTkuMjA3NyAxMDguMzI3IDU4LjgwMjggMTA4LjQwOCA1OC40MjQ1IDEwOC41NzNDNTguMDQ2MSAxMDguNzM4IDU3LjcwMTcgMTA4Ljk4MiA1Ny40MTE0IDEwOS4yOTNDNTcuMTIxIDEwOS42MDMgNTYuODkwNCAxMDkuOTcyIDU2LjczMzEgMTEwLjM4QzU2LjU3NTcgMTEwLjc4NyA1Ni40OTQ2IDExMS4yMjUgNTYuNDk0NiAxMTEuNjY2QzU2LjQ5NDYgMTEyLjEwOCA1Ni41NzU3IDExMi41NDUgNTYuNzMzMSAxMTIuOTUzQzU2Ljg5MDQgMTEzLjM2IDU3LjEyMSAxMTMuNzMgNTcuNDExNCAxMTQuMDRDNTcuNzAxNyAxMTQuMzUgNTguMDQ2MSAxMTQuNTk1IDU4LjQyNDUgMTE0Ljc2QzU4LjgwMjggMTE0LjkyNCA1OS4yMDc3IDExNS4wMDYgNTkuNjE1NCAxMTVIOTAuMzg0NkM5MC43OTIzIDExNS4wMDYgOTEuMTk3MiAxMTQuOTI0IDkxLjU3NTUgMTE0Ljc2QzkxLjk1MzkgMTE0LjU5NSA5Mi4yOTgzIDExNC4zNSA5Mi41ODg2IDExNC4wNEM5Mi44NzkgMTEzLjczIDkzLjEwOTYgMTEzLjM2IDkzLjI2NjkgMTEyLjk1M0M5My40MjQzIDExMi41NDUgOTMuNTA1NCAxMTIuMTA4IDkzLjUwNTQgMTExLjY2NkM5My41MDU0IDExMS4yMjUgOTMuNDI0MyAxMTAuNzg3IDkzLjI2NjkgMTEwLjM4QzkzLjEwOTYgMTA5Ljk3MiA5Mi44NzkgMTA5LjYwMyA5Mi41ODg2IDEwOS4yOTNDOTIuMjk4MyAxMDguOTgyIDkxLjk1MzkgMTA4LjczOCA5MS41NzU1IDEwOC41NzNDOTEuMTk3MiAxMDguNDA4IDkwLjc5MjMgMTA4LjMyNyA5MC4zODQ2IDEwOC4zMzNWMTA1QzkwLjM4NDYgMTAxLjMxNiA4Ny42MzA4IDk4LjMzMzEgODQuMjMwOCA5OC4zMzMxSDY1Ljc2OTJaIiBmaWxsPSJ3aGl0ZSIvPgo8ZGVmcz4KPGxpbmVhckdyYWRpZW50IGlkPSJwYWludDBfbGluZWFyIiB4MT0iMCIgeTE9IjAiIHgyPSIxNTAiIHkyPSIxNTAiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj4KPHN0b3Agc3RvcC1jb2xvcj0iI0REMjcyNyIvPgo8c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiM4NENEMTciLz4KPC9saW5lYXJHcmFkaWVudD4KPC9kZWZzPgo8L3N2Zz4K</icon_data></badge><badge><manually_awarded>1</manually_awarded><title>Helpful</title><icon_name>Helpful.svg</icon_name><icon_data>PHN2ZyB3aWR0aD0iMTUwIiBoZWlnaHQ9IjE1MCIgdmlld0JveD0iMCAwIDE1MCAxNTAiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyLine truncated
|
||||
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ranks><rank><posts/><title>Rookie</title><points>40</points><icon_name>2_Rookie.svg</icon_name><icon_data>PHN2ZyB3aWR0aD0iMTUwIiBoZWlnaHQ9IjE1MCIgdmlld0JveD0iMCAwIDE1MCAxNTAiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxwYXRoIGQ9Ik02OC41MDk0IDIuMjU1MjlDNzIuMzM2MyAtMC43NTE3NjIgNzcuNjYzNyAtMC43NTE3NjIgODEuNDkwNiAyLjI1NTI5TDEwMS4xNDggMTcuNzAxN0MxMDIuMzE1IDE4LjYxODkgMTAzLjY1NiAxOS4yNzg3IDEwNS4wODYgMTkuNjM5NUwxMjkuMTU5IDI1LjcxNTdDMTMzLjg0NSAyNi44OTg2IDEzNy4xNjcgMzEuMTU1NCAxMzcuMjUyIDM2LjA4OEwxMzcuNjkyIDYxLjQyNTVDMTM3LjcxOCA2Mi45MzAxIDEzOC4wNDkgNjQuNDEyNyAxMzguNjY0IDY1Ljc3OThMMTQ5LjAyNSA4OC44MDMxQzE1MS4wNDIgOTMuMjg1MiAxNDkuODU3IDk4LjU5MzMgMTQ2LjEzNyAxMDEuNzM3TDEyNy4wMjcgMTE3Ljg4NkMxMjUuODkzIDExOC44NDUgMTI0Ljk2NSAxMjAuMDM0IDEyNC4zMDMgMTIxLjM3OEwxMTMuMTQ5IDE0NC4wMTFDMTEwLjk3OCAxNDguNDE4IDEwNi4xNzggMTUwLjc4IDEwMS40NTQgMTQ5Ljc2OEw3Ny4xODUxIDE0NC41NjdDNzUuNzQ0IDE0NC4yNTkgNzQuMjU2IDE0NC4yNTkgNzIuODE0OSAxNDQuNTY3TDQ4LjU0NjIgMTQ5Ljc2OEM0My44MjE3IDE1MC43OCAzOS4wMjE5IDE0OC40MTggMzYuODUwNiAxNDQuMDExTDI1LjY5NzUgMTIxLjM3OEMyNS4wMzUyIDEyMC4wMzQgMjQuMTA3NCAxMTguODQ1IDIyLjk3MjcgMTE3Ljg4NkwzLjg2MzMyIDEwMS43MzdDMC4xNDMxODcgOTguNTkzMyAtMS4wNDIyOCA5My4yODUyIDAuOTc0NzQyIDg4LjgwMzFMMTEuMzM1NyA2NS43Nzk4QzExLjk1MDkgNjQuNDEyNyAxMi4yODIgNjIuOTMwMSAxMi4zMDgxIDYxLjQyNTVMMTIuNzQ3OCAzNi4wODhDMTIuODMzNCAzMS4xNTU0IDE2LjE1NSAyNi44OTg2IDIwLjg0MTQgMjUuNzE1N0w0NC45MTQ0IDE5LjYzOTVDNDYuMzQzOCAxOS4yNzg3IDQ3LjY4NDUgMTguNjE4OSA0OC44NTE4IDE3LjcwMTdMNjguNTA5NCAyLjI1NTI5WiIgZmlsbD0idXJsKCNwYWludDBfbGluZWFyKSIvPgo8ZyBvcGFjaXR5PSIwLjIiPgo8cGF0aCBkPSJNNzkuMzI4MSA1LjAwNzMyTDk4Ljk4NTcgMjAuNDUzOEMxMDAuNTM2IDIxLjY3MTcgMTAyLjMyMSAyMi41NTE1IDEwNC4yMjkgMjMuMDMzMUwxMjguMzAyIDI5LjEwOTNDMTMxLjQxMiAyOS44OTQyIDEzMy42OTQgMzIuNzUwMSAxMzMuNzUzIDM2LjE0ODdMMTM0LjE5MiA2MS40ODYzQzEzNC4yMjcgNjMuNDYzNiAxMzQuNjYyIDY1LjQxNDUgMTM1LjQ3MyA2Ny4yMTYxTDE0NS44MzQgOTAuMjM5NEMxNDcuMjE4IDkzLjMxNTMgMTQ2LjM4OSA5Ni45NDEyIDE0My44NzggOTkuMDYzOEwxMjQuNzY4IDExNS4yMTNDMTIzLjI2MiAxMTYuNDg1IDEyMi4wMzYgMTE4LjA1OSAxMjEuMTYzIDExOS44MzFMMTEwLjAxIDE0Mi40NjRDMTA4LjUzMSAxNDUuNDY2IDEwNS4zMDYgMTQ3LjAxNCAxMDIuMTg3IDE0Ni4zNDVMNzcuOTE4NCAxNDEuMTQ1Qzc1Ljk5MzkgMTQwLjczMyA3NC4wMDYgMTQwLjczMyA3Mi4wODE2IDE0MS4xNDVMNDcuODEyOSAxNDYuMzQ1QzQ0LjY5MzUgMTQ3LjAxNCA0MS40Njk0IDE0NS40NjYgMzkuOTkwMSAxNDIuNDY0TDI4LjgzNyAxMTkuODMxQzI3Ljk2MzcgMTE4LjA1OSAyNi43Mzc2IDExNi40ODUgMjUuMjMxOCAxMTUuMjEzTDYuMTIyNDUgOTkuMDYzOEMzLjYxMDY1IDk2Ljk0MTIgMi43ODIyNSA5My4zMTUzIDQuMTY2NDQgOTAuMjM5NEwxNC41Mjc0IDY3LjIxNjFDMTUuMzM4MiA2NS40MTQ1IDE1Ljc3MzMgNjMuNDYzNiAxNS44MDc2IDYxLjQ4NjNMMTYuMjQ3MiAzNi4xNDg3QzE2LjMwNjIgMzIuNzUwMSAxOC41ODgzIDI5Ljg5NDIgMjEuNjk4IDI5LjEwOTNMNDUuNzcxIDIzLjAzMzFDNDcuNjc5MiAyMi41NTE1IDQ5LjQ2NDIgMjEuNjcxNyA1MS4wMTQzIDIwLjQ1MzhMNzAuNjcxOSA1LjAwNzMyQzczLjIyOTYgMi45OTc1NiA3Ni43NzA0IDIuOTk3NTYgNzkuMzI4MSA1LjAwNzMyWiIgc3Ryb2tlPSJibGFjayIgc3Ryb2tlLXdpZHRoPSI3Ii8+CjwvZz4KPHBhdGggZD0iTTgyLjg4NzEgNDYuMTZDODIuMjM3NCA0Ni4xNzgxIDgxLjY2NTkgNDYuNjE3MiA4MS40NzM0IDQ3LjI0MjhDODEuMjgwOSA0Ny44Njg0IDgxLjUwMzUgNDguNTQ4MiA4Mi4wMjY5IDQ4LjkzOTJDODUuNTIyIDUxLjU5MjEgODguNjMyIDU0LjcxNDIgOTEuMjc4OSA1OC4yMDkzQzkxLjYwMzggNTguNjY2NSA5Mi4xNTEyIDU4LjkxMzEgOTIuNzEwNiA1OC44NDdDOTMuMjcwMSA1OC43ODY4IDkzLjc0NTMgNTguNDE5OCA5My45NjE5IDU3LjkwMjVDOTQuMTcyNCA1Ny4zNzkxIDk0LjA4ODIgNTYuNzg5NiA5My43MzMzIDU2LjM1MDVDOTAuOTE4IDUyLjYyNjggODcuNjAzNCA0OS4zMDYyIDgzLjg5MTcgNDYuNDg0OEM4My42MDkgNDYuMjYyMyA4My4yNTQxIDQ2LjE0OCA4Mi44ODcxIDQ2LjE2Wk03MS44NzI1IDQ3Ljc5NjNDNzEuMTYyNyA0Ny43ODQyIDcwLjUzMSA0OC4yNTM0IDcwLjM0NDUgNDguOTM5MkM3MC4xNjQxIDQ5LjYzMSA3MC40NzA5IDUwLjM1MjkgNzEuMDk2NSA1MC42OTU4Qzc4LjA5MjcgNTQuNjEyIDg0IDYwLjI0ODYgODguMjUzMSA2Ny4wMjIyQzg4LjcwNDIgNjcuNzQ0MSA4OS42NTQ3IDY3Ljk2NjYgOTAuMzc2NiA2Ny41MTU1QzkxLjA5MjQgNjcuMDU4MyA5MS4zMTUgNjYuMTA3OCA5MC44NTc4IDY1LjM4NTlDODYuMzM0MSA1OC4xNzMyIDgwLjA1MzggNTIuMTgxNiA3Mi42MDY0IDQ4LjAwNjhDNzIuMzgzOCA0Ny44NzQ1IDcyLjEzMTIgNDcuODA4MyA3MS44NzI1IDQ3Ljc5NjNaTTYwLjQ1NDkgNTAuNzg2QzYwLjE5MDIgNTAuNzc0IDU5LjkxMzQgNTAuNzkyIDU5LjYzNjcgNTAuODUyMkM1OC41MTE4IDUxLjA4NjggNTcuNTc5NCA1MS45ODkxIDU3LjMwODcgNTMuMTAyQzU3LjAzMiA1NC4yNTEgNTcuMzk4OSA1NS4zMjc4IDU4LjEyNjggNTYuMDQ5N0w1OS43MTQ5IDU3LjYzMThMNzIuNzUwOCA3MC42NDk2QzczLjM1MjQgNzEuMjUxMiA3My4zNTg0IDcyLjIyNTcgNzIuNzU2OCA3Mi44MjczQzcyLjE0OTIgNzMuNDI4OCA3MS4xODA3IDczLjQyODggNzAuNTczMSA3Mi44MjczTDUwLjkzMjEgNTMuMjE2M0M1MC4yMDQyIDUyLjQ5NDUgNDkuMTI3NCA1Mi4xMzM1IDQ3Ljk4NDUgNTIuNDA0MkM0Ni45MDc3IDUyLjY2ODkgNDYuMDIzNCA1My41NTMyIDQ1Ljc1ODcgNTQuNjNDNDUuNDgyIDU1Ljc4NSA0NS44NDg5IDU2Ljg2MTggNDYuNTc2OCA1Ny41ODM3TDY0Ljg5NDQgNzUuOTAxM0M2NS41MDIgNzYuNTAyOCA2NS41MDIgNzcuNDc3MyA2NC44OTQ0IDc4LjA4NDlDNjQuMjk4OCA3OC42ODY1IDYzLjMyNDMgNzguNjg2NSA2Mi43MjI3IDc4LjA4NDlMNDYuODcxNiA2Mi4yMzM4QzQ2LjE0OTcgNjEuNTIzOSA0NS4wNzg5IDYxLjE3NSA0My45NDIgNjEuNDUxN0M0Mi44NzEyIDYxLjcxNjQgNDEuOTkyOSA2Mi41ODg3IDQxLjcyODIgNjMuNjU5NUM0MS40NTE1IDY0LjgwODQgNDEuODE4NCA2NS44ODUyIDQyLjUzNDMgNjYuNjEzMUw2MC41NjMxIDg0LjY2NkM2MS4xNjQ3IDg1LjI3MzYgNjEuMTY0NyA4Ni4yNDgxIDYwLjU2MzEgODYuODQ5N0M1OS45NjE2IDg3LjQ1MTMgNTguOTgxIDg3LjQ1MTMgNTguMzg1NSA4Ni44NDk3QzU4LjM4NTUgODYuODQ5NyA1MC4zOTY3IDc4LjgzNjkgNDYuOTM3NyA3NS4zNzE5QzQ1Ljk4NzMgNzQuNDE1NCA0NS4zNzM3IDczLjgwMTggLine truncated
|
||||
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<rules><rule><action>core_NewContentItem</action><filters/><milestone/><points_subject>10</points_subject><badge_subject/><points_other>0</points_other><badge_other/><enabled>1</enabled><award_subject_lang/><award_other_lang/></rule><rule><action>core_Comment</action><filters/><milestone/><points_subject>5</points_subject><badge_subject/><points_other>0</points_other><badge_other/><enabled>1</enabled><award_subject_lang/><award_other_lang/></rule><rule><action>core_FollowNode</action><filters/><milestone/><points_subject>2</points_subject><badge_subject/><points_other>0</points_other><badge_other/><enabled>1</enabled><award_subject_lang/><award_other_lang/></rule><rule><action>core_FollowContentItem</action><filters/><milestone/><points_subject>2</points_subject><badge_subject/><points_other>0</points_other><badge_other/><enabled>1</enabled><award_subject_lang/><award_other_lang/></rule><rule><action>core_FollowMember</action><filters/><milestone/><points_subject>2</points_subject><badge_subject/><points_other>0</points_other><badge_other/><enabled>1</enabled><award_subject_lang/><award_other_lang/></rule><rule><action>core_Reaction</action><filters/><milestone/><points_subject>1</points_subject><badge_subject/><points_other>1</points_other><badge_other/><enabled>1</enabled><award_subject_lang/><award_other_lang/></rule><rule><action>core_Comment</action><filters>{"milestone":1}</filters><milestone>1</milestone><points_subject>0</points_subject><badge_subject>6087eca35e0df</badge_subject><points_other>0</points_other><badge_other/><enabled>1</enabled><award_subject_lang>Making your first post</award_subject_lang><award_other_lang/></rule><rule><action>core_NewContentItem</action><filters>{"milestone":1}</filters><milestone>1</milestone><points_subject>0</points_subject><badge_subject>6087eca35e1ea</badge_subject><points_other>0</points_other><badge_other/><enabled>1</enabled><award_subject_lang>Started a discussion</award_subject_lang><award_other_lang/></rule><rule><action>core_Comment</action><filters>{"milestone":10}</filters><milestone>10</milestone><points_subject>0</points_subject><badge_subject>6087eca35e304</badge_subject><points_other>0</points_other><badge_other/><enabled>1</enabled><award_subject_lang>Making your 10th post</award_subject_lang><award_other_lang/></rule><rule><action>core_Reaction</action><filters>{"milestone":5}</filters><milestone>5</milestone><points_subject>0</points_subject><badge_subject/><points_other>0</points_other><badge_other>6087eca35e3b2</badge_other><enabled>1</enabled><award_subject_lang/><award_other_lang/></rule><rule><action>core_FollowMember</action><filters>{"milestone":10}</filters><milestone>10</milestone><points_subject>0</points_subject><badge_subject>6087eca35e557</badge_subject><points_other>0</points_other><badge_other/><enabled>1</enabled><award_subject_lang>Got 10 followers!</award_subject_lang><award_other_lang/></rule><rule><action>forums_AnswerMarkedBest</action><filters>{"milestone":10}</filters><milestone>10</milestone><points_subject>0</points_subject><badge_subject>6087eca35e6c4</badge_subject><points_other>0</points_other><badge_other/><enabled>1</enabled><award_subject_lang>Solved 10 topics</award_subject_lang><award_other_lang/></rule><rule><action>core_SessionStartDaily</action><filters>{"milestone_concurrent":7}</filters><milestone/><points_subject>0</points_subject><badge_subject>6087eca35e776</badge_subject><points_other>0</points_other><badge_other/><enabled>1</enabled><award_subject_lang>Visited daily for a week</award_subject_lang><award_other_lang/></rule><rule><action>core_SessionStartDaily</action><filters>{"milestone_registered":7}</filters><milestone/><points_subject>0</points_subject><badge_subject>6087eca35e81a</badge_subject><points_other>0</points_other><badge_other/><enabled>1</enabled><award_subject_lang>A week since joining</award_subject_lang><award_other_lang/></rule><rule><action>core_SessionStartDaily</action><filters>{"milestone_registered":30}</filters><milestone/><points_subject>0</points_subject><badge_subject>6087eca35e932</badge_subject><points_other>0</points_other><badge_other/><enabled>1</enabled><award_subject_lang>A month since joining</award_subject_lang><award_other_lang/></rule><rule><action>core_SessionStartDaily</action><filters>{"milestone_registered":365}</filters><milestone/><points_subject>0</points_subject><badge_subject>6087eca35e9cb</badge_subject><points_other>0</points_other><badge_other/><enabled>1</enabled><award_subject_lang>A year since joining</award_subject_lang><award_other_lang/></rule><rule><action>core_Reaction</action><filters>{"milestone":100}</filters><milestone>100</milestone><points_subject>0</points_subject><badge_subject>6087eca35ea70</badge_subject><points_other>0</points_other><badge_other/><enabled>1</enabled><award_subject_lang>Got 100 reactions</award_subject_lang><award_other_lang/></rule><rule><action>core_Comment</action><filters>{"milestone":500}</filters><milestone>500Line truncated
|
||||
@@ -138,7 +138,8 @@
|
||||
"tab": "core",
|
||||
"controller": "seo",
|
||||
"do": "",
|
||||
"restriction": "seo_manage"
|
||||
"restriction": null,
|
||||
"callback": "return ( ( !\\IPS\\CIC AND \\IPS\\Member::loggedIn()->hasAcpRestriction( 'core', 'promotion', 'seo_furls' ) ) or \\IPS\\Member::loggedIn()->hasAcpRestriction( 'core', 'promotion', 'seo_sitemap' ) or \\IPS\\Member::loggedIn()->hasAcpRestriction( 'core', 'promotion', 'seo_meta' ) );"
|
||||
},
|
||||
"analytics": {
|
||||
"tab": "core",
|
||||
@@ -200,6 +201,35 @@
|
||||
"restriction": "membertools_ip"
|
||||
}
|
||||
},
|
||||
"achievements": {
|
||||
"rules": {
|
||||
"tab": "members",
|
||||
"controller": "rules",
|
||||
"do": "",
|
||||
"restriction": "rules_manage",
|
||||
"subcontrollers": ""
|
||||
},
|
||||
"ranks": {
|
||||
"tab": "members",
|
||||
"controller": "ranks",
|
||||
"do": "",
|
||||
"restriction": "ranks_manage"
|
||||
},
|
||||
"badges": {
|
||||
"tab": "members",
|
||||
"controller": "badges",
|
||||
"do": "",
|
||||
"restriction": "badges_manage",
|
||||
"subcontrollers": ""
|
||||
},
|
||||
"settings": {
|
||||
"tab": "members",
|
||||
"controller": "settings",
|
||||
"do": "",
|
||||
"restriction": "settings_manage",
|
||||
"subcontrollers": ""
|
||||
}
|
||||
},
|
||||
"membersettings": {
|
||||
"profiles": {
|
||||
"tab": "members",
|
||||
@@ -225,12 +255,6 @@
|
||||
"do": "",
|
||||
"restriction": "ban_manage"
|
||||
},
|
||||
"ranks": {
|
||||
"tab": "members",
|
||||
"controller": "ranks",
|
||||
"do": "",
|
||||
"restriction": "ranks_manage"
|
||||
},
|
||||
"referrals": {
|
||||
"tab": "members",
|
||||
"controller": "referrals",
|
||||
@@ -338,7 +362,7 @@
|
||||
"support": {
|
||||
"tab": "core",
|
||||
"controller": "support",
|
||||
"do": "&_new=1",
|
||||
"do": "",
|
||||
"restriction": "get_support",
|
||||
"subcontrollers": "systemLogs,errorLogs"
|
||||
}
|
||||
@@ -427,6 +451,20 @@
|
||||
"controller": "deviceusage",
|
||||
"do": "",
|
||||
"restriction": "deviceusage_manage"
|
||||
},
|
||||
"points": {
|
||||
"tab": "stats",
|
||||
"controller": "points",
|
||||
"do": "",
|
||||
"restriction": "overview_manage",
|
||||
"subcontrollers": ""
|
||||
},
|
||||
"badges": {
|
||||
"tab": "stats",
|
||||
"controller": "badges",
|
||||
"do": "",
|
||||
"restriction": "overview_manage",
|
||||
"subcontrollers": ""
|
||||
}
|
||||
},
|
||||
"messengerstats": {
|
||||
|
||||
@@ -45,7 +45,9 @@
|
||||
},
|
||||
"promotion": {
|
||||
"seo": {
|
||||
"seo_manage": "seo_manage"
|
||||
"seo_furls": "seo_furls",
|
||||
"seo_sitemap": "seo_sitemap",
|
||||
"seo_meta": "seo_meta"
|
||||
},
|
||||
"sharelinks": {
|
||||
"sharelinks_manage": "sharelinks_manage"
|
||||
@@ -174,6 +176,26 @@
|
||||
"promotions_manage": "promotions_manage"
|
||||
}
|
||||
},
|
||||
"achievements": {
|
||||
"rules": {
|
||||
"rules_manage": "rules_manage",
|
||||
"rules_add": "rules_add",
|
||||
"rules_edit": "rules_edit",
|
||||
"rules_delete": "rules_delete"
|
||||
},
|
||||
"ranks": {
|
||||
"ranks_manage": "ranks_manage",
|
||||
"ranks_add": "ranks_add",
|
||||
"ranks_edit": "ranks_edit",
|
||||
"ranks_delete": "ranks_delete"
|
||||
},
|
||||
"badges": {
|
||||
"badges_manage": "badges_manage"
|
||||
},
|
||||
"settings": {
|
||||
"settings_manage": "settings_manage"
|
||||
}
|
||||
},
|
||||
"membersettings": {
|
||||
"members_reputation": {
|
||||
"reps_settings": "reps_settings",
|
||||
@@ -191,14 +213,12 @@
|
||||
"profilefieldgroups_delete": "profilefieldgroups_delete",
|
||||
"member_history_prune": "member_history_prune"
|
||||
},
|
||||
"ranks": {
|
||||
"ranks_manage": "ranks_manage"
|
||||
},
|
||||
"ban": {
|
||||
"ban_manage": "ban_manage"
|
||||
},
|
||||
"notifications": {
|
||||
"notifications_manage": "notifications_manage"
|
||||
"notifications_manage": "notifications_manage",
|
||||
"notifications_prune": "notifications_prune"
|
||||
},
|
||||
"reactions": {
|
||||
"reactions_manage": "reactions_manage"
|
||||
@@ -343,9 +363,6 @@
|
||||
"deviceusage": {
|
||||
"deviceusage_manage": "deviceusage_manage"
|
||||
},
|
||||
"emailstats": {
|
||||
"emailstats_manage": "emailstats_manage"
|
||||
},
|
||||
"overview": {
|
||||
"overview_manage": "overview_manage"
|
||||
}
|
||||
@@ -400,6 +417,9 @@
|
||||
},
|
||||
"search_stats": {
|
||||
"search_stats_manage": "search_stats_manage"
|
||||
},
|
||||
"emailstats": {
|
||||
"emailstats_manage": "emailstats_manage"
|
||||
}
|
||||
},
|
||||
"marketplace": {
|
||||
|
||||
@@ -1,4 +1,46 @@
|
||||
{
|
||||
"app=core&module=achievements&controller=badges": {
|
||||
"lang_key": "menu__core_achievements_badges",
|
||||
"restriction": "badges_manage",
|
||||
"keywords": [
|
||||
"awards",
|
||||
"badges",
|
||||
"rewards",
|
||||
"trophies",
|
||||
"trophy"
|
||||
]
|
||||
},
|
||||
"app=core&module=achievements&controller=ranks": {
|
||||
"lang_key": "menu__core_membersettings_ranks",
|
||||
"restriction": "ranks_manage",
|
||||
"keywords": [
|
||||
"badges",
|
||||
"ranks",
|
||||
"titles"
|
||||
]
|
||||
},
|
||||
"app=core&module=achievements&controller=rules": {
|
||||
"lang_key": "achievements_rules",
|
||||
"restriction": "rules_manage",
|
||||
"keywords": [
|
||||
"achievement rules",
|
||||
"achievements",
|
||||
"awards",
|
||||
"badges",
|
||||
"karma",
|
||||
"points",
|
||||
"rules"
|
||||
]
|
||||
},
|
||||
"app=core&module=achievements&controller=settings": {
|
||||
"lang_key": "menu__core_achievements_settings",
|
||||
"restriction": "settings_manage",
|
||||
"keywords": [
|
||||
"achievement",
|
||||
"badge",
|
||||
"rare badge"
|
||||
]
|
||||
},
|
||||
"app=core&module=activitystats&controller=communityactivity": {
|
||||
"lang_key": "menu__core_activitystats_communityactivity",
|
||||
"restriction": null,
|
||||
@@ -252,7 +294,7 @@
|
||||
},
|
||||
"app=core&module=customization&controller=themes&do=designersmode&searchResult=form_theme_designers_mode": {
|
||||
"lang_key": "theme_designers_mode",
|
||||
"restriction": "theme_templates_manage",
|
||||
"restriction": "theme_designers_mode",
|
||||
"keywords": [
|
||||
"designers mode"
|
||||
]
|
||||
@@ -404,7 +446,7 @@
|
||||
"groups"
|
||||
]
|
||||
},
|
||||
"app=core&module=members&controller=groups&do=form&searchResult=g_promote_exclude": {
|
||||
"app=core&module=members&controller=groups&searchResult=g_promote_exclude": {
|
||||
"lang_key": "g_promote_exclude",
|
||||
"restriction": "groups_manage",
|
||||
"keywords": [
|
||||
@@ -413,7 +455,7 @@
|
||||
"member upgrades"
|
||||
]
|
||||
},
|
||||
"app=core&module=members&controller=groups&do=form&searchResult=g_upload_animated_photos": {
|
||||
"app=core&module=members&controller=groups&searchResult=g_upload_animated_photos": {
|
||||
"lang_key": "g_upload_animated_photos",
|
||||
"restriction": "groups_manage",
|
||||
"keywords": [
|
||||
@@ -421,7 +463,15 @@
|
||||
"photos"
|
||||
]
|
||||
},
|
||||
"app=core&module=members&controller=groups&do=form&searchResult=gbw_hide_group": {
|
||||
"app=core&module=members&controller=groups&searchResult=gbw_can_post_anonymously": {
|
||||
"lang_key": "can_post_anonymously",
|
||||
"restriction": "groups_manage",
|
||||
"keywords": [
|
||||
"anonymous",
|
||||
"anonymously"
|
||||
]
|
||||
},
|
||||
"app=core&module=members&controller=groups&searchResult=gbw_hide_group": {
|
||||
"lang_key": "gbw_hide_group",
|
||||
"restriction": "groups_manage",
|
||||
"keywords": [
|
||||
@@ -430,7 +480,7 @@
|
||||
"search"
|
||||
]
|
||||
},
|
||||
"app=core&module=members&controller=groups&do=form&searchResult=gbw_post_highlight": {
|
||||
"app=core&module=members&controller=groups&searchResult=gbw_post_highlight": {
|
||||
"lang_key": "gbw_post_highlight",
|
||||
"restriction": "groups_manage",
|
||||
"keywords": [
|
||||
@@ -1046,16 +1096,9 @@
|
||||
"notification sounds"
|
||||
]
|
||||
},
|
||||
"app=core&module=membersettings&controller=notifications&do=method&id=inline&searchResult=prune_notifications": {
|
||||
"lang_key": "prune_notifications",
|
||||
"restriction": "notifications_manage",
|
||||
"keywords": [
|
||||
"prune notifications"
|
||||
]
|
||||
},
|
||||
"app=core&module=membersettings&controller=notifications&do=pruneSettings&searchResult=form_prune_notifications": {
|
||||
"lang_key": "prune_notifications",
|
||||
"restriction": "notifications_manage",
|
||||
"restriction": "notifications_prune",
|
||||
"keywords": [
|
||||
"notifications",
|
||||
"prune"
|
||||
@@ -1063,7 +1106,7 @@
|
||||
},
|
||||
"app=core&module=membersettings&controller=notifications&do=pruneSettings&searchResult=prune_follows": {
|
||||
"lang_key": "prune_follows",
|
||||
"restriction": "notifications_manage",
|
||||
"restriction": "notifications_prune",
|
||||
"keywords": [
|
||||
"follow",
|
||||
"prune"
|
||||
@@ -1191,7 +1234,7 @@
|
||||
},
|
||||
"app=core&module=membersettings&controller=profiles&tab=profilesettings&searchResult=prune_item_markers": {
|
||||
"lang_key": "prune_item_markers",
|
||||
"restriction": "profiles_manage",
|
||||
"restriction": "member_history_prune",
|
||||
"keywords": [
|
||||
"item markers",
|
||||
"prune"
|
||||
@@ -1199,7 +1242,7 @@
|
||||
},
|
||||
"app=core&module=membersettings&controller=profiles&tab=profilesettings&searchResult=prune_known_devices": {
|
||||
"lang_key": "prune_known_devices",
|
||||
"restriction": "profiles_manage",
|
||||
"restriction": "member_history_prune",
|
||||
"keywords": [
|
||||
"device history",
|
||||
"prune"
|
||||
@@ -1207,7 +1250,7 @@
|
||||
},
|
||||
"app=core&module=membersettings&controller=profiles&tab=profilesettings&searchResult=prune_known_ips": {
|
||||
"lang_key": "prune_known_ips",
|
||||
"restriction": "profiles_manage",
|
||||
"restriction": "member_history_prune",
|
||||
"keywords": [
|
||||
"address",
|
||||
"ip address",
|
||||
@@ -1216,7 +1259,7 @@
|
||||
},
|
||||
"app=core&module=membersettings&controller=profiles&tab=profilesettings&searchResult=prune_member_history": {
|
||||
"lang_key": "prune_member_history",
|
||||
"restriction": "profiles_manage",
|
||||
"restriction": "member_history_prune",
|
||||
"keywords": [
|
||||
"change log",
|
||||
"member history"
|
||||
@@ -1240,15 +1283,6 @@
|
||||
"username size"
|
||||
]
|
||||
},
|
||||
"app=core&module=membersettings&controller=ranks": {
|
||||
"lang_key": "menu__core_membersettings_ranks",
|
||||
"restriction": "ranks_manage",
|
||||
"keywords": [
|
||||
"badges",
|
||||
"ranks",
|
||||
"titles"
|
||||
]
|
||||
},
|
||||
"app=core&module=membersettings&controller=referrals": {
|
||||
"lang_key": "menu__core_membersettings_referrals",
|
||||
"restriction": "referrals_manage",
|
||||
@@ -1412,7 +1446,16 @@
|
||||
"restriction": "reportedContent_manage",
|
||||
"keywords": [
|
||||
"moderation",
|
||||
"report"
|
||||
"report",
|
||||
"report types"
|
||||
]
|
||||
},
|
||||
"app=core&module=moderation&controller=reportedContentTypes": {
|
||||
"lang_key": "menu__core_moderation_reportedContentTypes",
|
||||
"restriction": null,
|
||||
"keywords": [
|
||||
"report",
|
||||
"report types"
|
||||
]
|
||||
},
|
||||
"app=core&module=moderation&controller=spam": {
|
||||
@@ -1661,7 +1704,7 @@
|
||||
},
|
||||
"app=core&module=promotion&controller=seo&tab=metatags": {
|
||||
"lang_key": "seo_tab_metatags",
|
||||
"restriction": "seo_manage",
|
||||
"restriction": "seo_meta",
|
||||
"keywords": [
|
||||
"description",
|
||||
"keywords",
|
||||
@@ -1671,7 +1714,7 @@
|
||||
},
|
||||
"app=core&module=promotion&controller=seo&tab=sitemap": {
|
||||
"lang_key": "seo_tab_sitemap",
|
||||
"restriction": "seo_manage",
|
||||
"restriction": "seo_sitemap",
|
||||
"keywords": [
|
||||
"google",
|
||||
"priority",
|
||||
@@ -1682,7 +1725,7 @@
|
||||
},
|
||||
"app=core&module=promotion&controller=seo&tab=urls": {
|
||||
"lang_key": "seo_tab_furls",
|
||||
"restriction": "seo_manage",
|
||||
"restriction": "seo_furls",
|
||||
"keywords": [
|
||||
"friendly url",
|
||||
"furls",
|
||||
@@ -1742,7 +1785,7 @@
|
||||
},
|
||||
"app=core&module=settings&controller=advanced&tab=datastore&searchResult=cache_guest_page": {
|
||||
"lang_key": "cache_guest_page",
|
||||
"restriction": "advanced_manage_server",
|
||||
"restriction": "datastore",
|
||||
"keywords": [
|
||||
"cache",
|
||||
"guest cache",
|
||||
@@ -1843,6 +1886,13 @@
|
||||
"statistics"
|
||||
]
|
||||
},
|
||||
"app=core&module=settings&controller=email&searchResult=email_truncate": {
|
||||
"lang_key": "email_truncate",
|
||||
"restriction": "email_manage",
|
||||
"keywords": [
|
||||
"truncate"
|
||||
]
|
||||
},
|
||||
"app=core&module=settings&controller=email&searchResult=our_picks_in_email": {
|
||||
"lang_key": "our_picks_in_email",
|
||||
"restriction": "email_manage",
|
||||
|
||||
@@ -4,5 +4,6 @@
|
||||
"app_directory": "core",
|
||||
"app_protected": 1,
|
||||
"app_website": null,
|
||||
"app_update_check": null
|
||||
"app_update_check": null,
|
||||
"app_hide_tab": 0
|
||||
}
|
||||
@@ -24,7 +24,8 @@
|
||||
<module key="admin/messengerstats"><![CDATA[{"default_controller":"","protected":0,"default":0}]]></module>
|
||||
<module key="admin/moderation"><![CDATA[{"default_controller":"","protected":0,"default":0}]]></module>
|
||||
<module key="admin/mobile"><![CDATA[{"default_controller":"multi","protected":0,"default":0}]]></module>
|
||||
<module key="admin/marketplace"><![CDATA[{"default_controller":"","protected":false,"default":0}]]></module>
|
||||
<module key="admin/marketplace"><![CDATA[{"default_controller":"","protected":0,"default":0}]]></module>
|
||||
<module key="admin/achievements"><![CDATA[{"default_controller":"","protected":0,"default":0}]]></module>
|
||||
<module key="front/system"><![CDATA[{"default_controller":"splash","protected":1,"default":0}]]></module>
|
||||
<module key="front/members"><![CDATA[{"default_controller":"profile","protected":0,"default":0}]]></module>
|
||||
<module key="front/search"><![CDATA[{"default_controller":"search","protected":0,"default":0}]]></module>
|
||||
@@ -73,6 +74,11 @@
|
||||
<task frequency="P0Y0M0DT0H2M0S">webhooks</task>
|
||||
<task frequency="P0Y0M1DT0H0M0S">chunkcleanup</task>
|
||||
<task frequency="P0Y0M0DT0H15M0S">s3Delete</task>
|
||||
<task frequency="P0Y0M1DT0H0M0S">pwaprune</task>
|
||||
<setting key="achievements_enabled"><![CDATA[{"key":"achievements_enabled","default":"1","report":"full"}]]></setting>
|
||||
<setting key="achievements_last_rebuilt"><![CDATA[{"key":"achievements_last_rebuilt","default":"0","report":"full"}]]></setting>
|
||||
<setting key="achievements_rebuilding"><![CDATA[{"key":"achievements_rebuilding","default":"0","report":"full"}]]></setting>
|
||||
<setting key="achievements_recognize_max_per_user_day"><![CDATA[{"key":"achievements_recognize_max_per_user_day","default":"50","report":"full"}]]></setting>
|
||||
<setting key="acp_css_map"><![CDATA[{"key":"acp_css_map","default":"","report":"none"}]]></setting>
|
||||
<setting key="acp_dashboard_blocks"><![CDATA[{"key":"acp_dashboard_blocks","default":"","report":"none"}]]></setting>
|
||||
<setting key="acp_notes"><![CDATA[{"key":"acp_notes","default":"","report":"none"}]]></setting>
|
||||
@@ -158,7 +164,6 @@
|
||||
<setting key="diagnostics"><![CDATA[{"key":"diagnostics","default":"1","report":"full"}]]></setting>
|
||||
<setting key="diagnostics_reporting"><![CDATA[{"key":"diagnostics_reporting","default":"1","report":"full"}]]></setting>
|
||||
<setting key="disable_all_plugins"><![CDATA[{"key":"disable_all_plugins","default":"","report":"none"}]]></setting>
|
||||
<setting key="disable_anonymous"><![CDATA[{"key":"disable_anonymous","default":"0","report":"full"}]]></setting>
|
||||
<setting key="edit_log"><![CDATA[{"key":"edit_log","default":"1","report":"full"}]]></setting>
|
||||
<setting key="edit_log_prune"><![CDATA[{"key":"edit_log_prune","default":"30","report":"full"}]]></setting>
|
||||
<setting key="edit_log_public"><![CDATA[{"key":"edit_log_public","default":"0","report":"full"}]]></setting>
|
||||
@@ -181,6 +186,9 @@
|
||||
<setting key="error_log_level"><![CDATA[{"key":"error_log_level","default":"3","report":"full"}]]></setting>
|
||||
<setting key="error_notify"><![CDATA[{"key":"error_notify","default":"0","report":"full"}]]></setting>
|
||||
<setting key="error_notify_level"><![CDATA[{"key":"error_notify_level","default":"3","report":"full"}]]></setting>
|
||||
<setting key="fb_ig_oembed_appid"><![CDATA[{"key":"fb_ig_oembed_appid","default":"","report":"none"}]]></setting>
|
||||
<setting key="fb_ig_oembed_appsecret"><![CDATA[{"key":"fb_ig_oembed_appsecret","default":"","report":"none"}]]></setting>
|
||||
<setting key="fb_ig_oembed_token"><![CDATA[{"key":"fb_ig_oembed_token","default":"","report":"bool"}]]></setting>
|
||||
<setting key="fb_pixel_delay"><![CDATA[{"key":"fb_pixel_delay","default":"0","report":"full"}]]></setting>
|
||||
<setting key="fb_pixel_enabled"><![CDATA[{"key":"fb_pixel_enabled","default":"0","report":"full"}]]></setting>
|
||||
<setting key="fb_pixel_id"><![CDATA[{"key":"fb_pixel_id","default":"","report":"none"}]]></setting>
|
||||
@@ -206,6 +214,7 @@
|
||||
<setting key="guest_captcha"><![CDATA[{"key":"guest_captcha","default":"1","report":"full"}]]></setting>
|
||||
<setting key="guest_terms_bar"><![CDATA[{"key":"guest_terms_bar","default":"0","report":"full"}]]></setting>
|
||||
<setting key="htaccess_mod_rewrite"><![CDATA[{"key":"htaccess_mod_rewrite","default":"0","report":"full"}]]></setting>
|
||||
<setting key="icons_apple_startup"><![CDATA[{"key":"icons_apple_startup","default":"","report":"bool"}]]></setting>
|
||||
<setting key="icons_favicon"><![CDATA[{"key":"icons_favicon","default":"","report":"bool"}]]></setting>
|
||||
<setting key="icons_homescreen"><![CDATA[{"key":"icons_homescreen","default":"","report":"bool"}]]></setting>
|
||||
<setting key="icons_mask_color"><![CDATA[{"key":"icons_mask_color","default":"FFFFFF","report":"bool"}]]></setting>
|
||||
@@ -277,6 +286,7 @@
|
||||
<setting key="mobile_app_redirect_scheme"><![CDATA[{"key":"mobile_app_redirect_scheme","default":"","report":"bool"}]]></setting>
|
||||
<setting key="mobile_app_secret"><![CDATA[{"key":"mobile_app_secret","default":"","report":"none"}]]></setting>
|
||||
<setting key="most_online"><![CDATA[{"key":"most_online","default":"{\"count\":0,\"time\":0}","report":"none"}]]></setting>
|
||||
<setting key="mp_onboard_complete"><![CDATA[{"key":"mp_onboard_complete","default":"1","report":"none"}]]></setting>
|
||||
<setting key="new_device_email"><![CDATA[{"key":"new_device_email","default":"0","report":"full"}]]></setting>
|
||||
<setting key="new_reg_notify"><![CDATA[{"key":"new_reg_notify","default":"0","report":"full"}]]></setting>
|
||||
<setting key="notification_prefs_one_per_view"><![CDATA[{"key":"notification_prefs_one_per_view","default":"0","report":"full"}]]></setting>
|
||||
@@ -292,6 +302,7 @@
|
||||
<setting key="pixabay_apikey"><![CDATA[{"key":"pixabay_apikey","default":"","report":"none"}]]></setting>
|
||||
<setting key="pixabay_editor_permissions"><![CDATA[{"key":"pixabay_editor_permissions","default":"*","report":"none"}]]></setting>
|
||||
<setting key="pixabay_enabled"><![CDATA[{"key":"pixabay_enabled","default":"0","report":"full"}]]></setting>
|
||||
<setting key="pixabay_safesearch"><![CDATA[{"key":"pixabay_safesearch","default":"1","report":"full"}]]></setting>
|
||||
<setting key="poll_allow_public"><![CDATA[{"key":"poll_allow_public","default":"1","report":"full"}]]></setting>
|
||||
<setting key="poll_allow_vdelete"><![CDATA[{"key":"poll_allow_vdelete","default":"0","report":"full"}]]></setting>
|
||||
<setting key="pop3_password"><![CDATA[{"key":"pop3_password","default":"","report":"none"}]]></setting>
|
||||
@@ -300,7 +311,6 @@
|
||||
<setting key="pop3_tls"><![CDATA[{"key":"pop3_tls","default":"1","report":"none"}]]></setting>
|
||||
<setting key="pop3_user"><![CDATA[{"key":"pop3_user","default":"","report":"none"}]]></setting>
|
||||
<setting key="post_before_registering"><![CDATA[{"key":"post_before_registering","default":"1","report":"full"}]]></setting>
|
||||
<setting key="post_titlechange"><![CDATA[{"key":"post_titlechange","default":"500","report":"full"}]]></setting>
|
||||
<setting key="posts_add_nofollow"><![CDATA[{"key":"posts_add_nofollow","default":"1","report":"full"}]]></setting>
|
||||
<setting key="posts_add_nofollow_exclude"><![CDATA[{"key":"posts_add_nofollow_exclude","default":"","report":"bool"}]]></setting>
|
||||
<setting key="privacy_link"><![CDATA[{"key":"privacy_link","default":"","report":"bool"}]]></setting>
|
||||
@@ -332,14 +342,18 @@
|
||||
<setting key="prune_log_tasks"><![CDATA[{"key":"prune_log_tasks","default":"30","report":"full"}]]></setting>
|
||||
<setting key="prune_member_history"><![CDATA[{"key":"prune_member_history","default":"365","report":"full"}]]></setting>
|
||||
<setting key="prune_notifications"><![CDATA[{"key":"prune_notifications","default":"30","report":"full"}]]></setting>
|
||||
<setting key="prune_points_log"><![CDATA[{"key":"prune_points_log","default":"365","report":"full"}]]></setting>
|
||||
<setting key="quick_register"><![CDATA[{"key":"quick_register","default":"1","report":"full"}]]></setting>
|
||||
<setting key="rare_badge_percent"><![CDATA[{"key":"rare_badge_percent","default":"5","report":"full"}]]></setting>
|
||||
<setting key="reaction_count_display"><![CDATA[{"key":"reaction_count_display","default":"individual","report":"full"}]]></setting>
|
||||
<setting key="reaction_is_likemode"><![CDATA[{"key":"reaction_is_likemode","default":"","report":"full"}]]></setting>
|
||||
<setting key="recaptcha2_private_key"><![CDATA[{"key":"recaptcha2_private_key","default":"6LcH7UEUAAAAANmcQmZErdGW2FXwVhtRBVXBWBUA","report":"bool"}]]></setting>
|
||||
<setting key="recaptcha2_public_key"><![CDATA[{"key":"recaptcha2_public_key","default":"6LcH7UEUAAAAAIGWgOoyBKAqjLmOIKzfJTOjyC7z","report":"bool"}]]></setting>
|
||||
<setting key="ref_on"><![CDATA[{"key":"ref_on","default":"0","report":"full"}]]></setting>
|
||||
<setting key="referrer_policy_header"><![CDATA[{"key":"referrer_policy_header","default":"2","report":"full"}]]></setting>
|
||||
<setting key="reg_auth_type"><![CDATA[{"key":"reg_auth_type","default":"user","report":"full"}]]></setting>
|
||||
<setting key="reg_rules"><![CDATA[{"key":"reg_rules","default":"<p>Please take a moment to review these rules.<\/p><p>Please remember that we are not responsible for any messages posted. We do not vouch for or warrant the accuracy, completeness or usefulness of any message, and are not responsible for the contents of any message.<\/p><p>The messages express the views of the author of the message, not necessarily the views of this website. Any user who feels that a posted message is objectionable is encouraged to contact us immediately by email. We have the ability to remove objectionable messages and we will make every effort to do so, within a reasonable time frame, if we determine that removal is necessary.<\/p><p>You agree, through your use of this service, that you will not use this website to post any material which is knowingly false and\/or defamatory, inaccurate, abusive, vulgar, hateful, harassing, obscene, profane, sexually oriented, threatening, invasive of a person's privacy, or otherwise violative of any law.<\/p><p>You agree not to post any copyrighted material unless the copyright is owned by you or by this website.<\/p><p>Our software uses cookies to distinguish you from other users of our website. This helps us to provide you with a personalized experience when you browse this site.<\/p>","report":"bool"}]]></setting>
|
||||
<setting key="relative_dates_enable"><![CDATA[{"key":"relative_dates_enable","default":"1","report":"full"}]]></setting>
|
||||
<setting key="remote_image_cache"><![CDATA[{"key":"remote_image_cache","default":"7","report":"full"}]]></setting>
|
||||
<setting key="reputation_can_self_vote"><![CDATA[{"key":"reputation_can_self_vote","default":"0","report":"full"}]]></setting>
|
||||
<setting key="reputation_enabled"><![CDATA[{"key":"reputation_enabled","default":"1","report":"full"}]]></setting>
|
||||
@@ -356,6 +370,7 @@
|
||||
<setting key="reputation_top_members_filters"><![CDATA[{"key":"reputation_top_members_filters","default":"*","report":"bool"}]]></setting>
|
||||
<setting key="reputation_top_members_overview"><![CDATA[{"key":"reputation_top_members_overview","default":"pp_reputation_points,member_posts","report":"full"}]]></setting>
|
||||
<setting key="reviews_rating_out_of"><![CDATA[{"key":"reviews_rating_out_of","default":"5","report":"full"}]]></setting>
|
||||
<setting key="rules_exclude_groups"><![CDATA[{"key":"rules_exclude_groups","default":"[]","report":"none"}]]></setting>
|
||||
<setting key="search_decay_days"><![CDATA[{"key":"search_decay_days","default":"120","report":"full"}]]></setting>
|
||||
<setting key="search_decay_factor"><![CDATA[{"key":"search_decay_factor","default":"0.5","report":"full"}]]></setting>
|
||||
<setting key="search_default_operator"><![CDATA[{"key":"search_default_operator","default":"or","report":"full"}]]></setting>
|
||||
@@ -409,6 +424,7 @@
|
||||
<setting key="spam_service_action_2"><![CDATA[{"key":"spam_service_action_2","default":"1","report":"full"}]]></setting>
|
||||
<setting key="spam_service_action_3"><![CDATA[{"key":"spam_service_action_3","default":"2","report":"full"}]]></setting>
|
||||
<setting key="spam_service_action_4"><![CDATA[{"key":"spam_service_action_4","default":"4","report":"full"}]]></setting>
|
||||
<setting key="spam_service_days"><![CDATA[{"key":"spam_service_days","default":"","report":"bool"}]]></setting>
|
||||
<setting key="spam_service_enabled"><![CDATA[{"key":"spam_service_enabled","default":"1","report":"full"}]]></setting>
|
||||
<setting key="spam_service_send_to_ips"><![CDATA[{"key":"spam_service_send_to_ips","default":"1","report":"full"}]]></setting>
|
||||
<setting key="sparkpost_api_key"><![CDATA[{"key":"sparkpost_api_key","default":"","report":"none"}]]></setting>
|
||||
@@ -455,6 +471,8 @@
|
||||
<setting key="use_friendly_urls"><![CDATA[{"key":"use_friendly_urls","default":"1","report":"full"}]]></setting>
|
||||
<setting key="username_characters"><![CDATA[{"key":"username_characters","default":"\/^(([\\p{L}\\p{M}\\p{N}_\\.\\-,]+) ?)+$\/u","report":"bool"}]]></setting>
|
||||
<setting key="validate_day_prune"><![CDATA[{"key":"validate_day_prune","default":"30","report":"full"}]]></setting>
|
||||
<setting key="vapid_private_key"><![CDATA[{"key":"vapid_private_key","default":"","report":"none"}]]></setting>
|
||||
<setting key="vapid_public_key"><![CDATA[{"key":"vapid_public_key","default":"","report":"none"}]]></setting>
|
||||
<setting key="viglink_api_key"><![CDATA[{"key":"viglink_api_key","default":"","report":"none"}]]></setting>
|
||||
<setting key="viglink_enabled"><![CDATA[{"key":"viglink_enabled","default":"0","report":"full"}]]></setting>
|
||||
<setting key="viglink_groups"><![CDATA[{"key":"viglink_groups","default":"","report":"bool"}]]></setting>
|
||||
@@ -482,11 +500,15 @@
|
||||
<widget key="clubs"><![CDATA[{"class":"\\IPS\\Widget","restrict":["sidebar","cms"],"default_area":"","allow_reuse":true,"menu_style":"modal","embeddable":true}]]></widget>
|
||||
<widget key="newsletter"><![CDATA[{"class":"\\IPS\\Widget","restrict":["sidebar","cms"],"default_area":"","allow_reuse":false,"menu_style":"modal","embeddable":true}]]></widget>
|
||||
<widget key="mostContributions"><![CDATA[{"class":"\\IPS\\Widget\\StaticCache","restrict":["sidebar","cms"],"default_area":"","allow_reuse":true,"menu_style":"menu","embeddable":true}]]></widget>
|
||||
<widget key="oembed"><![CDATA[{"class":"\\IPS\\Widget\\StaticCache","restrict":["sidebar","cms"],"default_area":"","allow_reuse":true,"menu_style":"modal","embeddable":true}]]></widget>
|
||||
<widget key="twitter"><![CDATA[{"class":"\\IPS\\Widget\\StaticCache","restrict":["sidebar","cms"],"default_area":"","allow_reuse":true,"menu_style":"modal","embeddable":true}]]></widget>
|
||||
<widget key="invite"><![CDATA[{"class":"\\IPS\\Widget\\StaticCache","restrict":["sidebar","cms"],"default_area":"","allow_reuse":false,"menu_style":"menu","embeddable":true}]]></widget>
|
||||
<widget key="stream"><![CDATA[{"class":"\\IPS\\Widget\\PermissionCache","restrict":["sidebar","cms"],"default_area":"","allow_reuse":true,"menu_style":"menu","embeddable":true}]]></widget>
|
||||
<widget key="mostSolved"><![CDATA[{"class":"\\IPS\\Widget\\StaticCache","restrict":["sidebar","cms"],"default_area":"","allow_reuse":false,"menu_style":"modal","embeddable":true}]]></widget>
|
||||
<widget key="achievements"><![CDATA[{"class":"\\IPS\\Widget\\StaticCache","restrict":["sidebar","cms"],"default_area":"","allow_reuse":true,"menu_style":"menu","embeddable":true}]]></widget>
|
||||
<acpsearch key="app=core&module=achievements&controller=badges"><![CDATA[{"lang_key":"menu__core_achievements_badges","restriction":"badges_manage","keywords":["awards","badges","rewards","trophies","trophy"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=achievements&controller=ranks"><![CDATA[{"lang_key":"menu__core_membersettings_ranks","restriction":"ranks_manage","keywords":["badges","ranks","titles"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=achievements&controller=rules"><![CDATA[{"lang_key":"achievements_rules","restriction":"rules_manage","keywords":["achievement rules","achievements","awards","badges","karma","points","rules"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=achievements&controller=settings"><![CDATA[{"lang_key":"menu__core_achievements_settings","restriction":"settings_manage","keywords":["achievement","badge","rare badge"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=activitystats&controller=communityactivity"><![CDATA[{"lang_key":"menu__core_activitystats_communityactivity","restriction":null,"keywords":["active members","activity","community activity","member activity","new posts"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=activitystats&controller=keywords"><![CDATA[{"lang_key":"menu__core_activitystats_keywords","restriction":null,"keywords":["keyword tracking","keywords","tracking"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=applications&controller=api"><![CDATA[{"lang_key":"menu__core_applications_api","restriction":"api_manage","keywords":["api","rest api"]}]]></acpsearch>
|
||||
@@ -515,7 +537,7 @@
|
||||
<acpsearch key="app=core&module=customization&controller=icons&searchResult=form_icons_homescreen"><![CDATA[{"lang_key":"icons_homescreen","restriction":"theme_sets_manage","keywords":["icon"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=customization&controller=icons&searchResult=form_icons_sharer_logo"><![CDATA[{"lang_key":"icons_sharer_logo","restriction":"theme_sets_manage","keywords":["logo","share logo"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=customization&controller=themes"><![CDATA[{"lang_key":"menu__core_customization_themes","restriction":"theme_sets_manage","keywords":["design","look","skins","themes"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=customization&controller=themes&do=designersmode&searchResult=form_theme_designers_mode"><![CDATA[{"lang_key":"theme_designers_mode","restriction":"theme_templates_manage","keywords":["designers mode"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=customization&controller=themes&do=designersmode&searchResult=form_theme_designers_mode"><![CDATA[{"lang_key":"theme_designers_mode","restriction":"theme_designers_mode","keywords":["designers mode"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=discovery&controller=rss"><![CDATA[{"lang_key":"menu__core_discovery_rss","restriction":null,"keywords":["feed","rss"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=discovery&controller=search"><![CDATA[{"lang_key":"menu__core_discovery_search","restriction":"search_manage","keywords":["rebuild search","rebuild search index","reindex","reindex search","reindex search results","search","search index","search index rebuild","searching"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=discovery&controller=search&searchResult=form_search_method"><![CDATA[{"lang_key":"search_method","restriction":"search_manage","keywords":["elastic","elasticsearch","mysql","search"]}]]></acpsearch>
|
||||
@@ -531,10 +553,11 @@
|
||||
<acpsearch key="app=core&module=languages&controller=languages"><![CDATA[{"lang_key":"menu__core_languages_languages","restriction":null,"keywords":["languages","locales","translate","translations"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=languages&controller=languages&do=settings&searchResult=form_lang_auto_detect"><![CDATA[{"lang_key":"lang_auto_detect","restriction":"lang_words","keywords":["detection","language"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=members&controller=groups"><![CDATA[{"lang_key":"menu__core_members_groups","restriction":"groups_manage","keywords":["groups"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=members&controller=groups&do=form&searchResult=g_promote_exclude"><![CDATA[{"lang_key":"g_promote_exclude","restriction":"groups_manage","keywords":["group promotion","member promotions","member upgrades"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=members&controller=groups&do=form&searchResult=g_upload_animated_photos"><![CDATA[{"lang_key":"g_upload_animated_photos","restriction":"groups_manage","keywords":["animated","photos"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=members&controller=groups&do=form&searchResult=gbw_hide_group"><![CDATA[{"lang_key":"gbw_hide_group","restriction":"groups_manage","keywords":["allow filtering","online users","search"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=members&controller=groups&do=form&searchResult=gbw_post_highlight"><![CDATA[{"lang_key":"gbw_post_highlight","restriction":"groups_manage","keywords":["background","highlight","highlight post","replies"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=members&controller=groups&searchResult=g_promote_exclude"><![CDATA[{"lang_key":"g_promote_exclude","restriction":"groups_manage","keywords":["group promotion","member promotions","member upgrades"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=members&controller=groups&searchResult=g_upload_animated_photos"><![CDATA[{"lang_key":"g_upload_animated_photos","restriction":"groups_manage","keywords":["animated","photos"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=members&controller=groups&searchResult=gbw_can_post_anonymously"><![CDATA[{"lang_key":"can_post_anonymously","restriction":"groups_manage","keywords":["anonymous","anonymously"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=members&controller=groups&searchResult=gbw_hide_group"><![CDATA[{"lang_key":"gbw_hide_group","restriction":"groups_manage","keywords":["allow filtering","online users","search"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=members&controller=groups&searchResult=gbw_post_highlight"><![CDATA[{"lang_key":"gbw_post_highlight","restriction":"groups_manage","keywords":["background","highlight","highlight post","replies"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=members&controller=groups&searchResult=g_access_offline"><![CDATA[{"lang_key":"g_access_offline","restriction":"groups_manage","keywords":["offline access","site offline"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=members&controller=groups&searchResult=g_append_edit"><![CDATA[{"lang_key":"g_append_edit","restriction":"groups_manage","keywords":["edit","silent edit"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=members&controller=groups&searchResult=g_attach"><![CDATA[{"lang_key":"g_attach","restriction":"groups_manage","keywords":["attachments","uploads"]}]]></acpsearch>
|
||||
@@ -603,9 +626,8 @@
|
||||
<acpsearch key="app=core&module=membersettings&controller=notifications&do=edit&id=core_Content"><![CDATA[{"lang_key":"notifications__core_Content","restriction":"notifications_manage","keywords":["automatically follow","email limit","follow","followed content","followed members","limit emails"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=membersettings&controller=notifications&do=edit&id=core_Messenger"><![CDATA[{"lang_key":"notifications__core_Messenger","restriction":"notifications_manage","keywords":["messenger pop up window","messenger popup window","pm pop up window","pm popup window"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=membersettings&controller=notifications&do=method&id=inline&searchResult=notification_prefs_sound"><![CDATA[{"lang_key":"notification_prefs_sound","restriction":"notifications_manage","keywords":["notification sounds"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=membersettings&controller=notifications&do=method&id=inline&searchResult=prune_notifications"><![CDATA[{"lang_key":"prune_notifications","restriction":"notifications_manage","keywords":["prune notifications"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=membersettings&controller=notifications&do=pruneSettings&searchResult=form_prune_notifications"><![CDATA[{"lang_key":"prune_notifications","restriction":"notifications_manage","keywords":["notifications","prune"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=membersettings&controller=notifications&do=pruneSettings&searchResult=prune_follows"><![CDATA[{"lang_key":"prune_follows","restriction":"notifications_manage","keywords":["follow","prune"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=membersettings&controller=notifications&do=pruneSettings&searchResult=form_prune_notifications"><![CDATA[{"lang_key":"prune_notifications","restriction":"notifications_prune","keywords":["notifications","prune"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=membersettings&controller=notifications&do=pruneSettings&searchResult=prune_follows"><![CDATA[{"lang_key":"prune_follows","restriction":"notifications_prune","keywords":["follow","prune"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=membersettings&controller=profiles"><![CDATA[{"lang_key":"profile_fields","restriction":"profiles_manage","keywords":["custom fields","custom profile","custom profile fields","edit fields","edit profile fields","profile fields"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=membersettings&controller=profiles&tab=profilecompletion"><![CDATA[{"lang_key":"profile_completion","restriction":"profiles_manage","keywords":["complete my profile","complete profile","complete your profile","profile completion","register completion","registration completion","sign up completion"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=membersettings&controller=profiles&tab=profilesettings"><![CDATA[{"lang_key":"profile_settings","restriction":"profiles_manage","keywords":["first","link target","recent","unread"]}]]></acpsearch>
|
||||
@@ -619,12 +641,11 @@
|
||||
<acpsearch key="app=core&module=membersettings&controller=profiles&tab=profilesettings&searchResult=ignore_system_on"><![CDATA[{"lang_key":"ignore_system_on","restriction":"profiles_manage","keywords":["ignore","ignoring"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=membersettings&controller=profiles&tab=profilesettings&searchResult=profile_birthday_type"><![CDATA[{"lang_key":"profile_birthday_type","restriction":"profiles_manage","keywords":["birthday"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=membersettings&controller=profiles&tab=profilesettings&searchResult=profile_comment_approval"><![CDATA[{"lang_key":"profile_comment_approval","restriction":"profiles_manage","keywords":["profile comments","profile statuses"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=membersettings&controller=profiles&tab=profilesettings&searchResult=prune_item_markers"><![CDATA[{"lang_key":"prune_item_markers","restriction":"profiles_manage","keywords":["item markers","prune"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=membersettings&controller=profiles&tab=profilesettings&searchResult=prune_known_devices"><![CDATA[{"lang_key":"prune_known_devices","restriction":"profiles_manage","keywords":["device history","prune"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=membersettings&controller=profiles&tab=profilesettings&searchResult=prune_known_ips"><![CDATA[{"lang_key":"prune_known_ips","restriction":"profiles_manage","keywords":["address","ip address","prune"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=membersettings&controller=profiles&tab=profilesettings&searchResult=prune_member_history"><![CDATA[{"lang_key":"prune_member_history","restriction":"profiles_manage","keywords":["change log","member history"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=membersettings&controller=profiles&tab=profilesettings&searchResult=prune_item_markers"><![CDATA[{"lang_key":"prune_item_markers","restriction":"member_history_prune","keywords":["item markers","prune"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=membersettings&controller=profiles&tab=profilesettings&searchResult=prune_known_devices"><![CDATA[{"lang_key":"prune_known_devices","restriction":"member_history_prune","keywords":["device history","prune"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=membersettings&controller=profiles&tab=profilesettings&searchResult=prune_known_ips"><![CDATA[{"lang_key":"prune_known_ips","restriction":"member_history_prune","keywords":["address","ip address","prune"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=membersettings&controller=profiles&tab=profilesettings&searchResult=prune_member_history"><![CDATA[{"lang_key":"prune_member_history","restriction":"member_history_prune","keywords":["change log","member history"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=membersettings&controller=profiles&tab=profilesettings&searchResult=user_name_length"><![CDATA[{"lang_key":"user_name_length","restriction":"profiles_manage","keywords":["display name length","display name size","maximum display name length","maximum display name size","maximum username length","maximum username size","minimum display name length","minimum display name size","minimum username length","minimum username size","username length","username size"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=membersettings&controller=ranks"><![CDATA[{"lang_key":"menu__core_membersettings_ranks","restriction":"ranks_manage","keywords":["badges","ranks","titles"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=membersettings&controller=referrals"><![CDATA[{"lang_key":"menu__core_membersettings_referrals","restriction":"referrals_manage","keywords":["comision","comission","commision","commission","invitations","invites","refer","referals","referral settings","referrals","reffer"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=membersettings&controller=reputation"><![CDATA[{"lang_key":"menu__core_membersettings_reputation","restriction":"reps_manage","keywords":["karma","likes","reactions","reputation"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=membersettings&controller=reputation&searchResult=form_reaction_count_display"><![CDATA[{"lang_key":"reaction_count_display","restriction":"reps_manage","keywords":["reaction display"]}]]></acpsearch>
|
||||
@@ -643,7 +664,8 @@
|
||||
<acpsearch key="app=core&module=membersettings&controller=reputation&tab=leaderboard&searchResult=reputation_max_members"><![CDATA[{"lang_key":"reputation_top_members_overview","restriction":"reps_manage","keywords":["top members"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=membersettings&controller=reputation&tab=leaderboard&searchResult=reputation_show_days_won_trophy"><![CDATA[{"lang_key":"reputation_show_days_won_trophy","restriction":"reps_manage","keywords":["leaderboard","winner"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=messengerstats&controller=pmstats"><![CDATA[{"lang_key":"menu__core_members_pmstats","restriction":null,"keywords":["message statistics","Messenger Statistics","private messages"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=moderation&controller=reportedContent"><![CDATA[{"lang_key":"menu__core_moderation_reportedContent","restriction":"reportedContent_manage","keywords":["moderation","report"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=moderation&controller=reportedContent"><![CDATA[{"lang_key":"menu__core_moderation_reportedContent","restriction":"reportedContent_manage","keywords":["moderation","report","report types"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=moderation&controller=reportedContentTypes"><![CDATA[{"lang_key":"menu__core_moderation_reportedContentTypes","restriction":null,"keywords":["report","report types"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=moderation&controller=spam"><![CDATA[{"lang_key":"menu__core_moderation_spam","restriction":"spam_manage","keywords":["spam","spammers"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=moderation&controller=spam&do=serviceLogs"><![CDATA[{"lang_key":"spamlogs","restriction":"spam_service_log","keywords":["spam logs"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=moderation&controller=spam&searchResult=bot_antispam_type"><![CDATA[{"lang_key":"bot_antispam_type","restriction":"spam_manage","keywords":["bot prevention","CAPTCHA","security question"]}]]></acpsearch>
|
||||
@@ -672,15 +694,15 @@
|
||||
<acpsearch key="app=core&module=promotion&controller=promote&tab=schedule"><![CDATA[{"lang_key":"promote_tab_schedule","restriction":"promote_manage","keywords":["schedule"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=promotion&controller=promote&tab=twitter"><![CDATA[{"lang_key":"promote_tab_twitter","restriction":"promote_manage","keywords":["twitter"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=promotion&controller=seo"><![CDATA[{"lang_key":"menu__core_promotion_seo","restriction":"seo_manage","keywords":["analytics","furl","search","search engine optimization","seo"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=promotion&controller=seo&tab=metatags"><![CDATA[{"lang_key":"seo_tab_metatags","restriction":"seo_manage","keywords":["description","keywords","meta tags","robots"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=promotion&controller=seo&tab=sitemap"><![CDATA[{"lang_key":"seo_tab_sitemap","restriction":"seo_manage","keywords":["google","priority","site map","sitemap","xml"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=promotion&controller=seo&tab=urls"><![CDATA[{"lang_key":"seo_tab_furls","restriction":"seo_manage","keywords":["friendly url","furls","htaccess","mod_rewrite","urls"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=promotion&controller=seo&tab=metatags"><![CDATA[{"lang_key":"seo_tab_metatags","restriction":"seo_meta","keywords":["description","keywords","meta tags","robots"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=promotion&controller=seo&tab=sitemap"><![CDATA[{"lang_key":"seo_tab_sitemap","restriction":"seo_sitemap","keywords":["google","priority","site map","sitemap","xml"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=promotion&controller=seo&tab=urls"><![CDATA[{"lang_key":"seo_tab_furls","restriction":"seo_furls","keywords":["friendly url","furls","htaccess","mod_rewrite","urls"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=promotion&controller=sharelinks"><![CDATA[{"lang_key":"menu__core_promotion_sharelinks","restriction":"sharelinks_manage","keywords":["facebook","linkedin","reddit","share links","stumbleupon","twitter"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=settings&controller=advanced&do=tasks"><![CDATA[{"lang_key":"task_manager","restriction":null,"keywords":["cron","cronjob","task","tasklog","tasks"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=settings&controller=advanced&searchResult=form_auto_polling_enabled"><![CDATA[{"lang_key":"auto_polling_enabled","restriction":"advanced_manage","keywords":["auto","automatic","polling"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=settings&controller=advanced&searchResult=form_lazy_load_enabled"><![CDATA[{"lang_key":"lazy_load_enabled","restriction":"advanced_manage","keywords":["images","lazy load","lazy loading","lazyloading"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=settings&controller=advanced&tab=datastore"><![CDATA[{"lang_key":"data_store","restriction":"datastore","keywords":["storage"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=settings&controller=advanced&tab=datastore&searchResult=cache_guest_page"><![CDATA[{"lang_key":"cache_guest_page","restriction":"advanced_manage_server","keywords":["cache","guest cache","output cache"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=settings&controller=advanced&tab=datastore&searchResult=cache_guest_page"><![CDATA[{"lang_key":"cache_guest_page","restriction":"datastore","keywords":["cache","guest cache","output cache"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=settings&controller=advanced&tab=datastore&searchResult=cache_method"><![CDATA[{"lang_key":"cache_method","restriction":"datastore","keywords":["apc","memcached","redis","wincache","xcache"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=settings&controller=advanced&tab=furl"><![CDATA[{"lang_key":"furls_customize","restriction":"advanced_manage_furls","keywords":["friendly","furl","seo"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=settings&controller=advanced&tab=settings&searchResult=form_clickjackprevention"><![CDATA[{"lang_key":"clickjackprevention","restriction":"advanced_manage","keywords":["clickjacking","content-security-policy","csp","iframe","x-frame-options"]}]]></acpsearch>
|
||||
@@ -691,6 +713,7 @@
|
||||
<acpsearch key="app=core&module=settings&controller=email"><![CDATA[{"lang_key":"menu__core_settings_email","restriction":"email_manage","keywords":["address","email","email logo","mail","smtp"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=settings&controller=email&do=errorLog"><![CDATA[{"lang_key":"emailerrorlogs","restriction":"email_errorlog","keywords":["email error logs","email logs","logs"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=settings&controller=email&searchResult=email_log_do"><![CDATA[{"lang_key":"email_log_do","restriction":"email_manage","keywords":["email log","email statistics","statistics"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=settings&controller=email&searchResult=email_truncate"><![CDATA[{"lang_key":"email_truncate","restriction":"email_manage","keywords":["truncate"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=settings&controller=email&searchResult=our_picks_in_email"><![CDATA[{"lang_key":"our_picks_in_email","restriction":"email_manage","keywords":["email","our picks","promotion"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=settings&controller=email&searchResult=settings_form_email_color"><![CDATA[{"lang_key":"email_color","restriction":"email_manage","keywords":["email color","email colour"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=settings&controller=email&searchResult=settings_form_email_in"><![CDATA[{"lang_key":"email_in","restriction":"email_manage","keywords":["contact email","contact us email","incoming email"]}]]></acpsearch>
|
||||
@@ -776,76 +799,24 @@
|
||||
<acpsearch key="app=core&module=support&controller=errorLogs"><![CDATA[{"lang_key":"error_logs","restriction":null,"keywords":["error log","errors","logs"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=support&controller=support"><![CDATA[{"lang_key":"menu__core_support_support","restriction":"support_dashboard","keywords":["diagnose","diagnostics","documentation","help","phpinfo","server","support","system","tech support","technical support","troubleshoot"]}]]></acpsearch>
|
||||
<acpsearch key="app=core&module=support&controller=systemLogs"><![CDATA[{"lang_key":"system_logs","restriction":null,"keywords":["driver errors","logs","sql error logs","sql logs","system logs"]}]]></acpsearch>
|
||||
<themesetting key="ajax_pagination"><![CDATA[{"sc_key":"ajax_pagination","sc_type":"YesNo","sc_multiple":0,"sc_content":"[{\"key\":\"\",\"value\":\"\"}]","sc_app":"core","sc_default":"1","sc_tab_key":"custom","sc_show_in_vse":1,"sc_title":"themesetting_ajax_pagination","sc_order":10,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="active_input_border"><![CDATA[{"sc_key":"active_input_border","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#3480bb","sc_tab_key":"frontendcolors","sc_show_in_vse":0,"sc_title":"themesetting_active_input_border","sc_order":36,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="ajax_pagination"><![CDATA[{"sc_key":"ajax_pagination","sc_type":"YesNo","sc_multiple":0,"sc_content":"[{\"key\":\"\",\"value\":\"\"}]","sc_app":"core","sc_default":"1","sc_tab_key":"custom","sc_show_in_vse":1,"sc_title":"themesetting_ajax_pagination","sc_order":11,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="alternate_button"><![CDATA[{"sc_key":"alternate_button","sc_type":"Color","sc_multiple":0,"sc_content":"[{\"key\":\"\",\"value\":\"\"}]","sc_app":"core","sc_default":"#177ec9","sc_tab_key":"buttoncolors","sc_show_in_vse":0,"sc_title":"themesetting_alternate_button","sc_order":3,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="alternate_button_font"><![CDATA[{"sc_key":"alternate_button_font","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#ffffff","sc_tab_key":"buttoncolors","sc_show_in_vse":0,"sc_title":"themesetting_alternate_button_font","sc_order":4,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="area_background"><![CDATA[{"sc_key":"area_background","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#edf2f7","sc_tab_key":"frontendcolors","sc_show_in_vse":0,"sc_title":"themesetting_area_background","sc_order":10,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="area_background_dark"><![CDATA[{"sc_key":"area_background_dark","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#2d3748","sc_tab_key":"frontendcolors","sc_show_in_vse":0,"sc_title":"themesetting_area_background_dark","sc_order":9,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="area_background_light"><![CDATA[{"sc_key":"area_background_light","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#f7fafc","sc_tab_key":"frontendcolors","sc_show_in_vse":0,"sc_title":"themesetting_area_background_light","sc_order":11,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="area_background_reset"><![CDATA[{"sc_key":"area_background_reset","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#ffffff","sc_tab_key":"frontendcolors","sc_show_in_vse":0,"sc_title":"themesetting_area_background_reset","sc_order":12,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="button_bar"><![CDATA[{"sc_key":"button_bar","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#ffffff","sc_tab_key":"buttoncolors","sc_show_in_vse":0,"sc_title":"themesetting_button_bar","sc_order":13,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="enable_fluid_width"><![CDATA[{"sc_key":"enable_fluid_width","sc_type":"YesNo","sc_multiple":0,"sc_content":"[{\"key\":\"\",\"value\":\"\"},{\"key\":\"\",\"value\":\"\"}]","sc_app":"core","sc_default":"0","sc_tab_key":"custom","sc_show_in_vse":1,"sc_title":"themesetting_enable_fluid_width","sc_order":7,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="fluid_width_size"><![CDATA[{"sc_key":"fluid_width_size","sc_type":"Number","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"95","sc_tab_key":"custom","sc_show_in_vse":1,"sc_title":"themesetting_fluid_width_size","sc_order":8,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="header"><![CDATA[{"sc_key":"header","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#ffffff","sc_tab_key":"frontendcolors","sc_show_in_vse":0,"sc_title":"themesetting_header","sc_order":3,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="important_button"><![CDATA[{"sc_key":"important_button","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#177ec9","sc_tab_key":"buttoncolors","sc_show_in_vse":0,"sc_title":"themesetting_important_button","sc_order":7,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="important_button_font"><![CDATA[{"sc_key":"important_button_font","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#ffffff","sc_tab_key":"buttoncolors","sc_show_in_vse":0,"sc_title":"themesetting_important_button_font","sc_order":8,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="js_include"><![CDATA[{"sc_key":"js_include","sc_type":"Radio","sc_multiple":0,"sc_content":"[{\"key\":\"head\",\"value\":\"themesetting_js_position_head\"},{\"key\":\"footer\",\"value\":\"themesetting_js_position_body\"}]","sc_app":"core","sc_default":"footer","sc_tab_key":"custom","sc_show_in_vse":0,"sc_title":"themesetting_js_location","sc_order":9,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="light_button"><![CDATA[{"sc_key":"light_button","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#e8f2fa","sc_tab_key":"buttoncolors","sc_show_in_vse":0,"sc_title":"themesetting_light_button","sc_order":9,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="light_button_font"><![CDATA[{"sc_key":"light_button_font","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#0e4c79","sc_tab_key":"buttoncolors","sc_show_in_vse":0,"sc_title":"themesetting_light_button_font","sc_order":10,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="link"><![CDATA[{"sc_key":"link","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#1a202c","sc_tab_key":"textcolors","sc_show_in_vse":0,"sc_title":"themesetting_link","sc_order":6,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="link_hover"><![CDATA[{"sc_key":"link_hover","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#177ec9","sc_tab_key":"textcolors","sc_show_in_vse":0,"sc_title":"themesetting_link_hover","sc_order":7,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="main_nav"><![CDATA[{"sc_key":"main_nav","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#1265a1","sc_tab_key":"frontendcolors","sc_show_in_vse":0,"sc_title":"themesetting_main_nav","sc_order":5,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="moderated"><![CDATA[{"sc_key":"moderated","sc_type":"Color","sc_multiple":0,"sc_content":"[{\"key\":\"\",\"value\":\"\"}]","sc_app":"core","sc_default":"#f7edf1","sc_tab_key":"frontendcolors","sc_show_in_vse":0,"sc_title":"themesetting_moderated","sc_order":20,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="moderated_light"><![CDATA[{"sc_key":"moderated_light","sc_type":"Color","sc_multiple":0,"sc_content":"[{\"key\":\"\",\"value\":\"\"}]","sc_app":"core","sc_default":"#fcf7f9","sc_tab_key":"frontendcolors","sc_show_in_vse":0,"sc_title":"themesetting_moderated_light","sc_order":21,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="moderated_text"><![CDATA[{"sc_key":"moderated_text","sc_type":"Color","sc_multiple":0,"sc_content":"[{\"key\":\"\",\"value\":\"\"}]","sc_app":"core","sc_default":"#880e4f","sc_tab_key":"frontendcolors","sc_show_in_vse":0,"sc_title":"themesetting_moderated_text","sc_order":22,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="moderated_text_light"><![CDATA[{"sc_key":"moderated_text_light","sc_type":"Color","sc_multiple":0,"sc_content":"[{\"key\":\"\",\"value\":\"\"}]","sc_app":"core","sc_default":"#a4768f","sc_tab_key":"frontendcolors","sc_show_in_vse":0,"sc_title":"themesetting_moderated_text_light","sc_order":23,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="normal_button"><![CDATA[{"sc_key":"normal_button","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#177ec9","sc_tab_key":"buttoncolors","sc_show_in_vse":0,"sc_title":"themesetting_normal_button","sc_order":5,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="normal_button_font"><![CDATA[{"sc_key":"normal_button_font","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#ffffff","sc_tab_key":"buttoncolors","sc_show_in_vse":0,"sc_title":"themesetting_normal_button_font","sc_order":6,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="page_background"><![CDATA[{"sc_key":"page_background","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#edf0f4","sc_tab_key":"frontendcolors","sc_show_in_vse":0,"sc_title":"themesetting_page_background","sc_order":2,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="prefix"><![CDATA[{"sc_key":"prefix","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#177ec9","sc_tab_key":"frontendcolors","sc_show_in_vse":0,"sc_title":"themesetting_prefix","sc_order":17,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="price"><![CDATA[{"sc_key":"price","sc_type":"Color","sc_multiple":0,"sc_content":"[{\"key\":\"\",\"value\":\"\"}]","sc_app":"core","sc_default":"#b63f3f","sc_tab_key":"textcolors","sc_show_in_vse":0,"sc_title":"themesetting_price","sc_order":14,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="primary_button"><![CDATA[{"sc_key":"primary_button","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#177ec9","sc_tab_key":"buttoncolors","sc_show_in_vse":0,"sc_title":"themesetting_primary_button","sc_order":1,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="primary_button_font"><![CDATA[{"sc_key":"primary_button_font","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#ffffff","sc_tab_key":"buttoncolors","sc_show_in_vse":0,"sc_title":"themesetting_primary_button_font","sc_order":2,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="profile_header"><![CDATA[{"sc_key":"profile_header","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#353c41","sc_tab_key":"frontendcolors","sc_show_in_vse":0,"sc_title":"themesetting_profile_header","sc_order":15,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="rating_on"><![CDATA[{"sc_key":"rating_on","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#ff9800","sc_tab_key":"frontendcolors","sc_show_in_vse":0,"sc_title":"themesetting_rating_on","sc_order":24,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="responsive"><![CDATA[{"sc_key":"responsive","sc_type":"YesNo","sc_multiple":0,"sc_content":"[{\"key\":\"\",\"value\":\"\"},{\"key\":\"\",\"value\":\"\"}]","sc_app":"core","sc_default":"1","sc_tab_key":"custom","sc_show_in_vse":0,"sc_title":"themesetting_responsive","sc_order":1,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="rounded_photos"><![CDATA[{"sc_key":"rounded_photos","sc_type":"YesNo","sc_multiple":0,"sc_content":"[{\"key\":\"\",\"value\":\"\"},{\"key\":\"\",\"value\":\"\"}]","sc_app":"core","sc_default":"1","sc_tab_key":"custom","sc_show_in_vse":0,"sc_title":"themesetting_rounded_photos","sc_order":2,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="secondary_title"><![CDATA[{"sc_key":"secondary_title","sc_type":"Color","sc_multiple":0,"sc_content":"[{\"key\":\"\",\"value\":\"\"}]","sc_app":"core","sc_default":"#ebedf0","sc_tab_key":"textcolors","sc_show_in_vse":0,"sc_title":"themesetting_secondary_title","sc_order":11,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="secondary_title_font"><![CDATA[{"sc_key":"secondary_title_font","sc_type":"Color","sc_multiple":0,"sc_content":"[{\"key\":\"\",\"value\":\"\"}]","sc_app":"core","sc_default":"#828e99","sc_tab_key":"textcolors","sc_show_in_vse":0,"sc_title":"themesetting_secondary_title_font","sc_order":12,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="section_title"><![CDATA[{"sc_key":"section_title","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#ffffff","sc_tab_key":"textcolors","sc_show_in_vse":0,"sc_title":"themesetting_section_title","sc_order":8,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="section_title_font"><![CDATA[{"sc_key":"section_title_font","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#1a202c","sc_tab_key":"textcolors","sc_show_in_vse":0,"sc_title":"themesetting_section_title_font","sc_order":10,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="selected"><![CDATA[{"sc_key":"selected","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#ebf4f9","sc_tab_key":"frontendcolors","sc_show_in_vse":0,"sc_title":"themesetting_selected","sc_order":13,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="sidebar_position"><![CDATA[{"sc_key":"sidebar_position","sc_type":"Select","sc_multiple":0,"sc_content":"[{\"key\":\"left\",\"value\":\"Left\"},{\"key\":\"right\",\"value\":\"Right\"}]","sc_app":"core","sc_default":"right","sc_tab_key":"custom","sc_show_in_vse":0,"sc_title":"themesetting_sidebar_position","sc_order":4,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="sidebar_responsive"><![CDATA[{"sc_key":"sidebar_responsive","sc_type":"YesNo","sc_multiple":0,"sc_content":"[{\"key\":\"\",\"value\":\"\"}]","sc_app":"core","sc_default":"1","sc_tab_key":"custom","sc_show_in_vse":1,"sc_title":"themesetting_sidebar_responsive","sc_order":5,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="text_color"><![CDATA[{"sc_key":"text_color","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#353c41","sc_tab_key":"textcolors","sc_show_in_vse":0,"sc_title":"themesetting_text_color","sc_order":3,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="text_light"><![CDATA[{"sc_key":"text_light","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#718096","sc_tab_key":"textcolors","sc_show_in_vse":0,"sc_title":"themesetting_text_light","sc_order":5,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="very_light_button"><![CDATA[{"sc_key":"very_light_button","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#ffffff","sc_tab_key":"buttoncolors","sc_show_in_vse":0,"sc_title":"themesetting_very_light_button","sc_order":11,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="very_light_button_font"><![CDATA[{"sc_key":"very_light_button_font","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#0e4c79","sc_tab_key":"buttoncolors","sc_show_in_vse":0,"sc_title":"themesetting_very_light_button_font","sc_order":12,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="widget_title_bar"><![CDATA[{"sc_key":"widget_title_bar","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#ffffff","sc_tab_key":"frontendcolors","sc_show_in_vse":0,"sc_title":"themesetting_widget_title_bar","sc_order":18,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="item_status"><![CDATA[{"sc_key":"item_status","sc_type":"Color","sc_multiple":0,"sc_content":"[{\"key\":\"\",\"value\":\"\"}]","sc_app":"core","sc_default":"#1265a1","sc_tab_key":"frontendcolors","sc_show_in_vse":0,"sc_title":"themesetting_item_status_active","sc_order":26,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="notification_bubble"><![CDATA[{"sc_key":"notification_bubble","sc_type":"Color","sc_multiple":0,"sc_content":"[{\"key\":\"\",\"value\":\"\"}]","sc_app":"core","sc_default":"#36ab80","sc_tab_key":"frontendcolors","sc_show_in_vse":0,"sc_title":"themesetting_notification_bubble","sc_order":27,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="timeline_color"><![CDATA[{"sc_key":"timeline_color","sc_type":"Color","sc_multiple":0,"sc_content":"[{\"key\":\"\",\"value\":\"\"}]","sc_app":"core","sc_default":"#2d3748","sc_tab_key":"frontendcolors","sc_show_in_vse":0,"sc_title":"activity_stream_timeline","sc_order":25,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="main_nav_tab"><![CDATA[{"sc_key":"main_nav_tab","sc_type":"Color","sc_multiple":0,"sc_content":"[{\"key\":\"\",\"value\":\"\"}]","sc_app":"core","sc_default":"#ffffff","sc_tab_key":"frontendcolors","sc_show_in_vse":0,"sc_title":"themesetting_main_nav_active","sc_order":7,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="mentions"><![CDATA[{"sc_key":"mentions","sc_type":"Color","sc_multiple":0,"sc_content":"[{\"key\":\"\",\"value\":\"\"}]","sc_app":"core","sc_default":"#3d6594","sc_tab_key":"frontendcolors","sc_show_in_vse":0,"sc_title":"themesetting_mentions","sc_order":28,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="tab_background"><![CDATA[{"sc_key":"tab_background","sc_type":"Color","sc_multiple":0,"sc_content":"[{\"key\":\"\",\"value\":\"\"}]","sc_app":"core","sc_default":"#4a5568","sc_tab_key":"frontendcolors","sc_show_in_vse":0,"sc_title":"themesetting_tabs_background","sc_order":29,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="widget_title_font"><![CDATA[{"sc_key":"widget_title_font","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#1a202c","sc_tab_key":"frontendcolors","sc_show_in_vse":0,"sc_title":"themesetting_widget_font","sc_order":19,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="footer_text"><![CDATA[{"sc_key":"footer_text","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#353c41","sc_tab_key":"textcolors","sc_show_in_vse":0,"sc_title":"themesetting_footer_text","sc_order":13,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="main_nav_font"><![CDATA[{"sc_key":"main_nav_font","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#ffffff","sc_tab_key":"frontendcolors","sc_show_in_vse":0,"sc_title":"themesetting_main_nav_font","sc_order":6,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="main_nav_tab_font"><![CDATA[{"sc_key":"main_nav_tab_font","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#353c41","sc_tab_key":"frontendcolors","sc_show_in_vse":0,"sc_title":"themesetting_main_nav_active_font","sc_order":8,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="post_highlight"><![CDATA[{"sc_key":"post_highlight","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#fdf5e7","sc_tab_key":"frontendcolors","sc_show_in_vse":0,"sc_title":"themesetting_post_highlight","sc_order":30,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="post_highlight_border"><![CDATA[{"sc_key":"post_highlight_border","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#81622e","sc_tab_key":"frontendcolors","sc_show_in_vse":0,"sc_title":"themesettings_post_highlight_border","sc_order":31,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="recaptcha_theme"><![CDATA[{"sc_key":"recaptcha_theme","sc_type":"other","sc_multiple":0,"sc_content":"return new \\IPS\\Helpers\\Form\\Radio( \"core_theme_setting_title_{$row['sc_id']}\", $value, FALSE, array( 'options' => array(\r\n\t\t\t'clean'\t\t\t=> \"<img src='\" . $theme->resource( 'recaptcha\/clean.png', 'core' ) . \"' alt='clean'>\",\r\n\t\t\t'red'\t\t\t=> \"<img src='\" . $theme->resource( 'recaptcha\/red.png', 'core' ) . \"' alt='clean'>\",\r\n\t\t\t'white'\t\t\t=> \"<img src='\" . $theme->resource( 'recaptcha\/white.png', 'core' ) . \"' alt='clean'>\",\r\n\t\t\t'blackglass'\t=> \"<img src='\" . $theme->resource( 'recaptcha\/blackglass.png', 'core' ) . \"' alt='clean'>\",\r\n\t\t\t), 'parse' => 'raw' ), NULL, NULL, NULL, 'theme_setting_' . $row['sc_key'] );","sc_app":"core","sc_default":"white","sc_tab_key":"custom","sc_show_in_vse":0,"sc_title":"recaptcha_theme","sc_order":13,"sc_condition":"return \\IPS\\Settings::i()->bot_antispam_type === 'recaptcha';"}]]></themesetting>
|
||||
<themesetting key="recaptcha2_theme"><![CDATA[{"sc_key":"recaptcha2_theme","sc_type":"other","sc_multiple":0,"sc_content":"return new \\IPS\\Helpers\\Form\\Radio( \"core_theme_setting_title_{$row['sc_id']}\", $value, FALSE, array( 'options' => array(\r\n\t\t\t'light'\t\t\t=> \"<img src='\" . $theme->resource( 'recaptcha2\/light.png', 'core' ) . \"' alt='light'>\",\r\n\t\t\t'dark'\t\t\t=> \"<img src='\" . $theme->resource( 'recaptcha2\/dark.png', 'core' ) . \"' alt='dark'>\",\r\n\t\t\t), 'parse' => 'raw' ), NULL, NULL, NULL, 'theme_setting_' . $row['sc_key'] );","sc_app":"core","sc_default":"light","sc_tab_key":"custom","sc_show_in_vse":0,"sc_title":"recaptcha2_theme","sc_order":12,"sc_condition":"return \\IPS\\Settings::i()->bot_antispam_type === 'recaptcha2';"}]]></themesetting>
|
||||
<themesetting key="text_dark"><![CDATA[{"sc_key":"text_dark","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#000000","sc_tab_key":"textcolors","sc_show_in_vse":0,"sc_title":"themesetting_dark_text_color","sc_order":4,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="social_links"><![CDATA[{"sc_key":"social_links","sc_type":"Radio","sc_multiple":0,"sc_content":"[{\"key\":\"header\",\"value\":\"themesetting_header\"},{\"key\":\"footer\",\"value\":\"themesetting_footer\"}]","sc_app":"core","sc_default":"footer","sc_tab_key":"custom","sc_show_in_vse":1,"sc_title":"themesetting_social_links_pos","sc_order":3,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="tag"><![CDATA[{"sc_key":"tag","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#fff4df","sc_tab_key":"frontendcolors","sc_show_in_vse":0,"sc_title":"themesetting_tag","sc_order":16,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="pagination_active"><![CDATA[{"sc_key":"pagination_active","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#3e4148","sc_tab_key":"buttoncolors","sc_show_in_vse":0,"sc_title":"themesetting_pagination_active","sc_order":14,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="link_button"><![CDATA[{"sc_key":"link_button","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#177ec9","sc_tab_key":"buttoncolors","sc_show_in_vse":0,"sc_title":"themesetting_link_button","sc_order":15,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="featured"><![CDATA[{"sc_key":"featured","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#2c8c69","sc_tab_key":"frontendcolors","sc_show_in_vse":0,"sc_title":"themesetting_featured_color","sc_order":40,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="headline_font"><![CDATA[{"sc_key":"headline_font","sc_type":"Select","sc_multiple":0,"sc_content":"[{\"key\":\"default\",\"value\":\"Default\"},{\"key\":\"Inter\",\"value\":\"Inter\"},{\"key\":\"Lato\",\"value\":\"Lato\"},{\"key\":\"Open Sans\",\"value\":\"Open Sans\"},{\"key\":\"Roboto\",\"value\":\"Roboto\"},{\"key\":\"Roboto Slab\",\"value\":\"Roboto Slab\"},{\"key\":\"Montserrat\",\"value\":\"Montserrat\"},{\"key\":\"Merriweather\",\"value\":\"Merriweather\"}]","sc_app":"core","sc_default":"Inter","sc_tab_key":"textcolors","sc_show_in_vse":1,"sc_title":"themesetting_headline_font","sc_order":2,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="comment_count"><![CDATA[{"sc_key":"comment_count","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#edf2f7","sc_tab_key":"frontendcolors","sc_show_in_vse":0,"sc_title":"themesetting_comment_count","sc_order":38,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="comment_count_font"><![CDATA[{"sc_key":"comment_count_font","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#2d3748","sc_tab_key":"frontendcolors","sc_show_in_vse":0,"sc_title":"themesetting_comment_count_font","sc_order":39,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="body_font"><![CDATA[{"sc_key":"body_font","sc_type":"Select","sc_multiple":0,"sc_content":"[{\"key\":\"default\",\"value\":\"Default\"},{\"key\":\"Inter\",\"value\":\"Inter\"},{\"key\":\"Lato\",\"value\":\"Lato\"},{\"key\":\"Open Sans\",\"value\":\"Open Sans\"},{\"key\":\"Roboto\",\"value\":\"Roboto\"},{\"key\":\"Roboto Slab\",\"value\":\"Roboto Slab\"},{\"key\":\"Montserrat\",\"value\":\"Montserrat\"},{\"key\":\"Merriweather\",\"value\":\"Merriweather\"}]","sc_app":"core","sc_default":"Inter","sc_tab_key":"textcolors","sc_show_in_vse":1,"sc_title":"themesetting_body_font","sc_order":1,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="brand_primary"><![CDATA[{"sc_key":"brand_primary","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#177ec9","sc_tab_key":"frontendcolors","sc_show_in_vse":0,"sc_title":"themesetting_brand_primary","sc_order":1,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="button_bar"><![CDATA[{"sc_key":"button_bar","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#ffffff","sc_tab_key":"buttoncolors","sc_show_in_vse":0,"sc_title":"themesetting_button_bar","sc_order":13,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="comment_count"><![CDATA[{"sc_key":"comment_count","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#edf2f7","sc_tab_key":"frontendcolors","sc_show_in_vse":0,"sc_title":"themesetting_comment_count","sc_order":33,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="comment_count_font"><![CDATA[{"sc_key":"comment_count_font","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#2d3748","sc_tab_key":"frontendcolors","sc_show_in_vse":0,"sc_title":"themesetting_comment_count_font","sc_order":34,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="enable_fluid_width"><![CDATA[{"sc_key":"enable_fluid_width","sc_type":"YesNo","sc_multiple":0,"sc_content":"[{\"key\":\"\",\"value\":\"\"},{\"key\":\"\",\"value\":\"\"}]","sc_app":"core","sc_default":"0","sc_tab_key":"custom","sc_show_in_vse":1,"sc_title":"themesetting_enable_fluid_width","sc_order":8,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="featured"><![CDATA[{"sc_key":"featured","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#2c8c69","sc_tab_key":"frontendcolors","sc_show_in_vse":0,"sc_title":"themesetting_featured_color","sc_order":35,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="fluid_width_size"><![CDATA[{"sc_key":"fluid_width_size","sc_type":"Number","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"95","sc_tab_key":"custom","sc_show_in_vse":1,"sc_title":"themesetting_fluid_width_size","sc_order":9,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="font_2x_large"><![CDATA[{"sc_key":"font_2x_large","sc_type":"Number","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"24","sc_tab_key":"typescale","sc_show_in_vse":0,"sc_title":"font_2x_large","sc_order":7,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="font_3x_large"><![CDATA[{"sc_key":"font_3x_large","sc_type":"Number","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"30","sc_tab_key":"typescale","sc_show_in_vse":0,"sc_title":"font_3x_large","sc_order":8,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="font_4x_large"><![CDATA[{"sc_key":"font_4x_large","sc_type":"Number","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"36","sc_tab_key":"typescale","sc_show_in_vse":0,"sc_title":"font_4x_large","sc_order":9,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="font_base"><![CDATA[{"sc_key":"font_base","sc_type":"Number","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"16","sc_tab_key":"typescale","sc_show_in_vse":0,"sc_title":"font_base","sc_order":4,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="font_large"><![CDATA[{"sc_key":"font_large","sc_type":"Number","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"18","sc_tab_key":"typescale","sc_show_in_vse":0,"sc_title":"font_large","sc_order":5,"sc_condition":null}]]></themesetting>
|
||||
@@ -854,11 +825,66 @@
|
||||
<themesetting key="font_small"><![CDATA[{"sc_key":"font_small","sc_type":"Number","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"13","sc_tab_key":"typescale","sc_show_in_vse":0,"sc_title":"font_small","sc_order":2,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="font_x_large"><![CDATA[{"sc_key":"font_x_large","sc_type":"Number","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"20","sc_tab_key":"typescale","sc_show_in_vse":0,"sc_title":"font_x_large","sc_order":6,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="font_x_small"><![CDATA[{"sc_key":"font_x_small","sc_type":"Number","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"12","sc_tab_key":"typescale","sc_show_in_vse":0,"sc_title":"font_x_small","sc_order":1,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="footer_text"><![CDATA[{"sc_key":"footer_text","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#353c41","sc_tab_key":"textcolors","sc_show_in_vse":0,"sc_title":"themesetting_footer_text","sc_order":13,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="header"><![CDATA[{"sc_key":"header","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#ffffff","sc_tab_key":"frontendcolors","sc_show_in_vse":0,"sc_title":"themesetting_header","sc_order":3,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="header_height"><![CDATA[{"sc_key":"header_height","sc_type":"Number","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"80","sc_tab_key":"custom","sc_show_in_vse":0,"sc_title":"header_height","sc_order":2,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="header_height_mobile"><![CDATA[{"sc_key":"header_height_mobile","sc_type":"Number","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"55","sc_tab_key":"custom","sc_show_in_vse":0,"sc_title":"header_height_mobile","sc_order":3,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="header_text"><![CDATA[{"sc_key":"header_text","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#2d3748","sc_tab_key":"frontendcolors","sc_show_in_vse":0,"sc_title":"themesetting_header_text","sc_order":4,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="headline_font"><![CDATA[{"sc_key":"headline_font","sc_type":"Select","sc_multiple":0,"sc_content":"[{\"key\":\"default\",\"value\":\"Default\"},{\"key\":\"Inter\",\"value\":\"Inter\"},{\"key\":\"Lato\",\"value\":\"Lato\"},{\"key\":\"Open Sans\",\"value\":\"Open Sans\"},{\"key\":\"Roboto\",\"value\":\"Roboto\"},{\"key\":\"Roboto Slab\",\"value\":\"Roboto Slab\"},{\"key\":\"Montserrat\",\"value\":\"Montserrat\"},{\"key\":\"Merriweather\",\"value\":\"Merriweather\"}]","sc_app":"core","sc_default":"Inter","sc_tab_key":"textcolors","sc_show_in_vse":1,"sc_title":"themesetting_headline_font","sc_order":2,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="important_button"><![CDATA[{"sc_key":"important_button","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#177ec9","sc_tab_key":"buttoncolors","sc_show_in_vse":0,"sc_title":"themesetting_important_button","sc_order":7,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="important_button_font"><![CDATA[{"sc_key":"important_button_font","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#ffffff","sc_tab_key":"buttoncolors","sc_show_in_vse":0,"sc_title":"themesetting_important_button_font","sc_order":8,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="item_status"><![CDATA[{"sc_key":"item_status","sc_type":"Color","sc_multiple":0,"sc_content":"[{\"key\":\"\",\"value\":\"\"}]","sc_app":"core","sc_default":"#1265a1","sc_tab_key":"frontendcolors","sc_show_in_vse":0,"sc_title":"themesetting_item_status_active","sc_order":27,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="js_include"><![CDATA[{"sc_key":"js_include","sc_type":"Radio","sc_multiple":0,"sc_content":"[{\"key\":\"head\",\"value\":\"themesetting_js_position_head\"},{\"key\":\"footer\",\"value\":\"themesetting_js_position_body\"}]","sc_app":"core","sc_default":"footer","sc_tab_key":"custom","sc_show_in_vse":0,"sc_title":"themesetting_js_location","sc_order":10,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="light_button"><![CDATA[{"sc_key":"light_button","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#e8f2fa","sc_tab_key":"buttoncolors","sc_show_in_vse":0,"sc_title":"themesetting_light_button","sc_order":9,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="light_button_font"><![CDATA[{"sc_key":"light_button_font","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#0e4c79","sc_tab_key":"buttoncolors","sc_show_in_vse":0,"sc_title":"themesetting_light_button_font","sc_order":10,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="link"><![CDATA[{"sc_key":"link","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#1a202c","sc_tab_key":"textcolors","sc_show_in_vse":0,"sc_title":"themesetting_link","sc_order":7,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="link_button"><![CDATA[{"sc_key":"link_button","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#177ec9","sc_tab_key":"buttoncolors","sc_show_in_vse":0,"sc_title":"themesetting_link_button","sc_order":15,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="link_hover"><![CDATA[{"sc_key":"link_hover","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#177ec9","sc_tab_key":"textcolors","sc_show_in_vse":0,"sc_title":"themesetting_link_hover","sc_order":8,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="main_nav"><![CDATA[{"sc_key":"main_nav","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#1265a1","sc_tab_key":"frontendcolors","sc_show_in_vse":0,"sc_title":"themesetting_main_nav","sc_order":5,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="main_nav_font"><![CDATA[{"sc_key":"main_nav_font","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#ffffff","sc_tab_key":"frontendcolors","sc_show_in_vse":0,"sc_title":"themesetting_main_nav_font","sc_order":6,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="main_nav_tab"><![CDATA[{"sc_key":"main_nav_tab","sc_type":"Color","sc_multiple":0,"sc_content":"[{\"key\":\"\",\"value\":\"\"}]","sc_app":"core","sc_default":"#ffffff","sc_tab_key":"frontendcolors","sc_show_in_vse":0,"sc_title":"themesetting_main_nav_active","sc_order":7,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="main_nav_tab_font"><![CDATA[{"sc_key":"main_nav_tab_font","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#353c41","sc_tab_key":"frontendcolors","sc_show_in_vse":0,"sc_title":"themesetting_main_nav_active_font","sc_order":8,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="mentions"><![CDATA[{"sc_key":"mentions","sc_type":"Color","sc_multiple":0,"sc_content":"[{\"key\":\"\",\"value\":\"\"}]","sc_app":"core","sc_default":"#3d6594","sc_tab_key":"frontendcolors","sc_show_in_vse":0,"sc_title":"themesetting_mentions","sc_order":29,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="moderated"><![CDATA[{"sc_key":"moderated","sc_type":"Color","sc_multiple":0,"sc_content":"[{\"key\":\"\",\"value\":\"\"}]","sc_app":"core","sc_default":"#f7edf1","sc_tab_key":"frontendcolors","sc_show_in_vse":0,"sc_title":"themesetting_moderated","sc_order":21,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="moderated_light"><![CDATA[{"sc_key":"moderated_light","sc_type":"Color","sc_multiple":0,"sc_content":"[{\"key\":\"\",\"value\":\"\"}]","sc_app":"core","sc_default":"#fcf7f9","sc_tab_key":"frontendcolors","sc_show_in_vse":0,"sc_title":"themesetting_moderated_light","sc_order":22,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="moderated_text"><![CDATA[{"sc_key":"moderated_text","sc_type":"Color","sc_multiple":0,"sc_content":"[{\"key\":\"\",\"value\":\"\"}]","sc_app":"core","sc_default":"#880e4f","sc_tab_key":"frontendcolors","sc_show_in_vse":0,"sc_title":"themesetting_moderated_text","sc_order":23,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="moderated_text_light"><![CDATA[{"sc_key":"moderated_text_light","sc_type":"Color","sc_multiple":0,"sc_content":"[{\"key\":\"\",\"value\":\"\"}]","sc_app":"core","sc_default":"#a4768f","sc_tab_key":"frontendcolors","sc_show_in_vse":0,"sc_title":"themesetting_moderated_text_light","sc_order":24,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="normal_button"><![CDATA[{"sc_key":"normal_button","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#177ec9","sc_tab_key":"buttoncolors","sc_show_in_vse":0,"sc_title":"themesetting_normal_button","sc_order":5,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="normal_button_font"><![CDATA[{"sc_key":"normal_button_font","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#ffffff","sc_tab_key":"buttoncolors","sc_show_in_vse":0,"sc_title":"themesetting_normal_button_font","sc_order":6,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="notification_bubble"><![CDATA[{"sc_key":"notification_bubble","sc_type":"Color","sc_multiple":0,"sc_content":"[{\"key\":\"\",\"value\":\"\"}]","sc_app":"core","sc_default":"#36ab80","sc_tab_key":"frontendcolors","sc_show_in_vse":0,"sc_title":"themesetting_notification_bubble","sc_order":28,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="page_background"><![CDATA[{"sc_key":"page_background","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#edf0f4","sc_tab_key":"frontendcolors","sc_show_in_vse":0,"sc_title":"themesetting_page_background","sc_order":2,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="pagination_active"><![CDATA[{"sc_key":"pagination_active","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#3e4148","sc_tab_key":"buttoncolors","sc_show_in_vse":0,"sc_title":"themesetting_pagination_active","sc_order":14,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="post_highlight"><![CDATA[{"sc_key":"post_highlight","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#fdf5e7","sc_tab_key":"frontendcolors","sc_show_in_vse":0,"sc_title":"themesetting_post_highlight","sc_order":31,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="post_highlight_border"><![CDATA[{"sc_key":"post_highlight_border","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#81622e","sc_tab_key":"frontendcolors","sc_show_in_vse":0,"sc_title":"themesettings_post_highlight_border","sc_order":32,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="prefix"><![CDATA[{"sc_key":"prefix","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#177ec9","sc_tab_key":"frontendcolors","sc_show_in_vse":0,"sc_title":"themesetting_prefix","sc_order":18,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="price"><![CDATA[{"sc_key":"price","sc_type":"Color","sc_multiple":0,"sc_content":"[{\"key\":\"\",\"value\":\"\"}]","sc_app":"core","sc_default":"#b63f3f","sc_tab_key":"textcolors","sc_show_in_vse":0,"sc_title":"themesetting_price","sc_order":14,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="primary_button"><![CDATA[{"sc_key":"primary_button","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#177ec9","sc_tab_key":"buttoncolors","sc_show_in_vse":0,"sc_title":"themesetting_primary_button","sc_order":1,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="primary_button_font"><![CDATA[{"sc_key":"primary_button_font","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#ffffff","sc_tab_key":"buttoncolors","sc_show_in_vse":0,"sc_title":"themesetting_primary_button_font","sc_order":2,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="profile_header"><![CDATA[{"sc_key":"profile_header","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#353c41","sc_tab_key":"frontendcolors","sc_show_in_vse":0,"sc_title":"themesetting_profile_header","sc_order":15,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="rating_on"><![CDATA[{"sc_key":"rating_on","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#ff9800","sc_tab_key":"frontendcolors","sc_show_in_vse":0,"sc_title":"themesetting_rating_on","sc_order":25,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="recaptcha_theme"><![CDATA[{"sc_key":"recaptcha_theme","sc_type":"other","sc_multiple":0,"sc_content":"return new \\IPS\\Helpers\\Form\\Radio( \"core_theme_setting_title_{$row['sc_id']}\", $value, FALSE, array( 'options' => array(\r\n\t\t\t'clean'\t\t\t=> \"<img src='\" . $theme->resource( 'recaptcha\/clean.png', 'core' ) . \"' alt='clean'>\",\r\n\t\t\t'red'\t\t\t=> \"<img src='\" . $theme->resource( 'recaptcha\/red.png', 'core' ) . \"' alt='clean'>\",\r\n\t\t\t'white'\t\t\t=> \"<img src='\" . $theme->resource( 'recaptcha\/white.png', 'core' ) . \"' alt='clean'>\",\r\n\t\t\t'blackglass'\t=> \"<img src='\" . $theme->resource( 'recaptcha\/blackglass.png', 'core' ) . \"' alt='clean'>\",\r\n\t\t\t), 'parse' => 'raw' ), NULL, NULL, NULL, 'theme_setting_' . $row['sc_key'] );","sc_app":"core","sc_default":"white","sc_tab_key":"custom","sc_show_in_vse":0,"sc_title":"recaptcha_theme","sc_order":14,"sc_condition":"return \\IPS\\Settings::i()->bot_antispam_type === 'recaptcha';"}]]></themesetting>
|
||||
<themesetting key="recaptcha2_theme"><![CDATA[{"sc_key":"recaptcha2_theme","sc_type":"other","sc_multiple":0,"sc_content":"return new \\IPS\\Helpers\\Form\\Radio( \"core_theme_setting_title_{$row['sc_id']}\", $value, FALSE, array( 'options' => array(\r\n\t\t\t'light'\t\t\t=> \"<img src='\" . $theme->resource( 'recaptcha2\/light.png', 'core' ) . \"' alt='light'>\",\r\n\t\t\t'dark'\t\t\t=> \"<img src='\" . $theme->resource( 'recaptcha2\/dark.png', 'core' ) . \"' alt='dark'>\",\r\n\t\t\t), 'parse' => 'raw' ), NULL, NULL, NULL, 'theme_setting_' . $row['sc_key'] );","sc_app":"core","sc_default":"light","sc_tab_key":"custom","sc_show_in_vse":0,"sc_title":"recaptcha2_theme","sc_order":13,"sc_condition":"return \\IPS\\Settings::i()->bot_antispam_type === 'recaptcha2';"}]]></themesetting>
|
||||
<themesetting key="responsive"><![CDATA[{"sc_key":"responsive","sc_type":"YesNo","sc_multiple":0,"sc_content":"[{\"key\":\"\",\"value\":\"\"},{\"key\":\"\",\"value\":\"\"}]","sc_app":"core","sc_default":"1","sc_tab_key":"custom","sc_show_in_vse":0,"sc_title":"themesetting_responsive","sc_order":1,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="rounded_photos"><![CDATA[{"sc_key":"rounded_photos","sc_type":"YesNo","sc_multiple":0,"sc_content":"[{\"key\":\"\",\"value\":\"\"},{\"key\":\"\",\"value\":\"\"}]","sc_app":"core","sc_default":"1","sc_tab_key":"custom","sc_show_in_vse":0,"sc_title":"themesetting_rounded_photos","sc_order":4,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="secondary_title"><![CDATA[{"sc_key":"secondary_title","sc_type":"Color","sc_multiple":0,"sc_content":"[{\"key\":\"\",\"value\":\"\"}]","sc_app":"core","sc_default":"#ebedf0","sc_tab_key":"textcolors","sc_show_in_vse":0,"sc_title":"themesetting_secondary_title","sc_order":11,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="secondary_title_font"><![CDATA[{"sc_key":"secondary_title_font","sc_type":"Color","sc_multiple":0,"sc_content":"[{\"key\":\"\",\"value\":\"\"}]","sc_app":"core","sc_default":"#828e99","sc_tab_key":"textcolors","sc_show_in_vse":0,"sc_title":"themesetting_secondary_title_font","sc_order":12,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="section_title"><![CDATA[{"sc_key":"section_title","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#ffffff","sc_tab_key":"textcolors","sc_show_in_vse":0,"sc_title":"themesetting_section_title","sc_order":9,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="section_title_font"><![CDATA[{"sc_key":"section_title_font","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#1a202c","sc_tab_key":"textcolors","sc_show_in_vse":0,"sc_title":"themesetting_section_title_font","sc_order":10,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="selected"><![CDATA[{"sc_key":"selected","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#ebf4f9","sc_tab_key":"frontendcolors","sc_show_in_vse":0,"sc_title":"themesetting_selected","sc_order":13,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="selected_border"><![CDATA[{"sc_key":"selected_border","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#177ec9","sc_tab_key":"frontendcolors","sc_show_in_vse":0,"sc_title":"themesetting_selected_border","sc_order":14,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="font_3x_large"><![CDATA[{"sc_key":"font_3x_large","sc_type":"Number","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"30","sc_tab_key":"typescale","sc_show_in_vse":0,"sc_title":"font_3x_large","sc_order":8,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="font_2x_large"><![CDATA[{"sc_key":"font_2x_large","sc_type":"Number","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"24","sc_tab_key":"typescale","sc_show_in_vse":0,"sc_title":"font_2x_large","sc_order":7,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="brand_primary"><![CDATA[{"sc_key":"brand_primary","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#177ec9","sc_tab_key":"frontendcolors","sc_show_in_vse":0,"sc_title":"themesetting_brand_primary","sc_order":1,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="active_input_border"><![CDATA[{"sc_key":"active_input_border","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#3480bb","sc_tab_key":"frontendcolors","sc_show_in_vse":0,"sc_title":"themesetting_active_input_border","sc_order":41,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="tag_font"><![CDATA[{"sc_key":"tag_font","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#9c4221","sc_tab_key":"textcolors","sc_show_in_vse":0,"sc_title":"themesetting_tag_font","sc_order":15,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="sidebar_position"><![CDATA[{"sc_key":"sidebar_position","sc_type":"Select","sc_multiple":0,"sc_content":"[{\"key\":\"left\",\"value\":\"Left\"},{\"key\":\"right\",\"value\":\"Right\"}]","sc_app":"core","sc_default":"right","sc_tab_key":"custom","sc_show_in_vse":0,"sc_title":"themesetting_sidebar_position","sc_order":6,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="sidebar_responsive"><![CDATA[{"sc_key":"sidebar_responsive","sc_type":"YesNo","sc_multiple":0,"sc_content":"[{\"key\":\"\",\"value\":\"\"}]","sc_app":"core","sc_default":"1","sc_tab_key":"custom","sc_show_in_vse":1,"sc_title":"themesetting_sidebar_responsive","sc_order":7,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="social_links"><![CDATA[{"sc_key":"social_links","sc_type":"Radio","sc_multiple":0,"sc_content":"[{\"key\":\"header\",\"value\":\"themesetting_header\"},{\"key\":\"footer\",\"value\":\"themesetting_footer\"}]","sc_app":"core","sc_default":"footer","sc_tab_key":"custom","sc_show_in_vse":1,"sc_title":"themesetting_social_links_pos","sc_order":5,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="tab_background"><![CDATA[{"sc_key":"tab_background","sc_type":"Color","sc_multiple":0,"sc_content":"[{\"key\":\"\",\"value\":\"\"}]","sc_app":"core","sc_default":"#4a5568","sc_tab_key":"frontendcolors","sc_show_in_vse":0,"sc_title":"themesetting_tabs_background","sc_order":30,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="tag"><![CDATA[{"sc_key":"tag","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#fff4df","sc_tab_key":"frontendcolors","sc_show_in_vse":0,"sc_title":"themesetting_tag","sc_order":16,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="tag_font"><![CDATA[{"sc_key":"tag_font","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#9c4221","sc_tab_key":"frontendcolors","sc_show_in_vse":0,"sc_title":"themesetting_tag_font","sc_order":17,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="text_color"><![CDATA[{"sc_key":"text_color","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#353c41","sc_tab_key":"textcolors","sc_show_in_vse":0,"sc_title":"themesetting_text_color","sc_order":3,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="text_dark"><![CDATA[{"sc_key":"text_dark","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#000000","sc_tab_key":"textcolors","sc_show_in_vse":0,"sc_title":"themesetting_dark_text_color","sc_order":4,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="text_light"><![CDATA[{"sc_key":"text_light","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#718096","sc_tab_key":"textcolors","sc_show_in_vse":0,"sc_title":"themesetting_text_light","sc_order":6,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="text_very_light"><![CDATA[{"sc_key":"text_very_light","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#ffffff","sc_tab_key":"textcolors","sc_show_in_vse":1,"sc_title":"themesetting_text_very_light","sc_order":5,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="timeline_color"><![CDATA[{"sc_key":"timeline_color","sc_type":"Color","sc_multiple":0,"sc_content":"[{\"key\":\"\",\"value\":\"\"}]","sc_app":"core","sc_default":"#2d3748","sc_tab_key":"frontendcolors","sc_show_in_vse":0,"sc_title":"activity_stream_timeline","sc_order":26,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="very_light_button"><![CDATA[{"sc_key":"very_light_button","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#ffffff","sc_tab_key":"buttoncolors","sc_show_in_vse":0,"sc_title":"themesetting_very_light_button","sc_order":11,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="very_light_button_font"><![CDATA[{"sc_key":"very_light_button_font","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#0e4c79","sc_tab_key":"buttoncolors","sc_show_in_vse":0,"sc_title":"themesetting_very_light_button_font","sc_order":12,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="widget_title_bar"><![CDATA[{"sc_key":"widget_title_bar","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#ffffff","sc_tab_key":"frontendcolors","sc_show_in_vse":0,"sc_title":"themesetting_widget_title_bar","sc_order":19,"sc_condition":null}]]></themesetting>
|
||||
<themesetting key="widget_title_font"><![CDATA[{"sc_key":"widget_title_font","sc_type":"Color","sc_multiple":0,"sc_content":"[]","sc_app":"core","sc_default":"#1a202c","sc_tab_key":"frontendcolors","sc_show_in_vse":0,"sc_title":"themesetting_widget_font","sc_order":20,"sc_condition":null}]]></themesetting>
|
||||
</build>
|
||||
@@ -0,0 +1,163 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Achievement Action 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/
|
||||
{subpackage}
|
||||
* @since {date}
|
||||
*/
|
||||
|
||||
namespace IPS\{app}\extensions\core\AchievementAction;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Achievement Action Extension
|
||||
*/
|
||||
class _{class} extends \IPS\core\Achievements\Actions\AbstractAchievementAction // NOTE: Other classes exist to provided bases for common situations, like where node-based filters will be required
|
||||
{
|
||||
/**
|
||||
* Get filter form elements
|
||||
*
|
||||
* @param array|NULL $filters Current filter values (if editing)
|
||||
* @param \IPS\Http\Url $url The URL the form is being shown on
|
||||
* @return array
|
||||
*/
|
||||
public function filters( ?array $filters, \IPS\Http\Url $url ): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Format filter form values
|
||||
*
|
||||
* @param array $values The values from the form
|
||||
* @return array
|
||||
*/
|
||||
public function formatFilterValues( array $values ): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Work out if the filters applies for a given action
|
||||
*
|
||||
* Important note for milestones: consider the context. This method is called by \IPS\Member::achievementAction(). If your code
|
||||
* calls that BEFORE making its change in the database (or there is read/write separation), you will need to add
|
||||
* 1 to the value being considered for milestones
|
||||
*
|
||||
* @param \IPS\Member $subject The subject member
|
||||
* @param array $filters The value returned by formatFilterValues()
|
||||
* @param mixed $extra Any additional information about what is happening (e.g. if a post is being made: the post object)
|
||||
* @return bool
|
||||
*/
|
||||
public function filtersMatch( \IPS\Member $subject, array $filters, $extra = NULL ): bool
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the labels for the people this action might give awards to
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
// You don't need to implement this if your action only gives points to the subject
|
||||
// public function awardOptions(): array
|
||||
// {
|
||||
// return [
|
||||
// 'subject' => 'achievement_filter_{class}_receiver',
|
||||
// 'other' => 'achievement_filter_{class}_giver'
|
||||
// ];
|
||||
// }
|
||||
|
||||
/**
|
||||
* Get the "other" people we need to award =stuff to
|
||||
*
|
||||
* @param mixed $extra Any additional information about what is happening (e.g. if a post is being made: the post object)
|
||||
* @return array
|
||||
*/
|
||||
// You don't need to implement this if your action only gives points to the subject
|
||||
// public function awardOther( $extra = NULL ): array
|
||||
// {
|
||||
// return [ \IPS\Member::loggedIn() ];
|
||||
// }
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @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)
|
||||
* @return string
|
||||
*/
|
||||
public function identifier( \IPS\Member $subject, $extra = NULL ): string
|
||||
{
|
||||
return (string) $extra->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a description for this action to show in the log
|
||||
*
|
||||
* @param string $identifier The identifier as returned by identifier()
|
||||
* @param array $actor If the member was the "subject", "other", or both
|
||||
* @return string
|
||||
*/
|
||||
public function logRow( string $identifier, array $actor ): string
|
||||
{
|
||||
return "{class}";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get "description" for rule
|
||||
*
|
||||
* @param \IPS\core\Achievements\Rule $rule The rule
|
||||
* @return string|NULL
|
||||
*/
|
||||
public function ruleDescription( \IPS\core\Achievements\Rule $rule ): ?string
|
||||
{
|
||||
return "{class}";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get rebuild data
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
static public function rebuildData()
|
||||
{
|
||||
// This method returns an array of tables that this extension uses to award achievements, so for example
|
||||
// the follow extension uses 'core_follow'.
|
||||
// We also need to know the primary key for this table. It should be unique but does not need to be an integer
|
||||
// The date is optional but useful if available for those that want to partially rebuild.
|
||||
// Where shouldn't attempt to limit based on filters or milestones, but just remove data that you don't need to
|
||||
// look at, such as banned members, archived items and so on. You can return an empty array if you do not need
|
||||
// a where statement.
|
||||
//return [ [
|
||||
// 'table' => 'table_name',
|
||||
// 'pkey' => 'field_id',
|
||||
// 'date' => 'field_date',
|
||||
// 'where' => [ [ 'banned != 1' ] ],
|
||||
//] ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the rebuild row
|
||||
*
|
||||
* @param array $row Row from database
|
||||
* @param array $data Data collected when starting rebuild [table, pkey...]
|
||||
* @return void
|
||||
*/
|
||||
public static function rebuildRow( $row, $data )
|
||||
{
|
||||
// This method runs the achievementAction on the table row from the table (or tables) you specified in rebuildData()
|
||||
// You are welcome to load any classes, etc you need here.
|
||||
//IPS\Member::loggedIn()->achievementAction( '{app}', '{class}', $row['field_id'] ), \IPS\DateTime::ts( $row['field_date'] ) );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -24,21 +24,72 @@ if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
class _{class}
|
||||
{
|
||||
/**
|
||||
* Get configuration
|
||||
* Get fields for configuration
|
||||
*
|
||||
* @param \IPS\Member $member The member
|
||||
* @param \IPS\Member|null $member The member (to take out any notification types a given member will never see) or NULL if this is for the ACP
|
||||
* @return array
|
||||
*/
|
||||
public function getConfiguration( $member )
|
||||
public static function configurationOptions( \IPS\Member $member = NULL )
|
||||
{
|
||||
// Basically just return a list of the keys for the types of notification your app will send
|
||||
// keys can be anything you want. You can specify what should be the default value and any disabled values (acceptable values are "email" and "inline")
|
||||
// For each key, create a language string "notifications__<key>" which is what will display in the user's Notification Options screen
|
||||
// Return an array defining each notification type, including the form elements necessary to allow its configuration
|
||||
|
||||
return array(
|
||||
'key' => array( 'default' => array( 'inline', 'push' ), 'disabled' => array() ),
|
||||
'setting_key' => array(
|
||||
'type' => 'custom',
|
||||
'adminCanSetDefault'=> TRUE,
|
||||
'field' => \IPS\Helpers\Form\CheckboxSet( 'setting_key', $defaultValue, FALSE, /*...*/ ),
|
||||
'admin_lang' => array(
|
||||
'header' => 'header_lang_key',
|
||||
'title' => 'header_lang_title',
|
||||
),
|
||||
),
|
||||
'other_setting_key' => array(
|
||||
'type' => 'custom',
|
||||
'adminCanSetDefault'=> FALSE,
|
||||
'field' => $formField,
|
||||
),
|
||||
'separator1' => array(
|
||||
'type' => 'separator',
|
||||
),
|
||||
//...
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save "extra" value
|
||||
*
|
||||
* @param \IPS\Member|NULL $member The member or NULL if this is the admin setting defaults
|
||||
* @param string $key The key
|
||||
* @param bool $value The value
|
||||
* @return void
|
||||
*/
|
||||
public static function saveExtra( ?\IPS\Member $member, $key, $value )
|
||||
{
|
||||
// You can perform extra processing here to save values in a specific manner if needed
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable all "extra" values for a particular type
|
||||
*
|
||||
* @param \IPS\Member|NULL $member The member or NULL if this is the admin setting defaults
|
||||
* @param string $method The method type
|
||||
* @return void
|
||||
*/
|
||||
public static function disableExtra( ?\IPS\Member $member, $method )
|
||||
{
|
||||
// You can disable extra values for a given type, such as if a setting means the notification preference is irrelevant
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset "extra" value to the default for all accounts
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function resetExtra()
|
||||
{
|
||||
// Any extra processing you may need to perform when resetting all members to default notification options.
|
||||
// Typically you won't have to do anything here unless you have custom settings
|
||||
}
|
||||
|
||||
// For each type of notification you need a method like this which controls what will be displayed when the user clicks on the notification icon in the header:
|
||||
// Note that for each type of notification you must *also* create email templates. See documentation for details: https://remoteservices.invisionpower.com/docs/devdocs-notifications
|
||||
@@ -47,6 +98,7 @@ class _{class}
|
||||
* Parse notification: key
|
||||
*
|
||||
* @param \IPS\Notification\Inline $notification The notification
|
||||
* @param bool $htmlEscape TRUE to escape HTML in title
|
||||
* @return array
|
||||
* @code
|
||||
return array(
|
||||
@@ -59,7 +111,7 @@ class _{class}
|
||||
);
|
||||
* @endcode
|
||||
*/
|
||||
public function parse_key( \IPS\Notification\Inline $notification )
|
||||
public function parse_key( \IPS\Notification\Inline $notification, $htmlEscape=TRUE )
|
||||
{
|
||||
return array(
|
||||
'title' => "Mark has replied to A Topic", // The notification title
|
||||
|
||||
@@ -43,18 +43,6 @@ class _{class}
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Code to execute when other applications are uninstalled
|
||||
*
|
||||
* @param string $application Application directory
|
||||
* @return void
|
||||
* @deprecated This is here for backwards-compatibility - all new code should go in onOtherUninstall
|
||||
*/
|
||||
public function onOtherAppUninstall( $application )
|
||||
{
|
||||
return $this->onOtherUninstall( $application );
|
||||
}
|
||||
|
||||
/**
|
||||
* Code to execute when other applications or plugins are uninstalled
|
||||
*
|
||||
|
||||
@@ -243,15 +243,15 @@
|
||||
{{if $warning->expire_date}}
|
||||
{{if $warning->expire_date < time()}}
|
||||
{{if $warning->expire_date == -1}}
|
||||
{$email->language->addToStack("warn_action_points_never_expire", FALSE, array( 'sprintf' => array( $warning->points ) ) )}
|
||||
{$email->language->addToStack("warn_action_points_never_expire", FALSE, array( 'pluralize' => array( $warning->points ) ) )}
|
||||
{{else}}
|
||||
{$email->language->addToStack("warn_action_points_expired", FALSE, array( 'sprintf' => array( $warning->points, \IPS\DateTime::ts( $warning->expire_date ) ) ) )}
|
||||
{$email->language->addToStack("warn_action_points_expired", FALSE, array( 'pluralize' => array( $warning->points ), 'sprintf' => array( \IPS\DateTime::ts( $warning->expire_date ) ) ) )}
|
||||
{{endif}}
|
||||
{{else}}
|
||||
{$email->language->addToStack("warn_action_points_expire", FALSE, array( 'sprintf' => array( $warning->points, \IPS\DateTime::ts( $warning->expire_date ) ) ) )}
|
||||
{$email->language->addToStack("warn_action_points_expire", FALSE, array( 'pluralize' => array( $warning->points ), 'sprintf' => array( \IPS\DateTime::ts( $warning->expire_date ) ) ) )}
|
||||
{{endif}}
|
||||
{{else}}
|
||||
{$email->language->addToStack("warn_action_points", FALSE, array( 'sprintf' => array( $warning->points ) ) )}
|
||||
{$email->language->addToStack("warn_action_points", FALSE, array( 'pluralize' => array( $warning->points ) ) )}
|
||||
{{endif}}
|
||||
</li>
|
||||
{{endif}}
|
||||
@@ -319,15 +319,15 @@
|
||||
{{if $warning->expire_date}}
|
||||
{{if $warning->expire_date < time()}}
|
||||
{{if $warning->expire_date == -1}}
|
||||
{$email->language->addToStack("warn_action_points_never_expire", FALSE, array( 'htmlsprintf' => array( $warning->points ) ) )}
|
||||
{$email->language->addToStack("warn_action_points_never_expire", FALSE, array( 'pluralize' => array( $warning->points ) ) )}
|
||||
{{else}}
|
||||
{$email->language->addToStack("warn_action_points_expired", FALSE, array( 'htmlsprintf' => array( $warning->points, \IPS\DateTime::ts( $warning->expire_date ) ) ) )}
|
||||
{$email->language->addToStack("warn_action_points_expired", FALSE, array( 'pluralize' => array( $warning->points ), 'htmlsprintf' => array( \IPS\DateTime::ts( $warning->expire_date ) ) ) )}
|
||||
{{endif}}
|
||||
{{else}}
|
||||
{$email->language->addToStack("warn_action_points_expire", FALSE, array( 'htmlsprintf' => array( $warning->points, \IPS\DateTime::ts( $warning->expire_date ) ) ) )}
|
||||
{$email->language->addToStack("warn_action_points_expire", FALSE, array( 'pluralize' => array( $warning->points ), 'htmlsprintf' => array( \IPS\DateTime::ts( $warning->expire_date ) ) ) )}
|
||||
{{endif}}
|
||||
{{else}}
|
||||
{$email->language->addToStack("warn_action_points", FALSE, array( 'htmlsprintf' => array( $warning->points ) ) )}
|
||||
{$email->language->addToStack("warn_action_points", FALSE, array( 'pluralize' => array( $warning->points ) ) )}
|
||||
{{endif}}
|
||||
{{endif}}
|
||||
{{if $warning->mq}}
|
||||
@@ -441,6 +441,20 @@
|
||||
|
||||
{$email->language->addToStack("email_url_to_message", FALSE)}: {$message->url()}
|
||||
|
||||
-- {setting="board_name"}]]></template_content_plaintext><template_pinned>0</template_pinned></template><template><template_app>core</template_app><template_name>notification_my_solution</template_name><template_content_html><![CDATA[
|
||||
<br />
|
||||
|
||||
{$email->language->addToStack("mail_your_post_is_solution", FALSE, array( 'htmlsprintf' => array( $comment->url('find'), $content->url(), $content->mapped('title') ) ) )}
|
||||
|
||||
<br />
|
||||
<br />
|
||||
|
||||
{$content->emailContent( $email, 'html' )|raw}
|
||||
<br /><br />
|
||||
<em style='color: #8c8c8c'>— {setting="board_name"}</em>]]></template_content_html><template_data>$content, $comment, $solver, $email</template_data><template_content_plaintext><![CDATA[
|
||||
|
||||
{$email->language->addToStack("mail_your_post_is_solution", FALSE, array( 'htmlsprintf' => array( $comment->url('find'), $content->url(), $content->mapped('title') ) ) )}
|
||||
|
||||
-- {setting="board_name"}]]></template_content_plaintext><template_pinned>0</template_pinned></template><template><template_app>core</template_app><template_name>notification_unapproved_content</template_name><template_content_html><![CDATA[
|
||||
{{if $content->author()->member_id}}
|
||||
{$email->language->addToStack("email_new_content_unapproved", FALSE, array( 'sprintf' => array( $content->author()->url(), $content->author()->name, $content->indefiniteArticle( $email->language ) ) ) )} <a href='{$content->url()}'>{{if $content instanceof \IPS\Content\Comment OR $content instanceof \IPS\Content\Review}}{$content->item()->mapped('title')}{{else}}{$content->mapped('title')}{{endif}}</a>
|
||||
@@ -569,7 +583,7 @@
|
||||
<a href='{url="app=core&module=system&controller=lostpass" seoTemplate="lostpassword" base="front"}' style="color: #ffffff; font-family: 'Helvetica Neue', helvetica, sans-serif; text-decoration: none; font-size: 14px; background: {setting="email_color"}; line-height: 32px; padding: 0 10px; display: inline-block; border-radius: 3px;">{$email->language->addToStack("email_reset_password", FALSE)}</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>]]></template_content_html><template_data>$member, $location, $unlockTime=NULL, $email</template_data><template_content_plaintext><![CDATA[{$email->language->addToStack("email_account_locked", FALSE, array( 'htmlsprintf' => array( \IPS\Settings::i()->ipb_bruteforce_attempts, $location ) ) )}
|
||||
</table>]]></template_content_html><template_data>$member, $location, $unlockTime=NULL, $email=NULL</template_data><template_content_plaintext><![CDATA[{$email->language->addToStack("email_account_locked", FALSE, array( 'htmlsprintf' => array( \IPS\Settings::i()->ipb_bruteforce_attempts, $location ) ) )}
|
||||
|
||||
{$email->language->addToStack("email_account_locked_change_password")}
|
||||
{{if $unlockTime}}
|
||||
@@ -580,7 +594,14 @@
|
||||
|
||||
{$email->language->addToStack("email_secure_account", FALSE)}: {url="app=core&module=system&controller=settings&do=secureAccount" seoTemplate="settings_secure" base="front" plain="true"}
|
||||
{$email->language->addToStack("or", FALSE)}
|
||||
{$email->language->addToStack("email_reset_password", FALSE)}: {url="app=core&module=system&controller=lostpass" seoTemplate="lostpassword" base="front" plain="true"}]]></template_content_plaintext><template_pinned>0</template_pinned></template><template><template_app>core</template_app><template_name>acp_notification_License</template_name><template_content_html><![CDATA[
|
||||
{$email->language->addToStack("email_reset_password", FALSE)}: {url="app=core&module=system&controller=lostpass" seoTemplate="lostpassword" base="front" plain="true"}]]></template_content_plaintext><template_pinned>0</template_pinned></template><template><template_app>core</template_app><template_name>notification_new_rank</template_name><template_content_html><![CDATA[<br />
|
||||
|
||||
{$email->language->addToStack( "notification__new_rank", FALSE, array( 'sprintf' => array( $email->language->addToStack( "core_member_rank_" . $rank->id ) ) ) )}
|
||||
|
||||
<br /><br />
|
||||
<em style='color: #8c8c8c'>— {setting="board_name"}</em>]]></template_content_html><template_data>$rank, $email</template_data><template_content_plaintext><![CDATA[{$email->language->addToStack( "notification__new_rank", FALSE, array( 'sprintf' => array( $email->language->addToStack( "core_member_rank_" . $rank->id ) ) ) )}
|
||||
|
||||
-- {setting="board_name"}]]></template_content_plaintext><template_pinned>0</template_pinned></template><template><template_app>core</template_app><template_name>acp_notification_License</template_name><template_content_html><![CDATA[
|
||||
<br />
|
||||
|
||||
{{if $notification->extra === 'missing' or $notification->extra === 'url'}}
|
||||
@@ -844,7 +865,18 @@
|
||||
<br />
|
||||
</td>
|
||||
</tr>
|
||||
{{endif}}]]></template_content_html><template_data>$key, $member, $email</template_data><template_content_plaintext><![CDATA[{$email->language->addToStack("unsubscribe_blurb", FALSE)} {$email->language->addToStack( 'adjust_notification_prefs', FALSE )}: {url="app=core&module=overview&controller=notifications&do=settings&type={$key}" base="admin_redirect" plain="true"}]]></template_content_plaintext><template_pinned>0</template_pinned></template><template><template_app>core</template_app><template_name>onboard_reminder</template_name><template_content_html><![CDATA[
|
||||
{{endif}}]]></template_content_html><template_data>$key, $member, $email</template_data><template_content_plaintext><![CDATA[{$email->language->addToStack("unsubscribe_blurb", FALSE)} {$email->language->addToStack( 'adjust_notification_prefs', FALSE )}: {url="app=core&module=overview&controller=notifications&do=settings&type={$key}" base="admin_redirect" plain="true"}]]></template_content_plaintext><template_pinned>0</template_pinned></template><template><template_app>core</template_app><template_name>notification_approved_content</template_name><template_content_html><![CDATA[
|
||||
{$email->language->addToStack("email_approved_content", FALSE, array( 'sprintf' => array( $content->definiteArticle( $email->language ) ) ) )}
|
||||
|
||||
<br />
|
||||
<br />
|
||||
|
||||
{$content->emailContent( $email, 'html' )|raw}
|
||||
<br /><br />
|
||||
<em style='color: #8c8c8c'>— {setting="board_name"}</em>]]></template_content_html><template_data>$content, $email</template_data><template_content_plaintext><![CDATA[
|
||||
{$email->language->addToStack("email_approved_content", FALSE, array( 'sprintf' => array( $content->definiteArticle( $email->language ) ) ) )}
|
||||
|
||||
-- {setting="board_name"}]]></template_content_plaintext><template_pinned>0</template_pinned></template><template><template_app>core</template_app><template_name>onboard_reminder</template_name><template_content_html><![CDATA[
|
||||
{$email->language->addToStack("onboard_welcome_message_email", FALSE)}
|
||||
<br />
|
||||
<a href='{url="app=core&module=overview&controller=onboard" base="admin"}' style="color: #ffffff; font-family: 'Helvetica Neue', helvetica, sans-serif; text-decoration: none; font-size: 14px; background: {setting="email_color"}; line-height: 32px; padding: 0 10px; display: inline-block; border-radius: 3px;">{$email->language->addToStack("onboard_finish_setup", FALSE)}</a>
|
||||
@@ -1109,6 +1141,20 @@
|
||||
=====
|
||||
|
||||
|
||||
-- {setting="board_name"}]]></template_content_plaintext><template_pinned>0</template_pinned></template><template><template_app>core</template_app><template_name>notification_mine_solved</template_name><template_content_html><![CDATA[
|
||||
<br />
|
||||
|
||||
{$email->language->addToStack("mail_your_content_is_solved", FALSE, array( 'htmlsprintf' => array( $comment->url('find'), $content->url(), $content->mapped('title'), $content->definiteArticle( $email->language ) ) ) )}
|
||||
|
||||
<br />
|
||||
<br />
|
||||
|
||||
{$content->emailContent( $email, 'html' )|raw}
|
||||
<br /><br />
|
||||
<em style='color: #8c8c8c'>— {setting="board_name"}</em>]]></template_content_html><template_data>$content, $comment, $solver, $email</template_data><template_content_plaintext><![CDATA[
|
||||
|
||||
{$email->language->addToStack("mail_your_content_is_solved", FALSE, array( 'htmlsprintf' => array( $comment->url('find'), $content->url(), $content->mapped('title'), $content->definiteArticle( $email->language ) ) ) )}
|
||||
|
||||
-- {setting="board_name"}]]></template_content_plaintext><template_pinned>0</template_pinned></template><template><template_app>core</template_app><template_name>lost_password_init</template_name><template_content_html><![CDATA[
|
||||
{$email->language->addToStack("email_lost_pass", FALSE)}
|
||||
<br /><br />
|
||||
@@ -1125,20 +1171,6 @@
|
||||
{$email->language->addToStack("email_reset_password", FALSE)}: {url="app=core&module=system&controller=lostpass&do=validate&vid={$vid}&mid={$member->member_id}" seoTemplate="lostpassword" plain="true" base="front"}
|
||||
=====
|
||||
|
||||
-- {setting="board_name"}]]></template_content_plaintext><template_pinned>0</template_pinned></template><template><template_app>core</template_app><template_name>notification_best_answer</template_name><template_content_html><![CDATA[
|
||||
{{$item = ( $comment instanceof \IPS\Content\Item ) ? $comment : $comment->item();}}
|
||||
|
||||
{$email->language->addToStack("email_best_answer", FALSE, array( 'sprintf' => array( $comment->indefiniteArticle( $email->language ) ) ) )} <a href='{$item->url()}'>{$item->mapped('title')}</a>
|
||||
|
||||
<br />
|
||||
<br />
|
||||
{$comment->emailContent( $email, 'html' )|raw}
|
||||
<br /><br />
|
||||
<em style='color: #8c8c8c'>— {setting="board_name"}</em>]]></template_content_html><template_data>$comment, $email</template_data><template_content_plaintext><![CDATA[
|
||||
{{$item = ( $comment instanceof \IPS\Content\Item ) ? $comment : $comment->item();}}{$email->language->addToStack("email_best_answer", FALSE, array( 'sprintf' => array( $comment->indefiniteArticle( $email->language ) ) ) )} {$item->mapped('title')}
|
||||
|
||||
{$comment->emailContent( $email, 'plaintext' )|raw}
|
||||
|
||||
-- {setting="board_name"}]]></template_content_plaintext><template_pinned>0</template_pinned></template><template><template_app>core</template_app><template_name>admin_reg</template_name><template_content_html><![CDATA[
|
||||
{expression="$email->language->addToStack( 'email_admin_reg', FALSE, array( 'sprintf' => array( \IPS\Settings::i()->board_name ) ) )"}
|
||||
<br />
|
||||
@@ -1315,9 +1347,27 @@
|
||||
}
|
||||
|
||||
.ipsImage {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
max-width: 100% !important;
|
||||
height: auto !important;
|
||||
}
|
||||
|
||||
/* Attachment styles for rich text */
|
||||
.ipsAttachLink_image,
|
||||
.ipsAttachLink {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
html[dir="ltr"] .ipsAttachLink_image.ipsAttachLink_right,
|
||||
html[dir="ltr"] .ipsAttachLink.ipsAttachLink_right,
|
||||
html[dir="rtl"] .ipsAttachLink_image.ipsAttachLink_left,
|
||||
html[dir="rtl"] .ipsAttachLink.ipsAttachLink_left {
|
||||
margin-left: 30px;
|
||||
}
|
||||
html[dir="ltr"] .ipsAttachLink_image.ipsAttachLink_left,
|
||||
html[dir="ltr"] .ipsAttachLink.ipsAttachLink_left,
|
||||
html[dir="rtl"] .ipsAttachLink_image.ipsAttachLink_right,
|
||||
html[dir="rtl"] .ipsAttachLink.ipsAttachLink_right {
|
||||
margin-right: 30px;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 480px) {
|
||||
@@ -1419,10 +1469,10 @@
|
||||
<tr>
|
||||
<td dir='{dir}'><img src='{setting="base_url"}applications/core/interface/email/spacer.png' width='1' height='1' alt=''></td>
|
||||
<td dir='{dir}' width='800' id='main' bgcolor='#ffffff' style='border-top: 10px solid {setting="email_color"}; line-height: 1.5;'>
|
||||
<table width='100%' cellpadding='20'>
|
||||
<table width='100%' cellpadding='20' style="table-layout: fixed;">
|
||||
{$email->getAdvertisement()|raw}
|
||||
<tr>
|
||||
<td dir='{dir}' style="font-family: 'Helvetica Neue', helvetica, sans-serif; font-size: 15px; color: #333333; line-height: 21px">
|
||||
<td dir='{dir}' style="font-family: 'Helvetica Neue', helvetica, sans-serif; font-size: 15px; color: #333333; line-height: 21px; overflow-wrap: break-word;">
|
||||
{{if $introText}}
|
||||
<h1 style="font-family: 'Helvetica Neue', helvetica, sans-serif; color: {setting="email_color"} !important; font-size: 28px; font-weight: 500 !important;"><center>{$introText}</center></h1>
|
||||
<br>
|
||||
@@ -1588,7 +1638,7 @@
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
]]></template_content_html><template_data>$subject, $member, $content, $unsubscribe, $placeholderRecipient=FALSE, $introText='', $email, $ourPicks=NULL</template_data><template_content_plaintext><![CDATA[
|
||||
]]></template_content_html><template_data>$subject, $member, $content, $unsubscribe, $placeholderRecipient=FALSE, $introText='', $email=NULL, $ourPicks=NULL</template_data><template_content_plaintext><![CDATA[
|
||||
{$email->getAdvertisement('plaintext')|raw}
|
||||
{{if $member->member_id }}{$email->language->addToStack("email_greeting_member", FALSE, array( 'htmlsprintf' => array( $member->name ) ) )}{{elseif $placeholderRecipient}}{$email->language->addToStack("email_greeting_member", FALSE, array( 'htmlsprintf' => array( '*|member_name|*' ) ) )}{{endif}}
|
||||
{$content|raw}
|
||||
@@ -1664,6 +1714,31 @@
|
||||
|
||||
{$email->language->addToStack("set_password", FALSE)}: {url="app=core&module=system&controller=register&do=setPassword&mid={$member->member_id}&passkey={$key}" base="front" seoTemplate="register"}
|
||||
|
||||
-- {setting="board_name"}]]></template_content_plaintext><template_pinned>0</template_pinned></template><template><template_app>core</template_app><template_name>notification_new_recognize</template_name><template_content_html><![CDATA[<br />
|
||||
{$email->language->addToStack('notification_new_recognized_mail', NULL, [ 'sprintf' => [ $recognize->content()->url() ] ] )}
|
||||
{{if $recognize->message}}
|
||||
<p style='border-bottom: 1px solid #e0e0e0;border-top: 1px solid #e0e0e0; padding: 10px 0px'>
|
||||
<strong><em>{$recognize->message}</em></strong>
|
||||
{{if $awardedBy = $recognize->awardedBy()}}
|
||||
<br>- <a href="{$awardedBy->url()}">{$awardedBy->name}</a>
|
||||
{{endif}}
|
||||
</p>
|
||||
{{endif}}
|
||||
{{if $recognize->points}}
|
||||
<p>{$email->language->addToStack("recognize_points_awarded", NULL, [ 'sprintf' => [ $recognize->points ] ] )}</p>
|
||||
{{endif}}
|
||||
{{if $badge = $recognize->badge()}}
|
||||
{$email->language->addToStack("recognize_badge_awarded", NULL, [ 'sprintf' => [ $badge->_title ] ] )}
|
||||
<br><br>
|
||||
{$email->language->addToStack("notification_email_check_it_out")}
|
||||
<br>
|
||||
<br><strong>{$badge->_title}</strong>
|
||||
<br>
|
||||
<img src="{file="$badge->image" extension="core_Badges"}">
|
||||
{{endif}}
|
||||
<br /><br />
|
||||
<em style='color: #8c8c8c'>— {setting="board_name"}</em>]]></template_content_html><template_data>$badge, $email</template_data><template_content_plaintext><![CDATA[{$email->language->addToStack("notification__new_recognized")}
|
||||
|
||||
-- {setting="board_name"}]]></template_content_plaintext><template_pinned>0</template_pinned></template><template><template_app>core</template_app><template_name>notification_member_follow</template_name><template_content_html><![CDATA[{$email->language->addToStack("notification__member_follow", FALSE, array( 'sprintf' => array( $member->name ) ) )}
|
||||
|
||||
<br />
|
||||
@@ -1841,6 +1916,19 @@
|
||||
|
||||
{$comment->emailContent( $email, 'plaintext' )|raw}
|
||||
|
||||
-- {setting="board_name"}]]></template_content_plaintext><template_pinned>0</template_pinned></template><template><template_app>core</template_app><template_name>notification_new_badge</template_name><template_content_html><![CDATA[<br />
|
||||
|
||||
{$email->language->addToStack("notification__new_badge")}
|
||||
<br><br>
|
||||
{$email->language->addToStack("notification_email_check_it_out")}
|
||||
<br>
|
||||
<br><strong>{$badge->_title}</strong>
|
||||
<br>
|
||||
<img src="{file="$badge->image" extension="core_Badges"}">
|
||||
|
||||
<br /><br />
|
||||
<em style='color: #8c8c8c'>— {setting="board_name"}</em>]]></template_content_html><template_data>$badge, $email</template_data><template_content_plaintext><![CDATA[{$email->language->addToStack("notification__new_badge")}
|
||||
|
||||
-- {setting="board_name"}]]></template_content_plaintext><template_pinned>0</template_pinned></template><template><template_app>core</template_app><template_name>notification_profile_reply</template_name><template_content_html><![CDATA[
|
||||
{{$item = $comment->item();}}
|
||||
|
||||
@@ -2058,7 +2146,7 @@
|
||||
{$content|raw}
|
||||
</body>
|
||||
</html>
|
||||
]]></template_content_html><template_data>$subject, $member, $content, $unsubscribe, $placeholderRecipient=FALSE, $introText='', $email, $ourPicks=NULL</template_data><template_content_plaintext>{$content|raw}</template_content_plaintext><template_pinned>0</template_pinned></template><template><template_app>core</template_app><template_name>digest</template_name><template_content_html><![CDATA[{$email->language->addToStack("digest_$frequency", FALSE)}
|
||||
]]></template_content_html><template_data>$subject, $member, $content, $unsubscribe, $placeholderRecipient=FALSE, $introText='', $email=NULL, $ourPicks=NULL</template_data><template_content_plaintext>{$content|raw}</template_content_plaintext><template_pinned>0</template_pinned></template><template><template_app>core</template_app><template_name>digest</template_name><template_content_html><![CDATA[{$email->language->addToStack("digest_$frequency", FALSE)}
|
||||
<br />
|
||||
<br />
|
||||
<em style='color: #8c8c8c'>— {setting="board_name"}</em>
|
||||
@@ -2183,16 +2271,21 @@ ___digest___]]></template_content_plaintext><template_pinned>0</template_pinned>
|
||||
{{if $warning->expire_date}}
|
||||
{{if $warning->expire_date < time()}}
|
||||
{{if $warning->expire_date == -1}}
|
||||
{$email->language->addToStack("warn_action_points_never_expire", FALSE, array( 'sprintf' => array( $warning->points ) ) )}
|
||||
{$email->language->addToStack("warn_action_points_never_expire", FALSE, array( 'pluralize' => array( $warning->points ) ) )}
|
||||
{{else}}
|
||||
{$email->language->addToStack("warn_action_points_expired", FALSE, array( 'sprintf' => array( $warning->points, \IPS\DateTime::ts( $warning->expire_date ) ) ) )}
|
||||
{$email->language->addToStack("warn_action_points_expired", FALSE, array( 'pluralize' => array( $warning->points ), 'sprintf' => array( \IPS\DateTime::ts( $warning->expire_date ) ) ) )}
|
||||
{{endif}}
|
||||
{{else}}
|
||||
{$email->language->addToStack("warn_action_points_expire", FALSE, array( 'sprintf' => array( $warning->points, \IPS\DateTime::ts( $warning->expire_date ) ) ) )}
|
||||
{$email->language->addToStack("warn_action_points_expire", FALSE, array( 'pluralize' => array( $warning->points ), 'sprintf' => array( \IPS\DateTime::ts( $warning->expire_date ) ) ) )}
|
||||
{{endif}}
|
||||
{{else}}
|
||||
{$email->language->addToStack("warn_action_points", FALSE, array( 'sprintf' => array( $warning->points ) ) )}
|
||||
{{endif}}
|
||||
{$email->language->addToStack("warn_action_points", FALSE, array( 'pluralize' => array( $warning->points ) ) )}
|
||||
{{endif}}
|
||||
</li>
|
||||
{{endif}}
|
||||
{{if $warning->cheev_point_reduction}}
|
||||
<li>
|
||||
{$email->language->addToStack("warn_deduct_cheev_points", FALSE, array( 'pluralize' => array( $warning->cheev_point_reduction ) ) )}
|
||||
</li>
|
||||
{{endif}}
|
||||
{{if $warning->mq}}
|
||||
@@ -2271,15 +2364,15 @@ ___digest___]]></template_content_plaintext><template_pinned>0</template_pinned>
|
||||
{{if $warning->expire_date}}
|
||||
{{if $warning->expire_date < time()}}
|
||||
{{if $warning->expire_date == -1}}
|
||||
{$email->language->addToStack("warn_action_points_never_expire", FALSE, array( 'htmlsprintf' => array( $warning->points ) ) )}
|
||||
{$email->language->addToStack("warn_action_points_never_expire", FALSE, array( 'pluralize' => array( $warning->points ) ) )}
|
||||
{{else}}
|
||||
{$email->language->addToStack("warn_action_points_expired", FALSE, array( 'htmlsprintf' => array( $warning->points, \IPS\DateTime::ts( $warning->expire_date ) ) ) )}
|
||||
{$email->language->addToStack("warn_action_points_expired", FALSE, array( 'pluralize' => array( $warning->points ), 'htmlsprintf' => array( \IPS\DateTime::ts( $warning->expire_date ) ) ) )}
|
||||
{{endif}}
|
||||
{{else}}
|
||||
{$email->language->addToStack("warn_action_points_expire", FALSE, array( 'htmlsprintf' => array( $warning->points, \IPS\DateTime::ts( $warning->expire_date ) ) ) )}
|
||||
{$email->language->addToStack("warn_action_points_expire", FALSE, array( 'pluralize' => array( $warning->points ), 'htmlsprintf' => array( \IPS\DateTime::ts( $warning->expire_date ) ) ) )}
|
||||
{{endif}}
|
||||
{{else}}
|
||||
{$email->language->addToStack("warn_action_points", FALSE, array( 'htmlsprintf' => array( $warning->points ) ) )}
|
||||
{$email->language->addToStack("warn_action_points", FALSE, array( 'pluralize' => array( $warning->points ) ) )}
|
||||
{{endif}}
|
||||
{{endif}}
|
||||
{{if $warning->mq}}
|
||||
|
||||
+731
-147
File diff suppressed because it is too large.
Load diff
@@ -41,6 +41,7 @@
|
||||
"Locations": "IPS\\core\\extensions\\core\\MemberACPProfileBlocks\\Locations",
|
||||
"Header": "IPS\\core\\extensions\\core\\MemberACPProfileBlocks\\Header",
|
||||
"Referrals": "IPS\\core\\extensions\\core\\MemberACPProfileBlocks\\Referrals",
|
||||
"Points": "IPS\\core\\extensions\\core\\MemberACPProfileBlocks\\Points",
|
||||
"Notifications": "IPS\\core\\extensions\\core\\MemberACPProfileBlocks\\Notifications",
|
||||
"Warnings": "IPS\\core\\extensions\\core\\MemberACPProfileBlocks\\Warnings",
|
||||
"Groups": "IPS\\core\\extensions\\core\\MemberACPProfileBlocks\\Groups",
|
||||
@@ -51,6 +52,21 @@
|
||||
"MemberExportPersonalInformation": {
|
||||
"Main": "IPS\\core\\extensions\\core\\MemberExportPersonalInformation\\Main"
|
||||
},
|
||||
"AchievementAction": {
|
||||
"JoinClub": "IPS\\core\\extensions\\core\\AchievementAction\\JoinClub",
|
||||
"Reaction": "IPS\\core\\extensions\\core\\AchievementAction\\Reaction",
|
||||
"NewPoll": "IPS\\core\\extensions\\core\\AchievementAction\\NewPoll",
|
||||
"FollowContentItem": "IPS\\core\\extensions\\core\\AchievementAction\\FollowContentItem",
|
||||
"Review": "IPS\\core\\extensions\\core\\AchievementAction\\Review",
|
||||
"SessionStartDaily": "IPS\\core\\extensions\\core\\AchievementAction\\SessionStartDaily",
|
||||
"NewClub": "IPS\\core\\extensions\\core\\AchievementAction\\NewClub",
|
||||
"ContentPromotion": "IPS\\core\\extensions\\core\\AchievementAction\\ContentPromotion",
|
||||
"Comment": "IPS\\core\\extensions\\core\\AchievementAction\\Comment",
|
||||
"FollowNode": "IPS\\core\\extensions\\core\\AchievementAction\\FollowNode",
|
||||
"VotePoll": "IPS\\core\\extensions\\core\\AchievementAction\\VotePoll",
|
||||
"FollowMember": "IPS\\core\\extensions\\core\\AchievementAction\\FollowMember",
|
||||
"NewContentItem": "IPS\\core\\extensions\\core\\AchievementAction\\NewContentItem"
|
||||
},
|
||||
"LiveSearch": {
|
||||
"Settings": "IPS\\core\\extensions\\core\\LiveSearch\\Settings",
|
||||
"Clubs": "IPS\\core\\extensions\\core\\LiveSearch\\Clubs",
|
||||
@@ -71,7 +87,6 @@
|
||||
"Login": "IPS\\core\\extensions\\core\\FileStorage\\Login",
|
||||
"ClubField": "IPS\\core\\extensions\\core\\FileStorage\\ClubField",
|
||||
"Clubs": "IPS\\core\\extensions\\core\\FileStorage\\Clubs",
|
||||
"Feature": "IPS\\core\\extensions\\core\\FileStorage\\Feature",
|
||||
"ProfileField": "IPS\\core\\extensions\\core\\FileStorage\\ProfileField",
|
||||
"Advertisements": "IPS\\core\\extensions\\core\\FileStorage\\Advertisements",
|
||||
"Theme": "IPS\\core\\extensions\\core\\FileStorage\\Theme",
|
||||
@@ -80,7 +95,8 @@
|
||||
"Profile": "IPS\\core\\extensions\\core\\FileStorage\\Profile",
|
||||
"ReferralBanners": "IPS\\core\\extensions\\core\\FileStorage\\ReferralBanners",
|
||||
"Imageproxycache": "IPS\\core\\extensions\\core\\FileStorage\\Imageproxycache",
|
||||
"Attachment": "IPS\\core\\extensions\\core\\FileStorage\\Attachment"
|
||||
"Attachment": "IPS\\core\\extensions\\core\\FileStorage\\Attachment",
|
||||
"Badges": "IPS\\core\\extensions\\core\\FileStorage\\Badges"
|
||||
},
|
||||
"MFAArea": {
|
||||
"EmailChange": "IPS\\core\\extensions\\core\\MFAArea\\EmailChange",
|
||||
@@ -186,14 +202,17 @@
|
||||
"RemoveOrphanedReputation": "IPS\\core\\extensions\\core\\Queue\\RemoveOrphanedReputation",
|
||||
"FixDeletionLog": "IPS\\core\\extensions\\core\\Queue\\FixDeletionLog",
|
||||
"DeleteOrphanedFiles": "IPS\\core\\extensions\\core\\Queue\\DeleteOrphanedFiles",
|
||||
"Upgrade46FeaturedContent": "IPS\\core\\extensions\\core\\Queue\\Upgrade46FeaturedContent",
|
||||
"RebuildNonContentImages": "IPS\\core\\extensions\\core\\Queue\\RebuildNonContentImages",
|
||||
"DeleteMovedFiles": "IPS\\core\\extensions\\core\\Queue\\DeleteMovedFiles",
|
||||
"RecountPollVotes": "IPS\\core\\extensions\\core\\Queue\\RecountPollVotes",
|
||||
"RebuildLazyLoadNonContent": "IPS\\core\\extensions\\core\\Queue\\RebuildLazyLoadNonContent",
|
||||
"PWANotifications": "IPS\\core\\extensions\\core\\Queue\\PWANotifications",
|
||||
"RecountStarRatings": "IPS\\core\\extensions\\core\\Queue\\RecountStarRatings",
|
||||
"Follow": "IPS\\core\\extensions\\core\\Queue\\Follow",
|
||||
"RebuildSitemap": "IPS\\core\\extensions\\core\\Queue\\RebuildSitemap",
|
||||
"RebuildItemCounts": "IPS\\core\\extensions\\core\\Queue\\RebuildItemCounts",
|
||||
"FileCleanup": "IPS\\core\\extensions\\core\\Queue\\FileCleanup",
|
||||
"Bulkmail": "IPS\\core\\extensions\\core\\Queue\\Bulkmail",
|
||||
"UpdateMemberSeoNames": "IPS\\core\\extensions\\core\\Queue\\UpdateMemberSeoNames",
|
||||
"RebuildPosts": "IPS\\core\\extensions\\core\\Queue\\RebuildPosts",
|
||||
@@ -202,6 +221,7 @@
|
||||
"PruneMembers": "IPS\\core\\extensions\\core\\Queue\\PruneMembers",
|
||||
"UpdateMembers": "IPS\\core\\extensions\\core\\Queue\\UpdateMembers",
|
||||
"RebuildLazyLoad": "IPS\\core\\extensions\\core\\Queue\\RebuildLazyLoad",
|
||||
"RebuildUrlRels": "IPS\\core\\extensions\\core\\Queue\\RebuildUrlRels",
|
||||
"RebuildAttachmentThumbnails": "IPS\\core\\extensions\\core\\Queue\\RebuildAttachmentThumbnails",
|
||||
"PruneLargeTable": "IPS\\core\\extensions\\core\\Queue\\PruneLargeTable",
|
||||
"DeleteImageProxyFiles": "IPS\\core\\extensions\\core\\Queue\\DeleteImageProxyFiles",
|
||||
@@ -224,6 +244,7 @@
|
||||
"RebuildContainerCounts": "IPS\\core\\extensions\\core\\Queue\\RebuildContainerCounts",
|
||||
"RebuildImageProxy": "IPS\\core\\extensions\\core\\Queue\\RebuildImageProxy",
|
||||
"DeleteOrMoveContent": "IPS\\core\\extensions\\core\\Queue\\DeleteOrMoveContent",
|
||||
"RebuildAchievements": "IPS\\core\\extensions\\core\\Queue\\RebuildAchievements",
|
||||
"ForcePasswordReset": "IPS\\core\\extensions\\core\\Queue\\ForcePasswordReset",
|
||||
"RestoreBrokenAttachments": "IPS\\core\\extensions\\core\\Queue\\RestoreBrokenAttachments"
|
||||
},
|
||||
@@ -255,9 +276,11 @@
|
||||
"Registrations": "IPS\\core\\extensions\\core\\OverviewStatistics\\Registrations",
|
||||
"Contributors": "IPS\\core\\extensions\\core\\OverviewStatistics\\Contributors",
|
||||
"RepGiven": "IPS\\core\\extensions\\core\\OverviewStatistics\\RepGiven",
|
||||
"Points": "IPS\\core\\extensions\\core\\OverviewStatistics\\Points",
|
||||
"Tags": "IPS\\core\\extensions\\core\\OverviewStatistics\\Tags",
|
||||
"Reactions": "IPS\\core\\extensions\\core\\OverviewStatistics\\Reactions",
|
||||
"Online": "IPS\\core\\extensions\\core\\OverviewStatistics\\Online"
|
||||
"Online": "IPS\\core\\extensions\\core\\OverviewStatistics\\Online",
|
||||
"Badges": "IPS\\core\\extensions\\core\\OverviewStatistics\\Badges"
|
||||
},
|
||||
"Build": {
|
||||
"codemirror": "IPS\\core\\extensions\\core\\Build\\codemirror",
|
||||
@@ -307,10 +330,11 @@
|
||||
},
|
||||
"MetaData": {
|
||||
"ContentMessages": "IPS\\core\\extensions\\core\\MetaData\\ContentMessages",
|
||||
"FeaturedComments": "IPS\\core\\extensions\\core\\MetaData\\FeaturedComments",
|
||||
"ItemModeration": "IPS\\core\\extensions\\core\\MetaData\\ItemModeration"
|
||||
"ItemModeration": "IPS\\core\\extensions\\core\\MetaData\\ItemModeration",
|
||||
"FeaturedComments": "IPS\\core\\extensions\\core\\MetaData\\FeaturedComments"
|
||||
},
|
||||
"Notifications": {
|
||||
"Achievements": "IPS\\core\\extensions\\core\\Notifications\\Achievements",
|
||||
"Moderation": "IPS\\core\\extensions\\core\\Notifications\\Moderation",
|
||||
"Clubs": "IPS\\core\\extensions\\core\\Notifications\\Clubs",
|
||||
"MyStuff": "IPS\\core\\extensions\\core\\Notifications\\MyStuff",
|
||||
|
||||
@@ -192,6 +192,28 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"profile_badges": {
|
||||
"friendly": "profile/{#id}-{?}/badges",
|
||||
"real": "app=core&module=members&controller=profile&do=badges",
|
||||
"seoTitles": [
|
||||
{
|
||||
"class": "\\IPS\\Member",
|
||||
"queryParam": "id",
|
||||
"property": "members_seo_name"
|
||||
}
|
||||
]
|
||||
},
|
||||
"profile_solutions": {
|
||||
"friendly": "profile/{#id}-{?}/solutions",
|
||||
"real": "app=core&module=members&controller=profile&do=solutions",
|
||||
"seoTitles": [
|
||||
{
|
||||
"class": "\\IPS\\Member",
|
||||
"queryParam": "id",
|
||||
"property": "members_seo_name"
|
||||
}
|
||||
]
|
||||
},
|
||||
"edit_profile": {
|
||||
"friendly": "profile/{#id}-{?}/edit",
|
||||
"real": "app=core&module=members&controller=profile&do=edit",
|
||||
@@ -480,6 +502,10 @@
|
||||
"referral": {
|
||||
"friendly": "refer/{#id}",
|
||||
"real": "app=core&module=system&controller=referrals"
|
||||
},
|
||||
"user_offline": {
|
||||
"friendly": "offline",
|
||||
"real": "app=core&module=system&controller=offline"
|
||||
}
|
||||
}
|
||||
}
|
||||
+2191
-1030
File diff suppressed because it is too large.
Load diff
+998
-298
File diff suppressed because it is too large.
Load diff
@@ -122,7 +122,12 @@
|
||||
},
|
||||
"marketplace": {
|
||||
"default_controller": "",
|
||||
"protected": false,
|
||||
"protected": 0,
|
||||
"default": 0
|
||||
},
|
||||
"achievements": {
|
||||
"default_controller": "",
|
||||
"protected": 0,
|
||||
"default": 0
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"php": {
|
||||
"required": "7.1.0",
|
||||
"recommended": "7.3.0"
|
||||
"required": "7.2.0",
|
||||
"recommended": "7.4.0"
|
||||
},
|
||||
"mysql": {
|
||||
"required": "5.5.3",
|
||||
|
||||
+1749
-154
File diff suppressed because it is too large.
Load diff
@@ -1,4 +1,24 @@
|
||||
[
|
||||
{
|
||||
"key": "achievements_enabled",
|
||||
"default": "1",
|
||||
"report": "full"
|
||||
},
|
||||
{
|
||||
"key": "achievements_last_rebuilt",
|
||||
"default": "0",
|
||||
"report": "full"
|
||||
},
|
||||
{
|
||||
"key": "achievements_rebuilding",
|
||||
"default": "0",
|
||||
"report": "full"
|
||||
},
|
||||
{
|
||||
"key": "achievements_recognize_max_per_user_day",
|
||||
"default": "50",
|
||||
"report": "full"
|
||||
},
|
||||
{
|
||||
"key": "acp_css_map",
|
||||
"default": "",
|
||||
@@ -424,11 +444,6 @@
|
||||
"default": "",
|
||||
"report": "none"
|
||||
},
|
||||
{
|
||||
"key": "disable_anonymous",
|
||||
"default": "0",
|
||||
"report": "full"
|
||||
},
|
||||
{
|
||||
"key": "edit_log",
|
||||
"default": "1",
|
||||
@@ -539,6 +554,21 @@
|
||||
"default": "3",
|
||||
"report": "full"
|
||||
},
|
||||
{
|
||||
"key": "fb_ig_oembed_appid",
|
||||
"default": "",
|
||||
"report": "none"
|
||||
},
|
||||
{
|
||||
"key": "fb_ig_oembed_appsecret",
|
||||
"default": "",
|
||||
"report": "none"
|
||||
},
|
||||
{
|
||||
"key": "fb_ig_oembed_token",
|
||||
"default": "",
|
||||
"report": "bool"
|
||||
},
|
||||
{
|
||||
"key": "fb_pixel_delay",
|
||||
"default": "0",
|
||||
@@ -664,6 +694,11 @@
|
||||
"default": "0",
|
||||
"report": "full"
|
||||
},
|
||||
{
|
||||
"key": "icons_apple_startup",
|
||||
"default": "",
|
||||
"report": "bool"
|
||||
},
|
||||
{
|
||||
"key": "icons_favicon",
|
||||
"default": "",
|
||||
@@ -1094,6 +1129,11 @@
|
||||
"default": "{\"count\":0,\"time\":0}",
|
||||
"report": "none"
|
||||
},
|
||||
{
|
||||
"key": "mp_onboard_complete",
|
||||
"default": "1",
|
||||
"report": "none"
|
||||
},
|
||||
{
|
||||
"key": "new_device_email",
|
||||
"default": "0",
|
||||
@@ -1169,6 +1209,11 @@
|
||||
"default": "0",
|
||||
"report": "full"
|
||||
},
|
||||
{
|
||||
"key": "pixabay_safesearch",
|
||||
"default": "1",
|
||||
"report": "full"
|
||||
},
|
||||
{
|
||||
"key": "poll_allow_public",
|
||||
"default": "1",
|
||||
@@ -1209,11 +1254,6 @@
|
||||
"default": "1",
|
||||
"report": "full"
|
||||
},
|
||||
{
|
||||
"key": "post_titlechange",
|
||||
"default": "500",
|
||||
"report": "full"
|
||||
},
|
||||
{
|
||||
"key": "posts_add_nofollow",
|
||||
"default": "1",
|
||||
@@ -1369,11 +1409,21 @@
|
||||
"default": "30",
|
||||
"report": "full"
|
||||
},
|
||||
{
|
||||
"key": "prune_points_log",
|
||||
"default": "365",
|
||||
"report": "full"
|
||||
},
|
||||
{
|
||||
"key": "quick_register",
|
||||
"default": "1",
|
||||
"report": "full"
|
||||
},
|
||||
{
|
||||
"key": "rare_badge_percent",
|
||||
"default": "5",
|
||||
"report": "full"
|
||||
},
|
||||
{
|
||||
"key": "reaction_count_display",
|
||||
"default": "individual",
|
||||
@@ -1399,6 +1449,11 @@
|
||||
"default": "0",
|
||||
"report": "full"
|
||||
},
|
||||
{
|
||||
"key": "referrer_policy_header",
|
||||
"default": "2",
|
||||
"report": "full"
|
||||
},
|
||||
{
|
||||
"key": "reg_auth_type",
|
||||
"default": "user",
|
||||
@@ -1409,6 +1464,11 @@
|
||||
"default": "<p>Please take a moment to review these rules.<\/p><p>Please remember that we are not responsible for any messages posted. We do not vouch for or warrant the accuracy, completeness or usefulness of any message, and are not responsible for the contents of any message.<\/p><p>The messages express the views of the author of the message, not necessarily the views of this website. Any user who feels that a posted message is objectionable is encouraged to contact us immediately by email. We have the ability to remove objectionable messages and we will make every effort to do so, within a reasonable time frame, if we determine that removal is necessary.<\/p><p>You agree, through your use of this service, that you will not use this website to post any material which is knowingly false and\/or defamatory, inaccurate, abusive, vulgar, hateful, harassing, obscene, profane, sexually oriented, threatening, invasive of a person's privacy, or otherwise violative of any law.<\/p><p>You agree not to post any copyrighted material unless the copyright is owned by you or by this website.<\/p><p>Our software uses cookies to distinguish you from other users of our website. This helps us to provide you with a personalized experience when you browse this site.<\/p>",
|
||||
"report": "bool"
|
||||
},
|
||||
{
|
||||
"key": "relative_dates_enable",
|
||||
"default": "1",
|
||||
"report": "full"
|
||||
},
|
||||
{
|
||||
"key": "remote_image_cache",
|
||||
"default": "7",
|
||||
@@ -1489,6 +1549,11 @@
|
||||
"default": "5",
|
||||
"report": "full"
|
||||
},
|
||||
{
|
||||
"key": "rules_exclude_groups",
|
||||
"default": "[]",
|
||||
"report": "none"
|
||||
},
|
||||
{
|
||||
"key": "search_decay_days",
|
||||
"default": "120",
|
||||
@@ -1754,6 +1819,11 @@
|
||||
"default": "4",
|
||||
"report": "full"
|
||||
},
|
||||
{
|
||||
"key": "spam_service_days",
|
||||
"default": "",
|
||||
"report": "bool"
|
||||
},
|
||||
{
|
||||
"key": "spam_service_enabled",
|
||||
"default": "0",
|
||||
@@ -1984,6 +2054,16 @@
|
||||
"default": "30",
|
||||
"report": "full"
|
||||
},
|
||||
{
|
||||
"key": "vapid_private_key",
|
||||
"default": "",
|
||||
"report": "none"
|
||||
},
|
||||
{
|
||||
"key": "vapid_public_key",
|
||||
"default": "",
|
||||
"report": "none"
|
||||
},
|
||||
{
|
||||
"key": "viglink_api_key",
|
||||
"default": "",
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"profilesync":"P0Y0M0DT1H0M0S","updatecheck":"P0Y0M1DT0H0M0S","cleanup":"P0Y0M1DT0H0M0S","sitemapgenerator":"P0Y0M0DT0H15M0S","queue":"P0Y0M0DT0H1M0S","pop":"P0Y0M0DT0H10M0S","digest":"P0Y0M0DT0H5M0S","publish":"P0Y0M0DT0H10M0S","clearcache":"P0Y0M0DT0H10M0S","clearsessions":"P0Y0M0DT0H30M0S","viewupdates":"P0Y0M0DT0H5M0S","cleanupattachments":"P0Y0M0DT12H0M0S","cleanupfiles":"P0Y0M1DT0H0M0S","unlockmembers":"P0Y0M0DT1H0M0S","leaderboard":"P0Y0M0DT6H0M0S","deletecontent":"P0Y0M1DT0H0M0S","clubrebuild":"P0Y0M0DT0H20M0S","onlineusers":"P0Y0M0DT0H15M0S","promote":"P0Y0M0DT0H5M0S","prunesearchindex":"P0Y0M1DT0H0M0S","prunesystemlogs":"P0Y0M1DT0H0M0S","automaticmoderation":"P0Y0M0DT0H10M0S","usagereporting":"P0Y0M7DT0H0M0S","userAgentStatistics":"P0Y0M0DT0H30M0S","pruneipaddresses":"P0Y0M1DT0H0M0S","clearelasticsearchtasks":"P0Y0M1DT0H0M0S","postBeforeRegisterFollowup":"P0Y0M0DT1H0M0S","weeklydigest":"P0Y0M0DT2H0M0S","clearincompletemembers":"P0Y0M0DT1H0M0S","rssimport":"P0Y0M0DT0H15M0S","webhooks":"P0Y0M0DT0H2M0S","chunkcleanup":"P0Y0M1DT0H0M0S","s3Delete":"P0Y0M0DT0H15M0S"}
|
||||
{"profilesync":"P0Y0M0DT1H0M0S","updatecheck":"P0Y0M1DT0H0M0S","cleanup":"P0Y0M1DT0H0M0S","sitemapgenerator":"P0Y0M0DT0H15M0S","queue":"P0Y0M0DT0H1M0S","pop":"P0Y0M0DT0H10M0S","digest":"P0Y0M0DT0H5M0S","publish":"P0Y0M0DT0H10M0S","clearcache":"P0Y0M0DT0H10M0S","clearsessions":"P0Y0M0DT0H30M0S","viewupdates":"P0Y0M0DT0H5M0S","cleanupattachments":"P0Y0M0DT12H0M0S","cleanupfiles":"P0Y0M1DT0H0M0S","unlockmembers":"P0Y0M0DT1H0M0S","leaderboard":"P0Y0M0DT6H0M0S","deletecontent":"P0Y0M1DT0H0M0S","clubrebuild":"P0Y0M0DT0H20M0S","onlineusers":"P0Y0M0DT0H15M0S","promote":"P0Y0M0DT0H5M0S","prunesearchindex":"P0Y0M1DT0H0M0S","prunesystemlogs":"P0Y0M1DT0H0M0S","automaticmoderation":"P0Y0M0DT0H10M0S","usagereporting":"P0Y0M7DT0H0M0S","userAgentStatistics":"P0Y0M0DT0H30M0S","pruneipaddresses":"P0Y0M1DT0H0M0S","clearelasticsearchtasks":"P0Y0M1DT0H0M0S","postBeforeRegisterFollowup":"P0Y0M0DT1H0M0S","weeklydigest":"P0Y0M0DT2H0M0S","clearincompletemembers":"P0Y0M0DT1H0M0S","rssimport":"P0Y0M0DT0H15M0S","webhooks":"P0Y0M0DT0H2M0S","chunkcleanup":"P0Y0M1DT0H0M0S","s3Delete":"P0Y0M0DT0H15M0S","pwaprune":"P0Y0M1DT0H0M0S"}
|
||||
+3919
-1831
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -368,6 +368,7 @@
|
||||
"104067": "4.4.10",
|
||||
"104068": "4.4.10",
|
||||
"104069": "4.4.10",
|
||||
"104070": "4.4.11",
|
||||
"105013": "4.5.0 Beta 1",
|
||||
"105014": "4.5.0 Beta 1",
|
||||
"105015": "4.5.0 Beta 2",
|
||||
@@ -388,5 +389,42 @@
|
||||
"105030": "4.5.0 Beta 11",
|
||||
"105031": "4.5.0 Beta 11",
|
||||
"105032": "4.5.0 Beta 12",
|
||||
"105100": "4.5.0"
|
||||
"105100": "4.5.0",
|
||||
"105101": "4.5.0",
|
||||
"105102": "4.5.1 Beta 1",
|
||||
"105103": "4.5.1 Beta 1",
|
||||
"105104": "4.5.1 Beta 2",
|
||||
"105105": "4.5.1 Beta 3",
|
||||
"105106": "4.5.1",
|
||||
"105107": "4.5.2",
|
||||
"105108": "4.5.2",
|
||||
"105109": "4.5.2",
|
||||
"105110": "4.5.2",
|
||||
"105111": "4.5.2",
|
||||
"105112": "4.5.3",
|
||||
"105113": "4.5.3",
|
||||
"105114": "4.5.3",
|
||||
"105115": "4.5.3",
|
||||
"105116": "4.5.4",
|
||||
"105117": "4.5.4",
|
||||
"105118": "4.5.4",
|
||||
"105119": "4.5.4",
|
||||
"105120": "4.5.4",
|
||||
"105121": "4.5.4",
|
||||
"105122": "4.5.4",
|
||||
"105123": "4.5.4",
|
||||
"105124": "4.5.4.1",
|
||||
"105125": "4.5.4.2",
|
||||
"105126": "4.5.4.2",
|
||||
"105127": "4.5.4.2",
|
||||
"105128": "4.5.4.2",
|
||||
"105129": "4.5.4.2",
|
||||
"105130": "4.5.4.2",
|
||||
"106100": "4.6.0 Beta 1",
|
||||
"106101": "4.6.0 Beta 1.1",
|
||||
"106103": "4.6.0 Beta 2",
|
||||
"106104": "4.6.0 Beta 3",
|
||||
"106105": "4.6.0 Beta 3.1",
|
||||
"106106": "4.6.0 Beta 4",
|
||||
"106107": "4.6.0"
|
||||
}
|
||||
@@ -1,171 +1 @@
|
||||
{
|
||||
"activeUsers": {
|
||||
"class": "\\IPS\\Widget",
|
||||
"restrict": [],
|
||||
"default_area": "",
|
||||
"allow_reuse": false,
|
||||
"menu_style": "menu",
|
||||
"embeddable": true
|
||||
},
|
||||
"stats": {
|
||||
"class": "\\IPS\\Widget\\StaticCache",
|
||||
"restrict": [],
|
||||
"default_area": "",
|
||||
"allow_reuse": false,
|
||||
"menu_style": "menu",
|
||||
"embeddable": true
|
||||
},
|
||||
"relatedContent": {
|
||||
"class": "\\IPS\\Widget",
|
||||
"restrict": [],
|
||||
"default_area": "",
|
||||
"allow_reuse": false,
|
||||
"menu_style": "menu",
|
||||
"embeddable": true
|
||||
},
|
||||
"recentStatusUpdates": {
|
||||
"class": "\\IPS\\Widget\\StaticCache",
|
||||
"restrict": [],
|
||||
"default_area": "",
|
||||
"allow_reuse": false,
|
||||
"menu_style": "menu",
|
||||
"embeddable": true
|
||||
},
|
||||
"topContributors": {
|
||||
"class": "\\IPS\\Widget\\StaticCache",
|
||||
"restrict": [],
|
||||
"default_area": "",
|
||||
"allow_reuse": false,
|
||||
"menu_style": "menu",
|
||||
"embeddable": true
|
||||
},
|
||||
"whosOnline": {
|
||||
"class": "\\IPS\\Widget",
|
||||
"restrict": [],
|
||||
"default_area": "",
|
||||
"allow_reuse": false,
|
||||
"menu_style": "menu",
|
||||
"embeddable": true
|
||||
},
|
||||
"members": {
|
||||
"class": "\\IPS\\Widget\\StaticCache",
|
||||
"restrict": [
|
||||
"sidebar",
|
||||
"cms"
|
||||
],
|
||||
"default_area": "",
|
||||
"allow_reuse": true,
|
||||
"menu_style": "modal",
|
||||
"embeddable": true
|
||||
},
|
||||
"guestSignUp": {
|
||||
"class": "\\IPS\\Widget\\StaticCache",
|
||||
"restrict": [
|
||||
"sidebar",
|
||||
"cms"
|
||||
],
|
||||
"default_area": "",
|
||||
"allow_reuse": false,
|
||||
"menu_style": "modal",
|
||||
"embeddable": true
|
||||
},
|
||||
"promoted": {
|
||||
"class": "\\IPS\\Widget\\PermissionCache",
|
||||
"restrict": [
|
||||
"sidebar",
|
||||
"cms"
|
||||
],
|
||||
"default_area": "",
|
||||
"allow_reuse": false,
|
||||
"menu_style": "menu",
|
||||
"embeddable": true
|
||||
},
|
||||
"clubs": {
|
||||
"class": "\\IPS\\Widget",
|
||||
"restrict": [
|
||||
"sidebar",
|
||||
"cms"
|
||||
],
|
||||
"default_area": "",
|
||||
"allow_reuse": true,
|
||||
"menu_style": "modal",
|
||||
"embeddable": true
|
||||
},
|
||||
"newsletter": {
|
||||
"class": "\\IPS\\Widget",
|
||||
"restrict": [
|
||||
"sidebar",
|
||||
"cms"
|
||||
],
|
||||
"default_area": "",
|
||||
"allow_reuse": false,
|
||||
"menu_style": "modal",
|
||||
"embeddable": true
|
||||
},
|
||||
"mostContributions": {
|
||||
"class": "\\IPS\\Widget\\StaticCache",
|
||||
"restrict": [
|
||||
"sidebar",
|
||||
"cms"
|
||||
],
|
||||
"default_area": "",
|
||||
"allow_reuse": true,
|
||||
"menu_style": "menu",
|
||||
"embeddable": true
|
||||
},
|
||||
"oembed": {
|
||||
"class": "\\IPS\\Widget\\StaticCache",
|
||||
"restrict": [
|
||||
"sidebar",
|
||||
"cms"
|
||||
],
|
||||
"default_area": "",
|
||||
"allow_reuse": true,
|
||||
"menu_style": "modal",
|
||||
"embeddable": true
|
||||
},
|
||||
"twitter": {
|
||||
"class": "\\IPS\\Widget\\StaticCache",
|
||||
"restrict": [
|
||||
"sidebar",
|
||||
"cms"
|
||||
],
|
||||
"default_area": "",
|
||||
"allow_reuse": true,
|
||||
"menu_style": "modal",
|
||||
"embeddable": true
|
||||
},
|
||||
"invite": {
|
||||
"class": "\\IPS\\Widget\\StaticCache",
|
||||
"restrict": [
|
||||
"sidebar",
|
||||
"cms"
|
||||
],
|
||||
"default_area": "",
|
||||
"allow_reuse": false,
|
||||
"menu_style": "menu",
|
||||
"embeddable": true
|
||||
},
|
||||
"stream": {
|
||||
"class": "\\IPS\\Widget\\PermissionCache",
|
||||
"restrict": [
|
||||
"sidebar",
|
||||
"cms"
|
||||
],
|
||||
"default_area": "",
|
||||
"allow_reuse": true,
|
||||
"menu_style": "menu",
|
||||
"embeddable": true
|
||||
},
|
||||
"mostSolved": {
|
||||
"class": "\\IPS\\Widget\\StaticCache",
|
||||
"restrict": [
|
||||
"sidebar",
|
||||
"cms"
|
||||
],
|
||||
"default_area": "",
|
||||
"allow_reuse": false,
|
||||
"menu_style": "modal",
|
||||
"embeddable": true
|
||||
}
|
||||
}
|
||||
{"activeUsers":{"class":"\\IPS\\Widget","restrict":[],"default_area":"","allow_reuse":false,"menu_style":"menu","embeddable":true},"stats":{"class":"\\IPS\\Widget\\StaticCache","restrict":[],"default_area":"","allow_reuse":false,"menu_style":"menu","embeddable":true},"relatedContent":{"class":"\\IPS\\Widget","restrict":[],"default_area":"","allow_reuse":false,"menu_style":"menu","embeddable":true},"recentStatusUpdates":{"class":"\\IPS\\Widget\\StaticCache","restrict":[],"default_area":"","allow_reuse":false,"menu_style":"menu","embeddable":true},"topContributors":{"class":"\\IPS\\Widget\\StaticCache","restrict":[],"default_area":"","allow_reuse":false,"menu_style":"menu","embeddable":true},"whosOnline":{"class":"\\IPS\\Widget","restrict":[],"default_area":"","allow_reuse":false,"menu_style":"menu","embeddable":true},"members":{"class":"\\IPS\\Widget\\StaticCache","restrict":["sidebar","cms"],"default_area":"","allow_reuse":true,"menu_style":"modal","embeddable":true},"guestSignUp":{"class":"\\IPS\\Widget\\StaticCache","restrict":["sidebar","cms"],"default_area":"","allow_reuse":false,"menu_style":"modal","embeddable":true},"promoted":{"class":"\\IPS\\Widget\\PermissionCache","restrict":["sidebar","cms"],"default_area":"","allow_reuse":false,"menu_style":"menu","embeddable":true},"clubs":{"class":"\\IPS\\Widget","restrict":["sidebar","cms"],"default_area":"","allow_reuse":true,"menu_style":"modal","embeddable":true},"newsletter":{"class":"\\IPS\\Widget","restrict":["sidebar","cms"],"default_area":"","allow_reuse":false,"menu_style":"modal","embeddable":true},"mostContributions":{"class":"\\IPS\\Widget\\StaticCache","restrict":["sidebar","cms"],"default_area":"","allow_reuse":true,"menu_style":"menu","embeddable":true},"twitter":{"class":"\\IPS\\Widget\\StaticCache","restrict":["sidebar","cms"],"default_area":"","allow_reuse":true,"menu_style":"modal","embeddable":true},"invite":{"class":"\\IPS\\Widget\\StaticCache","restrict":["sidebar","cms"],"default_area":"","allow_reuse":false,"menu_style":"menu","embeddable":true},"stream":{"class":"\\IPS\\Widget\\PermissionCache","restrict":["sidebar","cms"],"default_area":"","allow_reuse":true,"menu_style":"menu","embeddable":true},"mostSolved":{"class":"\\IPS\\Widget\\StaticCache","restrict":["sidebar","cms"],"default_area":"","allow_reuse":false,"menu_style":"modal","embeddable":true},"achievements":{"class":"\\IPS\\Widget\\StaticCache","restrict":["sidebar","cms"],"default_area":"","allow_reuse":true,"menu_style":"menu","embeddable":true}}
|
||||
@@ -0,0 +1,174 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Achievement Action 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 03 Mar 2021
|
||||
*/
|
||||
|
||||
namespace IPS\core\extensions\core\AchievementAction;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Achievement Action Extension
|
||||
*/
|
||||
class _Comment extends \IPS\core\Achievements\Actions\AbstractContentAchievementAction
|
||||
{
|
||||
protected static $includeItems = FALSE;
|
||||
protected static $includeReviews = FALSE;
|
||||
|
||||
/**
|
||||
* Work out if the filters applies for a given action
|
||||
*
|
||||
* Important note for milestones: consider the context. This method is called by \IPS\Member::achievementAction(). If your code
|
||||
* calls that BEFORE making its change in the database (or there is read/write separation), you will need to add
|
||||
* 1 to the value being considered for milestones
|
||||
*
|
||||
* @param \IPS\Member $subject The subject member
|
||||
* @param array $filters The value returned by formatFilterValues()
|
||||
* @param mixed $extra Any additional information about what is happening (e.g. if a post is being made: the post object)
|
||||
* @return bool
|
||||
*/
|
||||
public function filtersMatch( \IPS\Member $subject, array $filters, $extra = NULL ): bool
|
||||
{
|
||||
if ( !parent::filtersMatch( $subject, $filters, $extra ) )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ( isset( $filters['milestone'] ) )
|
||||
{
|
||||
$count = 0;
|
||||
$classes = [];
|
||||
$itemClassesToDeduct = [];
|
||||
if ( isset( $filters['type'] ) )
|
||||
{
|
||||
if ( isset( $filters[ 'nodes_' . str_replace( '\\', '-', $filters['type'] ) ] ) )
|
||||
{
|
||||
$class = $filters['type'];
|
||||
$where = [];
|
||||
$where[] = [ $class::$databasePrefix . $class::$databaseColumnMap['author'] . '=?', $subject->member_id ];
|
||||
$where[] = [ \IPS\Db::i()->in( $class::$databasePrefix . $class::$databaseColumnMap['container'] ), $filters[ 'nodes_' . str_replace( '\\', '-', $filters['type'] ) ] ];
|
||||
|
||||
$count += \IPS\Db::i()->select( 'COUNT(*)', $class::$databaseTable, $where )->first();
|
||||
}
|
||||
else
|
||||
{
|
||||
$classes[] = $filters['type'];
|
||||
}
|
||||
|
||||
foreach ( $classes as $class )
|
||||
{
|
||||
$count += $class::memberPostCount( $subject, TRUE, FALSE );
|
||||
}
|
||||
foreach ( $itemClassesToDeduct as $class )
|
||||
{
|
||||
$count -= $class::memberPostCount( $subject, TRUE, FALSE );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* It's too expensive to get a live count from every single item/comment class available to the suite
|
||||
so lets just use the post count here. It won't be quite as accurate but we're not a bank so whatever */
|
||||
$count = $subject->member_posts;
|
||||
}
|
||||
|
||||
if ( $count < $filters['milestone'] )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the labels for the people this action might give awards to
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function awardOptions(): array
|
||||
{
|
||||
return [
|
||||
'subject' => 'achievement_filter_Comment_author',
|
||||
'other' => 'achievement_filter_Comment_item_author'
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the "other" people we need to award =stuff to
|
||||
*
|
||||
* @param mixed $extra Any additional information about what is happening (e.g. if a post is being made: the post object)
|
||||
* @return array
|
||||
*/
|
||||
public function awardOther( $extra = NULL ): array
|
||||
{
|
||||
return [ $extra->item()->author() ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a description for this action to show in the log
|
||||
*
|
||||
* @param string $identifier The identifier as returned by identifier()
|
||||
* @param array $actor If the member was the "subject", "other", or both
|
||||
* @return string
|
||||
*/
|
||||
public function logRow( string $identifier, array $actor ): string
|
||||
{
|
||||
$exploded = explode( ':', $identifier );
|
||||
|
||||
$sprintf = [];
|
||||
try
|
||||
{
|
||||
$comment = $exploded[0]::load( $exploded[1] );
|
||||
$item = $comment->item();
|
||||
$sprintf = [ 'htmlsprintf' => [
|
||||
\IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->basicUrl( $comment->url(), TRUE, $item->mapped('title') ?: $item->indefiniteArticle(), FALSE )
|
||||
] ];
|
||||
}
|
||||
catch ( \OutOfRangeException $e )
|
||||
{
|
||||
$sprintf = [ 'sprintf' => [ \IPS\Member::loggedIn()->language()->addToStack('modcp_deleted') ] ];
|
||||
}
|
||||
|
||||
return \IPS\Member::loggedIn()->language()->addToStack( 'AchievementAction__Comment_log', FALSE, $sprintf );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get "description" for rule
|
||||
*
|
||||
* @param \IPS\core\Achievements\Rule $rule The rule
|
||||
* @return string|NULL
|
||||
*/
|
||||
public function ruleDescription( \IPS\core\Achievements\Rule $rule ): ?string
|
||||
{
|
||||
$type = $rule->filters['type'] ?? NULL;
|
||||
|
||||
$conditions = [];
|
||||
if ( isset( $rule->filters['milestone'] ) )
|
||||
{
|
||||
$conditions[] = \IPS\Member::loggedIn()->language()->addToStack( 'achievements_title_filter_milestone', FALSE, [
|
||||
'htmlsprintf' => [
|
||||
\IPS\Theme::i()->getTemplate( 'achievements' )->ruleDescriptionBadge( 'milestone', \IPS\Member::loggedIn()->language()->addToStack( 'achievements_title_filter_milestone_nth', FALSE, [ 'pluralize' => [ $rule->filters['milestone'] ] ] ) )
|
||||
],
|
||||
'sprintf' => [ $type ? \IPS\Member::loggedIn()->language()->addToStack( $type::$title ) : \IPS\Member::loggedIn()->language()->addToStack('AchievementAction__Comment_title_generic') ]
|
||||
] );
|
||||
}
|
||||
if ( $nodeCondition = $this->_nodeFilterDescription( $rule ) )
|
||||
{
|
||||
$conditions[] = $nodeCondition;
|
||||
}
|
||||
|
||||
return \IPS\Theme::i()->getTemplate( 'achievements' )->ruleDescription(
|
||||
$type ? \IPS\Member::loggedIn()->language()->addToStack( 'AchievementAction__NewContentItem_title_t', FALSE, [ 'sprintf' => [ \IPS\Member::loggedIn()->language()->addToStack( $type::$title ) ] ] ) : \IPS\Member::loggedIn()->language()->addToStack( 'AchievementAction__Comment_title' ),
|
||||
$conditions
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,408 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Achievement Action 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 05 Mar 2021
|
||||
*/
|
||||
|
||||
namespace IPS\core\extensions\core\AchievementAction;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Achievement Action Extension
|
||||
*/
|
||||
class _ContentPromotion extends \IPS\core\Achievements\Actions\AbstractContentAchievementAction
|
||||
{
|
||||
/**
|
||||
* Get filter form elements
|
||||
*
|
||||
* @param array|NULL $filters Current filter values (if editing)
|
||||
* @param \IPS\Http\Url $url The URL the form is being shown on
|
||||
* @return array
|
||||
*/
|
||||
public function filters( ?array $filters, \IPS\Http\Url $url ): array
|
||||
{
|
||||
$return = parent::filters( $filters, $url );
|
||||
|
||||
$promoFilter = new \IPS\Helpers\Form\CheckboxSet( 'achievement_filter_ContentPromotion_promotype', ( $filters and isset( $filters['promotype'] ) and $filters['promotype'] ) ? $filters['promotype'] : 0, FALSE, [
|
||||
'options' => [
|
||||
'promote' => 'achievement_filter_ContentPromotion_promotype_promote',
|
||||
'feature' => 'achievement_filter_ContentPromotion_promotype_feature',
|
||||
'recommend' => 'achievement_filter_ContentPromotion_promotype_recommend'
|
||||
]
|
||||
], NULL, \IPS\Member::loggedIn()->language()->addToStack( 'achievement_subfilter_ContentPromotion_promotype_prefix' ) );
|
||||
$return['promotype'] = $promoFilter;
|
||||
|
||||
if ( isset( $return['milestone'] ) )
|
||||
{
|
||||
$return['milestone']->suffix = \IPS\Member::loggedIn()->language()->addToStack('achievement_filter_ContentPromotion_nth_suffix');
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format filter form values
|
||||
*
|
||||
* @param array $values The values from the form
|
||||
* @return array
|
||||
*/
|
||||
public function formatFilterValues( array $values ): array
|
||||
{
|
||||
$return = parent::formatFilterValues( $values );
|
||||
if ( isset( $values['achievement_filter_ContentPromotion_promotype'] ) )
|
||||
{
|
||||
$return['promotype'] = $values['achievement_filter_ContentPromotion_promotype'];
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Work out if the filters applies for a given action
|
||||
*
|
||||
* Important note for milestones: consider the context. This method is called by \IPS\Member::achievementAction(). If your code
|
||||
* calls that BEFORE making its change in the database (or there is read/write separation), you will need to add
|
||||
* 1 to the value being considered for milestones
|
||||
*
|
||||
* @param \IPS\Member $subject The subject member
|
||||
* @param array $filters The value returned by formatFilterValues()
|
||||
* @param mixed $extra Any additional information about what is happening (e.g. if a post is being made: the post object)
|
||||
* @return bool
|
||||
*/
|
||||
public function filtersMatch( \IPS\Member $subject, array $filters, $extra = NULL ): bool
|
||||
{
|
||||
if ( !parent::filtersMatch( $subject, $filters, $extra['content'] ) )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ( isset( $filters['promotype'] ) and ! \in_array( $extra['promotype'], $filters['promotype'] ) )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ( isset( $filters['milestone'] ) )
|
||||
{
|
||||
if ( ( $this->getQuery( 'COUNT(*)', $filters, $filters['promotype'], $subject )->first() + 1 ) < $filters['milestone'] )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @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)
|
||||
* @return string
|
||||
*/
|
||||
public function identifier( \IPS\Member $subject, $extra = NULL ): string
|
||||
{
|
||||
return \get_class( $extra['content'] ) . ':' . $extra['content']->{$extra['content']::$databaseColumnId} . ':' . $extra['promotype'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a description for this action to show in the log
|
||||
*
|
||||
* @param string $identifier The identifier as returned by identifier()
|
||||
* @param array $actor If the member was the "subject", "other", or both
|
||||
* @return string
|
||||
*/
|
||||
public function logRow( string $identifier, array $actor ): string
|
||||
{
|
||||
$exploded = explode( ':', $identifier );
|
||||
|
||||
$contentLink = \IPS\Member::loggedIn()->language()->addToStack('modcp_deleted');
|
||||
try
|
||||
{
|
||||
$class = $exploded[0];
|
||||
$content = $class::load( $exploded[1] );
|
||||
$contentLink = \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->basicUrl( $content->url(), TRUE, $content->mapped('title'), FALSE );
|
||||
$promoType = \IPS\Member::loggedIn()->language()->addToStack( 'achievement_filter_ContentPromotion_promotype_' . $exploded[2] );
|
||||
}
|
||||
catch ( \OutOfRangeException $e ) { }
|
||||
|
||||
return \IPS\Member::loggedIn()->language()->addToStack( 'AchievementAction__ContentPromotion_log_subject', FALSE, [ 'sprintf' => [ $promoType ], 'htmlsprintf' => [ $contentLink ] ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get "description" for rule
|
||||
*
|
||||
* @param \IPS\core\Achievements\Rule $rule The rule
|
||||
* @return string|NULL
|
||||
*/
|
||||
public function ruleDescription( \IPS\core\Achievements\Rule $rule ): ?string
|
||||
{
|
||||
$conditions = [];
|
||||
if ( isset( $rule->filters['milestone'] ) )
|
||||
{
|
||||
$conditions[] = \IPS\Member::loggedIn()->language()->addToStack( 'achievements_title_filter_milestone', FALSE, [
|
||||
'htmlsprintf' => [
|
||||
\IPS\Theme::i()->getTemplate( 'achievements' )->ruleDescriptionBadge( 'milestone', \IPS\Member::loggedIn()->language()->addToStack( 'achievements_title_filter_milestone_nth', FALSE, [ 'pluralize' => [ $rule->filters['milestone'] ] ] ) )
|
||||
],
|
||||
'sprintf' => \IPS\Member::loggedIn()->language()->addToStack('AchievementAction__ContentPromotion_title_generic')
|
||||
] );
|
||||
}
|
||||
if ( isset( $rule->filters['promotype'] ) )
|
||||
{
|
||||
$promoTypes = [];
|
||||
foreach ( $rule->filters['promotype'] as $type )
|
||||
{
|
||||
try
|
||||
{
|
||||
$promoTypes[] = \IPS\Member::loggedIn()->language()->addToStack( 'achievement_filter_ContentPromotion_promotype_' . $type );
|
||||
}
|
||||
catch ( \OutOfRangeException $e ) {}
|
||||
}
|
||||
if ( $promoTypes )
|
||||
{
|
||||
$conditions[] = \IPS\Member::loggedIn()->language()->addToStack( 'achievements_title_filter_type', FALSE, [
|
||||
'htmlsprintf' => [
|
||||
\IPS\Theme::i()->getTemplate( 'achievements' )->ruleDescriptionBadge( 'other',
|
||||
\count( $promoTypes ) === 1 ? $promoTypes[0] : \IPS\Member::loggedIn()->language()->addToStack( 'AchievementAction__ContentPromotion_types', FALSE, [ 'sprintf' => [
|
||||
\count( $promoTypes ),
|
||||
] ] ),
|
||||
\count( $promoTypes ) === 1 ? NULL : $promoTypes
|
||||
)
|
||||
],
|
||||
] );
|
||||
}
|
||||
}
|
||||
if ( $nodeCondition = $this->_nodeFilterDescription( $rule ) )
|
||||
{
|
||||
$conditions[] = $nodeCondition;
|
||||
}
|
||||
|
||||
return \IPS\Theme::i()->getTemplate( 'achievements' )->ruleDescription(
|
||||
\IPS\Member::loggedIn()->language()->addToStack( 'AchievementAction__ContentPromotion_title' ),
|
||||
$conditions
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get rebuild data
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
static public function rebuildData()
|
||||
{
|
||||
return [ [
|
||||
'table' => 'core_content_meta',
|
||||
'pkey' => 'meta_id',
|
||||
'date' => 'meta_added',
|
||||
'where' => [ ['meta_type=?', 'core_FeaturedComments'] ],
|
||||
],
|
||||
[
|
||||
'table' => 'core_content_featured',
|
||||
'pkey' => 'feature_id',
|
||||
'date' => 'feature_date',
|
||||
'where' => [],
|
||||
],
|
||||
[
|
||||
'table' => 'core_social_promote',
|
||||
'pkey' => 'promote_id',
|
||||
'date' => 'promote_added',
|
||||
'where' => [],
|
||||
] ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the rebuild row
|
||||
*
|
||||
* @param array $row Row from database
|
||||
* @param array $data Data collected when starting rebuild [table, pkey...]
|
||||
* @return void
|
||||
*/
|
||||
public static function rebuildRow( $row, $data )
|
||||
{
|
||||
switch ( $data['table'] )
|
||||
{
|
||||
case 'core_content_meta':
|
||||
$metaData = json_decode( $row['meta_data'], TRUE );
|
||||
$commentClass = $row['meta_class']::$commentClass;
|
||||
$comment = $commentClass::load( $metaData['comment'] );
|
||||
$comment->author()->achievementAction( 'core', 'ContentPromotion', [
|
||||
'content' => $comment,
|
||||
'promotype' => 'recommend'
|
||||
] );
|
||||
break;
|
||||
case 'core_content_featured':
|
||||
$class = $row['feature_content_class'];
|
||||
$item = $class::load( $row['feature_content_id'] );
|
||||
$item->author()->achievementAction( 'core', 'ContentPromotion', [
|
||||
'content' => $item,
|
||||
'promotype' => 'feature'
|
||||
] );
|
||||
break;
|
||||
case 'core_social_promote':
|
||||
$promote = \IPS\core\Promote::load( $row['promote_id'] );
|
||||
$promote->author()->achievementAction( 'core', 'ContentPromotion', [
|
||||
'content' => $promote->object(),
|
||||
'promotype' => 'promote'
|
||||
] );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the data based on the things.
|
||||
*
|
||||
* @param $select
|
||||
* @param $filters
|
||||
* @param $type
|
||||
* @param null $subject
|
||||
* @param null $time
|
||||
* @param null|boolean $order
|
||||
* @param null $limit
|
||||
* @return \IPS\Db\Select
|
||||
*/
|
||||
protected function getQuery( $select, $filters, $type, $subject=NULL, $lastId=NULL, $time=NULL, $order=NULL, $limit=NULL )
|
||||
{
|
||||
$itemClass = $filters['type'];
|
||||
|
||||
if ( isset( $itemClass::$databaseColumnMap['hidden'] ) )
|
||||
{
|
||||
$subWhere = [ [ $itemClass::$databaseColumnMap['hidden'] . '=0' ] ];
|
||||
}
|
||||
elseif ( isset( $itemClass::$databaseColumnMap['approved'] ) )
|
||||
{
|
||||
$subWhere = [ [ $itemClass::$databaseColumnMap['approved'] . '=1' ] ];
|
||||
}
|
||||
|
||||
/* Recommended (but really called featured in the code just to confuse me) */
|
||||
if ( $type === 'recommend' )
|
||||
{
|
||||
if ( $subject )
|
||||
{
|
||||
$where = [
|
||||
['meta_item_author=? and meta_type=?', $subject->member_id, 'core_FeaturedComments'],
|
||||
];
|
||||
}
|
||||
else
|
||||
{
|
||||
$where = [
|
||||
['meta_type=?', 'core_FeaturedComments'],
|
||||
];
|
||||
}
|
||||
|
||||
if ( $time )
|
||||
{
|
||||
$where[] = [ 'meta_added >= ' . $time->getTimestamp() ];
|
||||
}
|
||||
|
||||
if ( $lastId )
|
||||
{
|
||||
$where[] = [ 'meta_id > ' . $lastId ];
|
||||
}
|
||||
|
||||
if ( $order )
|
||||
{
|
||||
$order = 'meta_id ASC';
|
||||
}
|
||||
|
||||
if ( isset( $filters['type'] ) )
|
||||
{
|
||||
$where[] = [ 'meta_class=?', $filters['type'] ];
|
||||
|
||||
if ( isset( $filters[ 'nodes_' . str_replace( '\\', '-', $itemClass ) ] ) )
|
||||
{
|
||||
$subWhere[] = [ \IPS\Db::i()->in( 'forum_id', $filters[ 'nodes_' . str_replace( '\\', '-', $itemClass ) ] ) ];
|
||||
}
|
||||
|
||||
$where[] = [ 'meta_item_id IN(?)', \IPS\Db::i()->select( $itemClass::$databaseColumnId, $itemClass::$databasePrefix . $itemClass::$databaseTable, $subWhere ) ];
|
||||
}
|
||||
|
||||
$query = \IPS\Db::i()->select( $select, 'core_content_meta', $where );
|
||||
}
|
||||
else if ( $type === 'feature' )
|
||||
{
|
||||
if ( $subject )
|
||||
{
|
||||
$where = [
|
||||
['feature_content_author=?', $subject->member_id],
|
||||
];
|
||||
}
|
||||
|
||||
if ( $time )
|
||||
{
|
||||
$where[] = [ 'feature_date >= ' . $time->getTimestamp() ];
|
||||
}
|
||||
|
||||
if ( $lastId )
|
||||
{
|
||||
$where[] = [ 'feature_id > ' . $lastId ];
|
||||
}
|
||||
|
||||
if ( $order )
|
||||
{
|
||||
$order = 'feature_id ASC';
|
||||
}
|
||||
|
||||
if ( isset( $filters['type'] ) )
|
||||
{
|
||||
$where[] = [ 'feature_content_class=?', $filters['type'] ];
|
||||
|
||||
if ( isset( $filters[ 'nodes_' . str_replace( '\\', '-', $itemClass ) ] ) )
|
||||
{
|
||||
$subWhere[] = [ \IPS\Db::i()->in( 'forum_id', $filters[ 'nodes_' . str_replace( '\\', '-', $itemClass ) ] ) ];
|
||||
}
|
||||
|
||||
$where[] = [ 'feature_content_id IN(?)', \IPS\Db::i()->select( $itemClass::$databaseColumnId, $itemClass::$databasePrefix . $itemClass::$databaseTable, $subWhere ) ];
|
||||
}
|
||||
|
||||
$query = \IPS\Db::i()->select( $select, 'core_content_featured', $where );
|
||||
}
|
||||
else if ( $type === 'promote' )
|
||||
{
|
||||
if ( $subject )
|
||||
{
|
||||
$where = [
|
||||
['promote_author_id=?', $subject->member_id],
|
||||
];
|
||||
}
|
||||
|
||||
if ( $time )
|
||||
{
|
||||
$where[] = [ 'promote_added >= ' . $time->getTimestamp() ];
|
||||
}
|
||||
|
||||
if ( $lastId )
|
||||
{
|
||||
$where[] = [ 'promote_id > ' . $lastId ];
|
||||
}
|
||||
|
||||
if ( $order )
|
||||
{
|
||||
$order = 'promote_id ASC';
|
||||
}
|
||||
|
||||
if ( isset( $filters['type'] ) )
|
||||
{
|
||||
$where[] = [ 'promote_hide=0 and promote_class=?', $filters['type'] ];
|
||||
|
||||
if ( isset( $filters[ 'nodes_' . str_replace( '\\', '-', $itemClass ) ] ) )
|
||||
{
|
||||
$subWhere[] = [ \IPS\Db::i()->in( 'forum_id', $filters[ 'nodes_' . str_replace( '\\', '-', $itemClass ) ] ) ];
|
||||
}
|
||||
|
||||
$where[] = [ 'promote_class_id IN(?)', \IPS\Db::i()->select( $itemClass::$databaseColumnId, $itemClass::$databasePrefix . $itemClass::$databaseTable, $subWhere ) ];
|
||||
}
|
||||
|
||||
$query = \IPS\Db::i()->select( $select, 'core_social_promote', $where, $order, $limit );
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,259 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Achievement Action 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 04 Mar 2021
|
||||
*/
|
||||
|
||||
namespace IPS\core\extensions\core\AchievementAction;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Achievement Action Extension
|
||||
*/
|
||||
class _FollowContentItem extends \IPS\core\Achievements\Actions\AbstractContentAchievementAction
|
||||
{
|
||||
/**
|
||||
* Get filter form elements
|
||||
*
|
||||
* @param array|NULL $filters Current filter values (if editing)
|
||||
* @param \IPS\Http\Url $url The URL the form is being shown on
|
||||
* @return array
|
||||
*/
|
||||
public function filters( ?array $filters, \IPS\Http\Url $url ): array
|
||||
{
|
||||
$filters = parent::filters( $filters, $url );
|
||||
|
||||
foreach( $filters['type']->options['options'] as $class => $value )
|
||||
{
|
||||
if ( ! \in_array( 'IPS\Content\Followable', class_implements( $class, TRUE ) ) )
|
||||
{
|
||||
unset( $filters['type']->options['options'][ $class ] );
|
||||
unset( $filters['nodes_' . str_replace( '\\', '-', $class ) ] );
|
||||
}
|
||||
}
|
||||
|
||||
return $filters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Work out if the filters applies for a given action
|
||||
*
|
||||
* Important note for milestones: consider the context. This method is called by \IPS\Member::achievementAction(). If your code
|
||||
* calls that BEFORE making its change in the database (or there is read/write separation), you will need to add
|
||||
* 1 to the value being considered for milestones
|
||||
*
|
||||
* @param \IPS\Member $subject The subject member
|
||||
* @param array $filters The value returned by formatFilterValues()
|
||||
* @param mixed $extra Any additional information about what is happening (e.g. if a post is being made: the post object)
|
||||
* @return bool
|
||||
*/
|
||||
public function filtersMatch( \IPS\Member $subject, array $filters, $extra = NULL ): bool
|
||||
{
|
||||
/* The parent already matches content type and node, so do that first */
|
||||
if( !parent::filtersMatch( $subject, $filters, $extra['item'] ) )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ( isset( $filters['milestone'] ) )
|
||||
{
|
||||
$query = $this->getQuery( 'COUNT(*)', [ [ 'follow_member_id=?', $subject->member_id ] ], NULL, NULL, $filters );
|
||||
|
||||
if ( $query->first() < $filters['milestone'] )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the labels for the people this action might give awards to
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function awardOptions(): array
|
||||
{
|
||||
return [
|
||||
'subject' => 'achievement_filter_FollowContentItem_follower',
|
||||
'other' => 'achievement_filter_FollowContentItem_author'
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the "other" people we need to award =stuff to
|
||||
*
|
||||
* @param mixed $extra Any additional information about what is happening (e.g. if a post is being made: the post object)
|
||||
* @return array
|
||||
*/
|
||||
public function awardOther( $extra = NULL ): array
|
||||
{
|
||||
return [ $extra['author'] ];
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @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)
|
||||
* @return string
|
||||
*/
|
||||
public function identifier( \IPS\Member $subject, $extra = NULL ): string
|
||||
{
|
||||
return \get_class( $extra['item'] ) . ':' . $extra['item']->{$extra['item']::$databaseColumnId} . ':' . $subject->member_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a description for this action to show in the log
|
||||
*
|
||||
* @param string $identifier The identifier as returned by identifier()
|
||||
* @param array $actor If the member was the "subject", "other", or both
|
||||
* @return string
|
||||
*/
|
||||
public function logRow( string $identifier, array $actor ): string
|
||||
{
|
||||
$exploded = explode( ':', $identifier );
|
||||
|
||||
$sprintf = [];
|
||||
try
|
||||
{
|
||||
$item = $exploded[0]::load( $exploded[1] );
|
||||
$sprintf = [ 'htmlsprintf' => [
|
||||
\IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->basicUrl( $item->url(), TRUE, $item->mapped('title') ?: $item->indefiniteArticle(), FALSE )
|
||||
] ];
|
||||
}
|
||||
catch ( \OutOfRangeException $e )
|
||||
{
|
||||
$sprintf = [ 'sprintf' => [ \IPS\Member::loggedIn()->language()->addToStack('modcp_deleted') ] ];
|
||||
}
|
||||
|
||||
return \IPS\Member::loggedIn()->language()->addToStack( 'AchievementAction__FollowContentItem_log', FALSE, $sprintf );
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get "description" for rule
|
||||
*
|
||||
* @param \IPS\core\Achievements\Rule $rule The rule
|
||||
* @return string|NULL
|
||||
*/
|
||||
public function ruleDescription( \IPS\core\Achievements\Rule $rule ): ?string
|
||||
{
|
||||
$type = $rule->filters['type'] ?? NULL;
|
||||
|
||||
$conditions = [];
|
||||
if ( isset( $rule->filters['milestone'] ) )
|
||||
{
|
||||
$conditions[] = \IPS\Member::loggedIn()->language()->addToStack( 'achievements_title_filter_milestone', FALSE, [
|
||||
'htmlsprintf' => [
|
||||
\IPS\Theme::i()->getTemplate( 'achievements' )->ruleDescriptionBadge( 'milestone', \IPS\Member::loggedIn()->language()->addToStack( 'achievements_title_filter_milestone_nth', FALSE, [ 'pluralize' => [ $rule->filters['milestone'] ] ] ) )
|
||||
],
|
||||
'sprintf' => [ $type ? \IPS\Member::loggedIn()->language()->addToStack( $type::$title, FALSE, [ 'strtolower' => TRUE ] ) : \IPS\Member::loggedIn()->language()->addToStack('AchievementAction__NewContentItem_title_generic') ]
|
||||
] );
|
||||
}
|
||||
if ( $nodeCondition = $this->_nodeFilterDescription( $rule ) )
|
||||
{
|
||||
$conditions[] = $nodeCondition;
|
||||
}
|
||||
|
||||
return \IPS\Theme::i()->getTemplate( 'achievements' )->ruleDescription(
|
||||
$type ? \IPS\Member::loggedIn()->language()->addToStack( 'AchievementAction__FollowContentItem_title_t', FALSE, [ 'sprintf' => [ \IPS\Member::loggedIn()->language()->addToStack( $type::$title ) ] ] ) : \IPS\Member::loggedIn()->language()->addToStack( 'AchievementAction__FollowContentItem_title' ),
|
||||
$conditions
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get rebuild data
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
static public function rebuildData()
|
||||
{
|
||||
return [ [
|
||||
'table' => 'core_follow',
|
||||
'pkey' => 'follow_id',
|
||||
'date' => 'follow_added',
|
||||
'where' => [ [ '(follow_app !=? and follow_area !=?)', 'core', 'member' ] ],
|
||||
] ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the rebuild row
|
||||
*
|
||||
* @param array $row Row from database
|
||||
* @param array $data Data collected when starting rebuild [table, pkey...]
|
||||
* @return void
|
||||
*/
|
||||
public static function rebuildRow( $row, $data )
|
||||
{
|
||||
$className = 'IPS\\' . $row['follow_app'] . '\\' . mb_ucfirst( $row['follow_area'] );
|
||||
|
||||
if ( \in_array( 'IPS\Content\Item', class_parents( $className ) ) )
|
||||
{
|
||||
$item = $className::load( $row['follow_rel_id'] );
|
||||
\IPS\Member::load( $row['follow_member_id'] )->achievementAction( 'core', 'FollowContentItem', [
|
||||
'item' => $item,
|
||||
'author' => $item->author()
|
||||
] );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a query to use for multiple methods within this extension
|
||||
* @param string $select Select for the query
|
||||
* @param array|NULL $where Where for the query
|
||||
* @param int|NULL $limit Limit for the query
|
||||
* @param string|NULL $order Order by for the query
|
||||
* @param array $filters Rule filters
|
||||
* @return \IPS\Db\Select
|
||||
*/
|
||||
public function getQuery( $select, $where, $limit, $order, $filters ): \IPS\Db\Select
|
||||
{
|
||||
$joinContainers = FALSE;
|
||||
$extraJoinCondition = NULL;
|
||||
$where = \is_array( $where ) ? $where : array();
|
||||
|
||||
/* Limit by type and node */
|
||||
if ( isset( $filters['type'] ) )
|
||||
{
|
||||
list( $ns, $app, $area ) = explode( '\\', $filters['type'] );
|
||||
$where[] = [ 'follow_app=? and follow_area=?', \mb_strtolower( $app ), \mb_strtolower( $area ) ];
|
||||
|
||||
$itemClass = $filters['type'];
|
||||
if ( \in_array( 'IPS\Content\Comment', class_parents( $filters['type'] ) ) )
|
||||
{
|
||||
$itemClass = $filters['type']::$itemClass;
|
||||
}
|
||||
|
||||
if ( isset( $filters['nodes_' . str_replace( '\\', '-', $itemClass )] ) )
|
||||
{
|
||||
$joinContainers = TRUE;
|
||||
$extraJoinCondition = ' AND ' . \IPS\Db::i()->in( $itemClass::$databaseTable . '.' . $itemClass::$databaseColumnMap['container'], $filters['nodes_' . str_replace( '\\', '-', $itemClass )] );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$where[] = [ '(follow_app !=? and follow_area !=?)', 'core', 'member' ];
|
||||
}
|
||||
|
||||
$query = \IPS\Db::i()->select( $select, 'core_follow', $where, $order, $limit );
|
||||
|
||||
if ( $joinContainers )
|
||||
{
|
||||
$query->join( $itemClass::$databaseTable, 'core_follow.follow_rel_id=' . $itemClass::$databaseTable . '.' . $itemClass::$databasePrefix . $itemClass::$databaseColumnId . $extraJoinCondition, 'INNER' );
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,215 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Achievement Action 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 03 Mar 2021
|
||||
*/
|
||||
|
||||
namespace IPS\core\extensions\core\AchievementAction;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Achievement Action Extension
|
||||
*/
|
||||
class _FollowMember extends \IPS\core\Achievements\Actions\AbstractAchievementAction
|
||||
{
|
||||
/**
|
||||
* Get filter form elements
|
||||
*
|
||||
* @param array|NULL $filters Current filter values (if editing)
|
||||
* @param \IPS\Http\Url $url The URL the form is being shown on
|
||||
* @return array
|
||||
*/
|
||||
public function filters( ?array $filters, \IPS\Http\Url $url ): array
|
||||
{
|
||||
$nthFilter = new \IPS\Helpers\Form\Number( 'achievement_filter_FollowMember_nth', ( $filters and isset( $filters['milestone'] ) and $filters['milestone'] ) ? $filters['milestone'] : 0, FALSE, [], NULL, \IPS\Member::loggedIn()->language()->addToStack('achievement_filter_nth_their'), \IPS\Member::loggedIn()->language()->addToStack('achievement_filter_FollowMember_nth_suffix') );
|
||||
$nthFilter->label = \IPS\Member::loggedIn()->language()->addToStack('achievement_filter_NewClub_nth');
|
||||
|
||||
$return = array();
|
||||
|
||||
$return['milestone'] = $nthFilter;
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format filter form values
|
||||
*
|
||||
* @param array $values The values from the form
|
||||
* @return array
|
||||
*/
|
||||
public function formatFilterValues( array $values ): array
|
||||
{
|
||||
$return = [];
|
||||
|
||||
if ( isset( $values['achievement_filter_FollowMember_nth'] ) )
|
||||
{
|
||||
$return['milestone'] = $values['achievement_filter_FollowMember_nth'];
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Work out if the filters applies for a given action
|
||||
*
|
||||
* Important note for milestones: consider the context. This method is called by \IPS\Member::achievementAction(). If your code
|
||||
* calls that BEFORE making its change in the database (or there is read/write separation), you will need to add
|
||||
* 1 to the value being considered for milestones
|
||||
*
|
||||
* @param \IPS\Member $subject The subject member
|
||||
* @param array $filters The value returned by formatFilterValues()
|
||||
* @param mixed $extra Any additional information about what is happening (e.g. if a post is being made: the post object)
|
||||
* @return bool
|
||||
*/
|
||||
public function filtersMatch( \IPS\Member $subject, array $filters, $extra = NULL ): bool
|
||||
{
|
||||
if ( isset( $filters['milestone'] ) )
|
||||
{
|
||||
$where = [];
|
||||
$where[] = [ 'follow_app=? and follow_area=? and follow_member_id=?', 'core', 'member', $subject->member_id ];
|
||||
|
||||
$count = \IPS\Db::i()->select( 'COUNT(*)', 'core_follow', $where )->first();
|
||||
|
||||
if ( $count < $filters['milestone'] )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the labels for the people this action might give awards to
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function awardOptions(): array
|
||||
{
|
||||
return [
|
||||
'subject' => 'achievement_filter_FollowMember_receiver',
|
||||
'other' => 'achievement_filter_FollowMember_giver'
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the "other" people we need to award =stuff to
|
||||
*
|
||||
* @param mixed $extra Any additional information about what is happening (e.g. if a post is being made: the post object)
|
||||
* @return array
|
||||
*/
|
||||
public function awardOther( $extra = NULL ): array
|
||||
{
|
||||
return [ $extra['giver'] ];
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @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)
|
||||
* @return string
|
||||
*/
|
||||
public function identifier( \IPS\Member $subject, $extra = NULL ): string
|
||||
{
|
||||
return $subject->member_id . ':' . $extra['giver']->member_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a description for this action to show in the log
|
||||
*
|
||||
* @param string $identifier The identifier as returned by identifier()
|
||||
* @param array $actor If the member was the "subject", "other", or both
|
||||
* @return string
|
||||
*/
|
||||
public function logRow( string $identifier, array $actor ): string
|
||||
{
|
||||
$exploded = explode( ':', $identifier );
|
||||
|
||||
$reactionName = \IPS\Member::loggedIn()->language()->addToStack('unknown');
|
||||
$receivedLink = \IPS\Member::loggedIn()->language()->addToStack('modcp_deleted');
|
||||
$giverLink = \IPS\Member::loggedIn()->language()->addToStack('modcp_deleted');
|
||||
try
|
||||
{
|
||||
$giver = \IPS\Member::load( $exploded[0] );
|
||||
$received = \IPS\Member::load( $exploded[1] );
|
||||
$receivedLink = \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->basicUrl( $received->url(), TRUE, $received->name, FALSE );
|
||||
$giverLink = \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->basicUrl( $giver->url(), TRUE, $giver->name, FALSE );
|
||||
}
|
||||
catch ( \OutOfRangeException $e ) { }
|
||||
|
||||
if ( \in_array( 'subject', $actor ) )
|
||||
{
|
||||
return \IPS\Member::loggedIn()->language()->addToStack( 'AchievementAction__FollowMember_log_subject', FALSE, [ 'htmlsprintf' => [ $receivedLink ] ] );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
return \IPS\Member::loggedIn()->language()->addToStack( 'AchievementAction__FollowMember_log_other', FALSE, [ 'htmlsprintf' => [ $giverLink ] ] );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get "description" for rule
|
||||
*
|
||||
* @param \IPS\core\Achievements\Rule $rule The rule
|
||||
* @return string|NULL
|
||||
*/
|
||||
public function ruleDescription( \IPS\core\Achievements\Rule $rule ): ?string
|
||||
{
|
||||
$conditions = [];
|
||||
if ( isset( $rule->filters['milestone'] ) )
|
||||
{
|
||||
$conditions[] = \IPS\Member::loggedIn()->language()->addToStack( 'achievements_title_filter_milestone', FALSE, [
|
||||
'htmlsprintf' => [
|
||||
\IPS\Theme::i()->getTemplate( 'achievements' )->ruleDescriptionBadge( 'milestone', \IPS\Member::loggedIn()->language()->addToStack( 'achievements_title_filter_milestone_nth', FALSE, [ 'pluralize' => [ $rule->filters['milestone'] ] ] ) )
|
||||
],
|
||||
'sprintf' => \IPS\Member::loggedIn()->language()->addToStack('AchievementAction__FollowMember_title_generic')
|
||||
] );
|
||||
}
|
||||
|
||||
return \IPS\Theme::i()->getTemplate( 'achievements' )->ruleDescription(
|
||||
\IPS\Member::loggedIn()->language()->addToStack( 'AchievementAction__FollowMember_title' ),
|
||||
$conditions
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get rebuild data
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
static public function rebuildData()
|
||||
{
|
||||
return [ [
|
||||
'table' => 'core_follow',
|
||||
'pkey' => 'follow_id',
|
||||
'date' => 'follow_added',
|
||||
'where' => [ ['follow_app=? and follow_area=?', 'core', 'member' ] ],
|
||||
] ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the rebuild row
|
||||
*
|
||||
* @param array $row Row from database
|
||||
* @param array $data Data collected when starting rebuild [table, pkey...]
|
||||
* @return void
|
||||
*/
|
||||
public static function rebuildRow( $row, $data )
|
||||
{
|
||||
$receiver = \IPS\Member::load( $row['follow_rel_id'] );
|
||||
$receiver->achievementAction( 'core', 'FollowMember', [
|
||||
'giver' => \IPS\Member::load( $row['follow_member_id'] )
|
||||
] );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Achievement Action 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 04 Mar 2021
|
||||
*/
|
||||
|
||||
namespace IPS\core\extensions\core\AchievementAction;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Achievement Action Extension
|
||||
*/
|
||||
class _FollowNode extends \IPS\core\Achievements\Actions\AbstractNodeAchievementAction
|
||||
{
|
||||
/**
|
||||
* Get filter form elements
|
||||
*
|
||||
* @param array|NULL $filters Current filter values (if editing)
|
||||
* @param \IPS\Http\Url $url The URL the form is being shown on
|
||||
* @return array
|
||||
*/
|
||||
public function filters( ?array $filters, \IPS\Http\Url $url ): array
|
||||
{
|
||||
$filters = parent::filters( $filters, $url );
|
||||
|
||||
foreach( $filters['type']->options['options'] as $class => $value )
|
||||
{
|
||||
if ( isset( $class::$contentItemClass ) and ! \in_array( 'IPS\Content\Followable', class_implements( $class::$contentItemClass ) ) )
|
||||
{
|
||||
unset( $filters['type']->options['options'][ $class ] );
|
||||
unset( $filters['nodes_' . str_replace( '\\', '-', $class ) ] );
|
||||
}
|
||||
}
|
||||
|
||||
return $filters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a description for this action to show in the log
|
||||
*
|
||||
* @param string $identifier The identifier as returned by identifier()
|
||||
* @param array $actor If the member was the "subject", "other", or both
|
||||
* @return string
|
||||
*/
|
||||
public function logRow( string $identifier, array $actor ): string
|
||||
{
|
||||
$exploded = explode( ':', $identifier );
|
||||
|
||||
$sprintf = [];
|
||||
try
|
||||
{
|
||||
$node = $exploded[0]::load( $exploded[1] );
|
||||
$sprintf = [ 'htmlsprintf' => [
|
||||
\IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->basicUrl( $node->url(), TRUE, $node->_title, FALSE )
|
||||
] ];
|
||||
}
|
||||
catch ( \OutOfRangeException $e )
|
||||
{
|
||||
$sprintf = [ 'sprintf' => [ \IPS\Member::loggedIn()->language()->addToStack('modcp_deleted') ] ];
|
||||
}
|
||||
|
||||
return \IPS\Member::loggedIn()->language()->addToStack( 'AchievementAction__FollowNode_log', FALSE, $sprintf );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get "description" for rule
|
||||
*
|
||||
* @param \IPS\core\Achievements\Rule $rule The rule
|
||||
* @return string|NULL
|
||||
*/
|
||||
public function ruleDescription( \IPS\core\Achievements\Rule $rule ): ?string
|
||||
{
|
||||
$type = $rule->filters['type'] ?? NULL;
|
||||
|
||||
$conditions = [];
|
||||
if ( isset( $rule->filters['milestone'] ) )
|
||||
{
|
||||
$conditions[] = \IPS\Member::loggedIn()->language()->addToStack( 'achievements_title_filter_milestone', FALSE, [
|
||||
'htmlsprintf' => [
|
||||
\IPS\Theme::i()->getTemplate( 'achievements' )->ruleDescriptionBadge( 'milestone', \IPS\Member::loggedIn()->language()->addToStack( 'achievements_title_filter_milestone_nth', FALSE, [ 'pluralize' => [ $rule->filters['milestone'] ] ] ) )
|
||||
],
|
||||
'sprintf' => [ $type ? \IPS\Member::loggedIn()->language()->addToStack( $type::fullyQualifiedType(), FALSE, [ 'strtolower' => TRUE ] ) : \IPS\Member::loggedIn()->language()->addToStack('AchievementAction__NewContentItem_title_generic') ]
|
||||
] );
|
||||
}
|
||||
if ( $nodeCondition = $this->_nodeFilterDescription( $rule ) )
|
||||
{
|
||||
$conditions[] = $nodeCondition;
|
||||
}
|
||||
|
||||
return \IPS\Theme::i()->getTemplate( 'achievements' )->ruleDescription(
|
||||
$type ? \IPS\Member::loggedIn()->language()->addToStack( 'AchievementAction__FollowNode_title_t', FALSE, [ 'sprintf' => [ \IPS\Member::loggedIn()->language()->addToStack( $type::fullyQualifiedType() ) ] ] ) : \IPS\Member::loggedIn()->language()->addToStack( 'AchievementAction__FollowNode_title' ),
|
||||
$conditions
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get rebuild data
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
static public function rebuildData()
|
||||
{
|
||||
return [ [
|
||||
'table' => 'core_follow',
|
||||
'pkey' => 'follow_id',
|
||||
'date' => 'follow_added',
|
||||
'where' => [ [ '(follow_app !=? and follow_area !=?)', 'core', 'member' ] ],
|
||||
] ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the rebuild row
|
||||
*
|
||||
* @param array $row Row from database
|
||||
* @param array $data Data collected when starting rebuild [table, pkey...]
|
||||
* @return void
|
||||
*/
|
||||
public static function rebuildRow( $row, $data )
|
||||
{
|
||||
$class = 'IPS\\' . $row['follow_app'] . '\\' . mb_ucfirst( $row['follow_area'] );
|
||||
if ( \in_array( 'IPS\Node\Model', class_parents( $class ) ) )
|
||||
{
|
||||
\IPS\Member::load( $row['follow_member_id'] )->achievementAction( 'core', 'FollowNode', $class::load( $row['follow_rel_id'] ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,206 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Achievement Action 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 04 Mar 2021
|
||||
*/
|
||||
|
||||
namespace IPS\core\extensions\core\AchievementAction;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Achievement Action Extension
|
||||
*/
|
||||
class _JoinClub extends \IPS\core\Achievements\Actions\AbstractAchievementAction // NOTE: Other classes exist to provided bases for common situations, like where node-based filters will be required
|
||||
{
|
||||
/**
|
||||
* Can use this rule?
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function canUse(): bool
|
||||
{
|
||||
return (bool) parent::canUse() and \IPS\Settings::i()->clubs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get filter form elements
|
||||
*
|
||||
* @param array|NULL $filters Current filter values (if editing)
|
||||
* @param \IPS\Http\Url $url The URL the form is being shown on
|
||||
* @return array
|
||||
*/
|
||||
public function filters( ?array $filters, \IPS\Http\Url $url ): array
|
||||
{
|
||||
$nthFilter = new \IPS\Helpers\Form\Number( 'achievement_filter_club_joined_nth', ( $filters and isset( $filters['milestone'] ) and $filters['milestone'] ) ? $filters['milestone'] : 0, FALSE, [], NULL, \IPS\Member::loggedIn()->language()->addToStack('achievement_filter_nth_their'), \IPS\Member::loggedIn()->language()->addToStack('achievement_filter_JoinClub_nth_suffix') );
|
||||
$nthFilter->label = \IPS\Member::loggedIn()->language()->addToStack('achievement_filter_JoinClub_nth');
|
||||
|
||||
$return = array();
|
||||
|
||||
$return['milestone'] = $nthFilter;
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format filter form values
|
||||
*
|
||||
* @param array $values The values from the form
|
||||
* @return array
|
||||
*/
|
||||
public function formatFilterValues( array $values ): array
|
||||
{
|
||||
$return = [];
|
||||
|
||||
if ( isset( $values['achievement_filter_club_joined_nth'] ) )
|
||||
{
|
||||
$return['milestone'] = $values['achievement_filter_club_joined_nth'];
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Work out if the filters applies for a given action
|
||||
*
|
||||
* Important note for milestones: consider the context. This method is called by \IPS\Member::achievementAction(). If your code
|
||||
* calls that BEFORE making its change in the database (or there is read/write separation), you will need to add
|
||||
* 1 to the value being considered for milestones
|
||||
*
|
||||
* @param \IPS\Member $subject The subject member
|
||||
* @param array $filters The value returned by formatFilterValues()
|
||||
* @param mixed $extra Any additional information about what is happening (e.g. if a post is being made: the post object)
|
||||
* @return bool
|
||||
*/
|
||||
public function filtersMatch( \IPS\Member $subject, array $filters, $extra = NULL ): bool
|
||||
{
|
||||
if ( isset( $filters['milestone'] ) )
|
||||
{
|
||||
$where = [];
|
||||
$where[] = [ "member_id=? and status IN('" . \IPS\Member\Club::STATUS_MEMBER . "','" . \IPS\Member\Club::STATUS_MODERATOR . "','" . \IPS\Member\Club::STATUS_LEADER . "','" . \IPS\Member\Club::STATUS_EXPIRED . "','" . \IPS\Member\Club::STATUS_EXPIRED_MODERATOR . "')", $subject->member_id ];
|
||||
|
||||
$count = \IPS\Db::i()->select( 'COUNT(*)', 'core_clubs_memberships', $where )->first();
|
||||
|
||||
if ( $count < $filters['milestone'] )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the labels for the people this action might give awards to
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function awardOptions(): array
|
||||
{
|
||||
return [
|
||||
'subject' => 'achievement_filter_JoinClub_joiner',
|
||||
'other' => 'achievement_filter_JoinClub_owner'
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the "other" people we need to award =stuff to
|
||||
*
|
||||
* @param mixed $extra Any additional information about what is happening (e.g. if a post is being made: the post object)
|
||||
* @return array
|
||||
*/
|
||||
public function awardOther( $extra = NULL ): array
|
||||
{
|
||||
return [ $extra->owner ];
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @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)
|
||||
* @return string
|
||||
*/
|
||||
public function identifier( \IPS\Member $subject, $extra = NULL ): string
|
||||
{
|
||||
return (string) $extra->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a description for this action to show in the log
|
||||
*
|
||||
* @param string $identifier The identifier as returned by identifier()
|
||||
* @param array $actor If the member was the "subject", "other", or both
|
||||
* @return string
|
||||
*/
|
||||
public function logRow( string $identifier, array $actor ): string
|
||||
{
|
||||
$club = \IPS\Member\Club::load( $identifier );
|
||||
$clubLink = \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->basicUrl( $club->url(), TRUE, $club->name, FALSE );
|
||||
|
||||
return \IPS\Member::loggedIn()->language()->addToStack( 'AchievementAction__JoinClub_log', FALSE, [ 'htmlsprintf' => [ $clubLink ] ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get "description" for rule
|
||||
*
|
||||
* @param \IPS\core\Achievements\Rule $rule The rule
|
||||
* @return string|NULL
|
||||
*/
|
||||
public function ruleDescription( \IPS\core\Achievements\Rule $rule ): ?string
|
||||
{
|
||||
$conditions = [];
|
||||
if ( isset( $rule->filters['milestone'] ) )
|
||||
{
|
||||
$conditions[] = \IPS\Member::loggedIn()->language()->addToStack( 'achievements_title_filter_milestone', FALSE, [
|
||||
'htmlsprintf' => [
|
||||
\IPS\Theme::i()->getTemplate( 'achievements' )->ruleDescriptionBadge( 'milestone', \IPS\Member::loggedIn()->language()->addToStack( 'achievements_title_filter_milestone_nth', FALSE, [ 'pluralize' => [ $rule->filters['milestone'] ] ] ) )
|
||||
],
|
||||
'sprintf' => [ \IPS\Member::loggedIn()->language()->addToStack('AchievementAction__JoinClub_title_generic') ]
|
||||
] );
|
||||
}
|
||||
|
||||
return \IPS\Theme::i()->getTemplate( 'achievements' )->ruleDescription(
|
||||
\IPS\Member::loggedIn()->language()->addToStack( 'AchievementAction__JoinClub_title' ),
|
||||
$conditions
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get rebuild data
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
static public function rebuildData()
|
||||
{
|
||||
return [ [
|
||||
'table' => 'core_clubs_memberships',
|
||||
'pkey' => 'club_id',
|
||||
'date' => 'joined',
|
||||
'where' => [],
|
||||
] ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the rebuild row
|
||||
*
|
||||
* @param array $row Row from database
|
||||
* @param array $data Data collected when starting rebuild [table, pkey...]
|
||||
* @return void
|
||||
*/
|
||||
public static function rebuildRow( $row, $data )
|
||||
{
|
||||
if ( \in_array( $row['status'], array( \IPS\Member\Club::STATUS_MEMBER, \IPS\Member\Club::STATUS_MODERATOR, \IPS\Member\Club::STATUS_LEADER, \IPS\Member\Club::STATUS_EXPIRED, \IPS\Member\Club::STATUS_EXPIRED_MODERATOR ) ) )
|
||||
{
|
||||
\IPS\Member::load( $row['member_id'] )->achievementAction( 'core', 'JoinClub', \IPS\Member\Club::load( $row['club_id'] ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Achievement Action 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 03 Mar 2021
|
||||
*/
|
||||
|
||||
namespace IPS\core\extensions\core\AchievementAction;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Achievement Action Extension
|
||||
*/
|
||||
class _NewClub extends \IPS\core\Achievements\Actions\AbstractAchievementAction // NOTE: Other classes exist to provided bases for common situations, like where node-based filters will be required
|
||||
{
|
||||
/**
|
||||
* Can use this rule?
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function canUse(): bool
|
||||
{
|
||||
return (bool) parent::canUse() and \IPS\Settings::i()->clubs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get filter form elements
|
||||
*
|
||||
* @param array|NULL $filters Current filter values (if editing)
|
||||
* @param \IPS\Http\Url $url The URL the form is being shown on
|
||||
* @return array
|
||||
*/
|
||||
public function filters( ?array $filters, \IPS\Http\Url $url ): array
|
||||
{
|
||||
$nthFilter = new \IPS\Helpers\Form\Number( 'achievement_filter_club_nth', ( $filters and isset( $filters['milestone'] ) and $filters['milestone'] ) ? $filters['milestone'] : 0, FALSE, [], NULL, \IPS\Member::loggedIn()->language()->addToStack('achievement_filter_nth_their'), \IPS\Member::loggedIn()->language()->addToStack('achievement_filter_NewClub_nth_suffix') );
|
||||
$nthFilter->label = \IPS\Member::loggedIn()->language()->addToStack('achievement_filter_NewClub_nth');
|
||||
|
||||
$return = array();
|
||||
|
||||
$return['milestone'] = $nthFilter;
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format filter form values
|
||||
*
|
||||
* @param array $values The values from the form
|
||||
* @return array
|
||||
*/
|
||||
public function formatFilterValues( array $values ): array
|
||||
{
|
||||
$return = [];
|
||||
|
||||
if ( isset( $values['achievement_filter_club_nth'] ) )
|
||||
{
|
||||
$return['milestone'] = $values['achievement_filter_club_nth'];
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Work out if the filters applies for a given action
|
||||
*
|
||||
* Important note for milestones: consider the context. This method is called by \IPS\Member::achievementAction(). If your code
|
||||
* calls that BEFORE making its change in the database (or there is read/write separation), you will need to add
|
||||
* 1 to the value being considered for milestones
|
||||
*
|
||||
* @param \IPS\Member $subject The subject member
|
||||
* @param array $filters The value returned by formatFilterValues()
|
||||
* @param mixed $extra Any additional information about what is happening (e.g. if a post is being made: the post object)
|
||||
* @return bool
|
||||
*/
|
||||
public function filtersMatch( \IPS\Member $subject, array $filters, $extra = NULL ): bool
|
||||
{
|
||||
if ( isset( $filters['milestone'] ) )
|
||||
{
|
||||
$where = [];
|
||||
$where[] = [ 'owner=? and approved=?', $subject->member_id, 1 ];
|
||||
|
||||
$count = \IPS\Db::i()->select( 'COUNT(*)', 'core_clubs', $where )->first();
|
||||
|
||||
if ( $count < $filters['milestone'] )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @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)
|
||||
* @return string
|
||||
*/
|
||||
public function identifier( \IPS\Member $subject, $extra = NULL ): string
|
||||
{
|
||||
return (string) $extra->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a description for this action to show in the log
|
||||
*
|
||||
* @param string $identifier The identifier as returned by identifier()
|
||||
* @param array $actor If the member was the "subject", "other", or both
|
||||
* @return string
|
||||
*/
|
||||
public function logRow( string $identifier, array $actor ): string
|
||||
{
|
||||
$club = \IPS\Member\Club::load( $identifier );
|
||||
$clubLink = \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->basicUrl( $club->url(), TRUE, $club->name, FALSE );
|
||||
|
||||
return \IPS\Member::loggedIn()->language()->addToStack( 'AchievementAction__NewClub_log', FALSE, [ 'htmlsprintf' => [ $clubLink ] ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get "description" for rule
|
||||
*
|
||||
* @param \IPS\core\Achievements\Rule $rule The rule
|
||||
* @return string|NULL
|
||||
*/
|
||||
public function ruleDescription( \IPS\core\Achievements\Rule $rule ): ?string
|
||||
{
|
||||
$conditions = [];
|
||||
if ( isset( $rule->filters['milestone'] ) )
|
||||
{
|
||||
$conditions[] = \IPS\Member::loggedIn()->language()->addToStack( 'achievements_title_filter_milestone', FALSE, [
|
||||
'htmlsprintf' => [
|
||||
\IPS\Theme::i()->getTemplate( 'achievements' )->ruleDescriptionBadge( 'milestone', \IPS\Member::loggedIn()->language()->addToStack( 'achievements_title_filter_milestone_nth', FALSE, [ 'pluralize' => [ $rule->filters['milestone'] ] ] ) )
|
||||
],
|
||||
'sprintf' => [ \IPS\Member::loggedIn()->language()->addToStack('AchievementAction__NewClub_title_generic') ]
|
||||
] );
|
||||
}
|
||||
|
||||
return \IPS\Theme::i()->getTemplate( 'achievements' )->ruleDescription(
|
||||
\IPS\Member::loggedIn()->language()->addToStack( 'AchievementAction__NewClub_title' ),
|
||||
$conditions
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get rebuild data
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
static public function rebuildData()
|
||||
{
|
||||
return [ [
|
||||
'table' => 'core_clubs',
|
||||
'pkey' => 'id',
|
||||
'date' => 'created',
|
||||
'where' => [ [ 'approved=1' ] ],
|
||||
] ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the rebuild row
|
||||
*
|
||||
* @param array $row Row from database
|
||||
* @param array $data Data collected when starting rebuild [table, pkey...]
|
||||
* @return void
|
||||
*/
|
||||
public static function rebuildRow( $row, $data )
|
||||
{
|
||||
\IPS\Member::load( $row['owner'] )->achievementAction( 'core', 'NewClub', \IPS\Member\Club::load( $row['id'] ) );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Achievement Action Extension: User posts new content item
|
||||
* @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 24 Feb 2021
|
||||
*/
|
||||
|
||||
namespace IPS\core\extensions\core\AchievementAction;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Achievement Action Extension: User posts new content item
|
||||
*/
|
||||
class _NewContentItem extends \IPS\core\Achievements\Actions\AbstractContentAchievementAction
|
||||
{
|
||||
protected static $includeComments = FALSE;
|
||||
protected static $includeReviews = FALSE;
|
||||
|
||||
/**
|
||||
* Work out if the filters applies for a given action
|
||||
*
|
||||
* Important note for milestones: consider the context. This method is called by \IPS\Member::achievementAction(). If your code
|
||||
* calls that BEFORE making its change in the database (or there is read/write separation), you will need to add
|
||||
* 1 to the value being considered for milestones
|
||||
*
|
||||
* @param \IPS\Member $subject The subject member
|
||||
* @param array $filters The value returned by formatFilterValues()
|
||||
* @param mixed $extra Any additional information about what is happening (e.g. if a post is being made: the post object)
|
||||
* @return bool
|
||||
*/
|
||||
public function filtersMatch( \IPS\Member $subject, array $filters, $extra = NULL ): bool
|
||||
{
|
||||
if ( !parent::filtersMatch( $subject, $filters, $extra ) )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ( isset( $filters['milestone'] ) )
|
||||
{
|
||||
$count = 0;
|
||||
$classes = [];
|
||||
if ( isset( $filters['type'] ) )
|
||||
{
|
||||
if ( isset( $filters[ 'nodes_' . str_replace( '\\', '-', $filters['type'] ) ] ) )
|
||||
{
|
||||
$class = $filters['type'];
|
||||
$where = [];
|
||||
$where[] = [ $class::$databasePrefix . $class::$databaseColumnMap['author'] . '=?', $subject->member_id ];
|
||||
$where[] = [ \IPS\Db::i()->in( $class::$databasePrefix . $class::$databaseColumnMap['container'], $filters[ 'nodes_' . str_replace( '\\', '-', $filters['type'] ) ] ) ];
|
||||
|
||||
$count += \IPS\Db::i()->select( 'COUNT(*)', $class::$databaseTable, $where )->first();
|
||||
}
|
||||
else
|
||||
{
|
||||
$classes[] = $filters['type'];
|
||||
}
|
||||
|
||||
foreach ( $classes as $class )
|
||||
{
|
||||
$count += $class::memberPostCount( $subject, TRUE, FALSE );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* It's too expensive to get a live count from every single item/comment class available to the suite
|
||||
so lets just use the post count here. It won't be quite as accurate but we're not a bank so whatever */
|
||||
$count = $subject->member_posts;
|
||||
}
|
||||
|
||||
if ( $count < $filters['milestone'] )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a description for this action to show in the log
|
||||
*
|
||||
* @param string $identifier The identifier as returned by identifier()
|
||||
* @param array $actor If the member was the "subject", "other", or both
|
||||
* @return string
|
||||
*/
|
||||
public function logRow( string $identifier, array $actor ): string
|
||||
{
|
||||
$exploded = explode( ':', $identifier );
|
||||
|
||||
$sprintf = [];
|
||||
try
|
||||
{
|
||||
$item = $exploded[0]::load( $exploded[1] );
|
||||
$sprintf = [ 'htmlsprintf' => [
|
||||
\IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->basicUrl( $item->url(), TRUE, $item->mapped('title') ?: $item->indefiniteArticle(), FALSE )
|
||||
] ];
|
||||
}
|
||||
catch ( \OutOfRangeException $e )
|
||||
{
|
||||
$sprintf = [ 'sprintf' => [ \IPS\Member::loggedIn()->language()->addToStack('modcp_deleted') ] ];
|
||||
}
|
||||
|
||||
return \IPS\Member::loggedIn()->language()->addToStack( 'AchievementAction__NewContentItem_log', FALSE, $sprintf );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get "description" for rule
|
||||
*
|
||||
* @param \IPS\core\Achievements\Rule $rule The rule
|
||||
* @return string|NULL
|
||||
*/
|
||||
public function ruleDescription( \IPS\core\Achievements\Rule $rule ): ?string
|
||||
{
|
||||
$type = $rule->filters['type'] ?? NULL;
|
||||
|
||||
$conditions = [];
|
||||
if ( isset( $rule->filters['milestone'] ) )
|
||||
{
|
||||
$conditions[] = \IPS\Member::loggedIn()->language()->addToStack( 'achievements_title_filter_milestone', FALSE, [
|
||||
'htmlsprintf' => [
|
||||
\IPS\Theme::i()->getTemplate( 'achievements' )->ruleDescriptionBadge( 'milestone', \IPS\Member::loggedIn()->language()->addToStack( 'achievements_title_filter_milestone_nth', FALSE, [ 'pluralize' => [ $rule->filters['milestone'] ] ] ) )
|
||||
],
|
||||
'sprintf' => [ $type ? \IPS\Member::loggedIn()->language()->addToStack( $type::$title ) : \IPS\Member::loggedIn()->language()->addToStack('AchievementAction__NewContentItem_title_generic') ]
|
||||
] );
|
||||
}
|
||||
if ( $nodeCondition = $this->_nodeFilterDescription( $rule ) )
|
||||
{
|
||||
$conditions[] = $nodeCondition;
|
||||
}
|
||||
|
||||
return \IPS\Theme::i()->getTemplate( 'achievements' )->ruleDescription(
|
||||
$type ? \IPS\Member::loggedIn()->language()->addToStack( 'AchievementAction__NewContentItem_title_t', FALSE, [ 'sprintf' => [ \IPS\Member::loggedIn()->language()->addToStack( $type::$title ) ] ] ) : \IPS\Member::loggedIn()->language()->addToStack( 'AchievementAction__NewContentItem_title' ),
|
||||
$conditions
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Achievement Action 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 05 Mar 2021
|
||||
*/
|
||||
|
||||
namespace IPS\core\extensions\core\AchievementAction;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Achievement Action Extension
|
||||
*/
|
||||
class _NewPoll extends \IPS\core\Achievements\Actions\AbstractAchievementAction // NOTE: Other classes exist to provided bases for common situations, like where node-based filters will be required
|
||||
{
|
||||
/**
|
||||
* Get filter form elements
|
||||
*
|
||||
* @param array|NULL $filters Current filter values (if editing)
|
||||
* @param \IPS\Http\Url $url The URL the form is being shown on
|
||||
* @return array
|
||||
*/
|
||||
public function filters( ?array $filters, \IPS\Http\Url $url ): array
|
||||
{
|
||||
$nthFilter = new \IPS\Helpers\Form\Number( 'achievement_filter_poll_nth', ( $filters and isset( $filters['milestone'] ) and $filters['milestone'] ) ? $filters['milestone'] : 0, FALSE, [], NULL, \IPS\Member::loggedIn()->language()->addToStack('achievement_filter_nth_their'), \IPS\Member::loggedIn()->language()->addToStack('achievement_filter_NewPoll_nth_suffix') );
|
||||
$nthFilter->label = \IPS\Member::loggedIn()->language()->addToStack('achievement_filter_NewPoll_nth');
|
||||
|
||||
$return = array();
|
||||
|
||||
$return['milestone'] = $nthFilter;
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format filter form values
|
||||
*
|
||||
* @param array $values The values from the form
|
||||
* @return array
|
||||
*/
|
||||
public function formatFilterValues( array $values ): array
|
||||
{
|
||||
$return = [];
|
||||
|
||||
if ( isset( $values['achievement_filter_poll_nth'] ) )
|
||||
{
|
||||
$return['milestone'] = $values['achievement_filter_poll_nth'];
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Work out if the filters applies for a given action
|
||||
*
|
||||
* Important note for milestones: consider the context. This method is called by \IPS\Member::achievementAction(). If your code
|
||||
* calls that BEFORE making its change in the database (or there is read/write separation), you will need to add
|
||||
* 1 to the value being considered for milestones
|
||||
*
|
||||
* @param \IPS\Member $subject The subject member
|
||||
* @param array $filters The value returned by formatFilterValues()
|
||||
* @param mixed $extra Any additional information about what is happening (e.g. if a post is being made: the post object)
|
||||
* @return bool
|
||||
*/
|
||||
public function filtersMatch( \IPS\Member $subject, array $filters, $extra = NULL ): bool
|
||||
{
|
||||
if ( isset( $filters['milestone'] ) )
|
||||
{
|
||||
$where = [];
|
||||
$where[] = [ 'starter_id=?', $subject->member_id ];
|
||||
|
||||
$count = \IPS\Db::i()->select( 'COUNT(*)', 'core_polls', $where )->first();
|
||||
|
||||
if ( $count < $filters['milestone'] )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @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)
|
||||
* @return string
|
||||
*/
|
||||
public function identifier( \IPS\Member $subject, $extra = NULL ): string
|
||||
{
|
||||
return (string) $extra->pid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a description for this action to show in the log
|
||||
*
|
||||
* @param string $identifier The identifier as returned by identifier()
|
||||
* @param array $actor If the member was the "subject", "other", or both
|
||||
* @return string
|
||||
*/
|
||||
public function logRow( string $identifier, array $actor ): string
|
||||
{
|
||||
return \IPS\Member::loggedIn()->language()->addToStack( 'AchievementAction__NewPoll_log', FALSE );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get "description" for rule
|
||||
*
|
||||
* @param \IPS\core\Achievements\Rule $rule The rule
|
||||
* @return string|NULL
|
||||
*/
|
||||
public function ruleDescription( \IPS\core\Achievements\Rule $rule ): ?string
|
||||
{
|
||||
$conditions = [];
|
||||
if ( isset( $rule->filters['milestone'] ) )
|
||||
{
|
||||
$conditions[] = \IPS\Member::loggedIn()->language()->addToStack( 'achievements_title_filter_milestone', FALSE, [
|
||||
'htmlsprintf' => [
|
||||
\IPS\Theme::i()->getTemplate( 'achievements' )->ruleDescriptionBadge( 'milestone', \IPS\Member::loggedIn()->language()->addToStack( 'achievements_title_filter_milestone_nth', FALSE, [ 'pluralize' => [ $rule->filters['milestone'] ] ] ) )
|
||||
],
|
||||
'sprintf' => [ \IPS\Member::loggedIn()->language()->addToStack('AchievementAction__NewPoll_title_generic') ]
|
||||
] );
|
||||
}
|
||||
|
||||
return \IPS\Theme::i()->getTemplate( 'achievements' )->ruleDescription(
|
||||
\IPS\Member::loggedIn()->language()->addToStack( 'AchievementAction__NewPoll_title' ),
|
||||
$conditions
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get rebuild data
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
static public function rebuildData()
|
||||
{
|
||||
return [ [
|
||||
'table' => 'core_polls',
|
||||
'pkey' => 'pid',
|
||||
'date' => 'start_date',
|
||||
'where' => [],
|
||||
] ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the rebuild row
|
||||
*
|
||||
* @param array $row Row from database
|
||||
* @param array $data Data collected when starting rebuild [table, pkey...]
|
||||
* @return void
|
||||
*/
|
||||
public static function rebuildRow( $row, $data )
|
||||
{
|
||||
\IPS\Member::load( $row['starter_id'] )->achievementAction( 'core', 'NewPoll', \IPS\Poll::load( $row['pid'] ) );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,324 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Achievement Action 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 01 Mar 2021
|
||||
*/
|
||||
|
||||
namespace IPS\core\extensions\core\AchievementAction;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Achievement Action Extension
|
||||
*/
|
||||
class _Reaction extends \IPS\core\Achievements\Actions\AbstractContentAchievementAction
|
||||
{
|
||||
/**
|
||||
* Get filter form elements
|
||||
*
|
||||
* @param array|NULL $filters Current filter values (if editing)
|
||||
* @param \IPS\Http\Url $url The URL the form is being shown on
|
||||
* @return array
|
||||
*/
|
||||
public function filters( ?array $filters, \IPS\Http\Url $url ): array
|
||||
{
|
||||
$return = parent::filters( $filters, $url );
|
||||
|
||||
$reactionFilter = new \IPS\Helpers\Form\Node( 'achievement_filter_Reaction_reaction', ( $filters and isset( $filters['reactions'] ) and $filters['reactions'] ) ? $filters['reactions'] : 0, FALSE, [
|
||||
'url' => $url,
|
||||
'class' => 'IPS\Content\Reaction',
|
||||
'showAllNodes' => TRUE,
|
||||
'multiple' => TRUE,
|
||||
], NULL, \IPS\Member::loggedIn()->language()->addToStack( 'achievement_subfilter_Reaction_reaction_prefix' ) );
|
||||
$return['reactions'] = $reactionFilter;
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format filter form values
|
||||
*
|
||||
* @param array $values The values from the form
|
||||
* @return array
|
||||
*/
|
||||
public function formatFilterValues( array $values ): array
|
||||
{
|
||||
$return = parent::formatFilterValues( $values );
|
||||
if ( isset( $values['achievement_filter_Reaction_reaction'] ) )
|
||||
{
|
||||
$return['reactions'] = array_keys( $values['achievement_filter_Reaction_reaction'] );
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Work out if the filters applies for a given action
|
||||
*
|
||||
* Important note for milestones: consider the context. This method is called by \IPS\Member::achievementAction(). If your code
|
||||
* calls that BEFORE making its change in the database (or there is read/write separation), you will need to add
|
||||
* 1 to the value being considered for milestones
|
||||
*
|
||||
* @param \IPS\Member $subject The subject member
|
||||
* @param array $filters The value returned by formatFilterValues()
|
||||
* @param mixed $extra Any additional information about what is happening (e.g. if a post is being made: the post object)
|
||||
* @return bool
|
||||
*/
|
||||
public function filtersMatch( \IPS\Member $subject, array $filters, $extra = NULL ): bool
|
||||
{
|
||||
if ( !parent::filtersMatch( $subject, $filters, $extra['content'] ) )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ( isset( $filters['reactions'] ) )
|
||||
{
|
||||
if ( !\in_array( $extra['reaction']->id, $filters['reactions'] ) )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if ( isset( $filters['milestone'] ) )
|
||||
{
|
||||
$query = $this->getQuery( 'COUNT(*)', [ [ 'member_id=?', $subject->member_id ] ], NULL, $filters );
|
||||
|
||||
if ( ( $query->first() + 1 ) < $filters['milestone'] )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @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)
|
||||
* @return string
|
||||
*/
|
||||
public function identifier( \IPS\Member $subject, $extra = NULL ): string
|
||||
{
|
||||
return \get_class( $extra['content'] ) . ':' . $extra['content']->{$extra['content']::$databaseColumnId} . ':' . $extra['giver']->member_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the labels for the people this action might give awards to
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function awardOptions(): array
|
||||
{
|
||||
return [
|
||||
'subject' => 'achievement_filter_Reaction_receiver',
|
||||
'other' => 'achievement_filter_Reaction_giver'
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the "other" people we need to award =stuff to
|
||||
*
|
||||
* @param mixed $extra Any additional information about what is happening (e.g. if a post is being made: the post object)
|
||||
* @return array
|
||||
*/
|
||||
public function awardOther( $extra = NULL ): array
|
||||
{
|
||||
return [ $extra['giver'] ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a description for this action to show in the log
|
||||
*
|
||||
* @param string $identifier The identifier as returned by identifier()
|
||||
* @param array $actor If the member was the "subject", "other", or both
|
||||
* @return string
|
||||
*/
|
||||
public function logRow( string $identifier, array $actor ): string
|
||||
{
|
||||
$exploded = explode( ':', $identifier );
|
||||
|
||||
$reactionName = \IPS\Member::loggedIn()->language()->addToStack('unknown');
|
||||
$contentLink = \IPS\Member::loggedIn()->language()->addToStack('modcp_deleted');
|
||||
try
|
||||
{
|
||||
$class = $exploded[0];
|
||||
$content = $class::load( $exploded[1] );
|
||||
$contentLink = \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->basicUrl( $content->url(), TRUE, $content->indefiniteArticle(), FALSE );
|
||||
|
||||
$reaction = $content->reacted( \IPS\Member::load( $exploded[2] ) );
|
||||
$reactionName = $reaction->_title;
|
||||
}
|
||||
catch ( \Exception $e ) { }
|
||||
|
||||
if ( \in_array( 'subject', $actor ) )
|
||||
{
|
||||
return \IPS\Member::loggedIn()->language()->addToStack( 'AchievementAction__Reaction_log_subject', FALSE, [ 'sprintf' => [ $reactionName ], 'htmlsprintf' => [ $contentLink ] ] );
|
||||
}
|
||||
else
|
||||
{
|
||||
return \IPS\Member::loggedIn()->language()->addToStack( 'AchievementAction__Reaction_log_other', FALSE, [ 'sprintf' => [ $reactionName ], 'htmlsprintf' => [ $contentLink ] ] );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get "description" for rule
|
||||
*
|
||||
* @param \IPS\core\Achievements\Rule $rule The rule
|
||||
* @return string|NULL
|
||||
*/
|
||||
public function ruleDescription( \IPS\core\Achievements\Rule $rule ): ?string
|
||||
{
|
||||
$conditions = [];
|
||||
if ( isset( $rule->filters['milestone'] ) )
|
||||
{
|
||||
$conditions[] = \IPS\Member::loggedIn()->language()->addToStack( 'achievements_title_filter_milestone', FALSE, [
|
||||
'htmlsprintf' => [
|
||||
\IPS\Theme::i()->getTemplate( 'achievements' )->ruleDescriptionBadge( 'milestone', \IPS\Member::loggedIn()->language()->addToStack( 'achievements_title_filter_milestone_nth', FALSE, [ 'pluralize' => [ $rule->filters['milestone'] ] ] ) )
|
||||
],
|
||||
'sprintf' => \IPS\Member::loggedIn()->language()->addToStack('AchievementAction__Reaction_title_generic')
|
||||
] );
|
||||
}
|
||||
if ( isset( $rule->filters['reactions'] ) )
|
||||
{
|
||||
$reactionNames = [];
|
||||
foreach ( $rule->filters['reactions'] as $id )
|
||||
{
|
||||
try
|
||||
{
|
||||
$reactionNames[] = \IPS\Content\Reaction::load( $id )->_title;
|
||||
}
|
||||
catch ( \OutOfRangeException $e ) {}
|
||||
}
|
||||
if ( $reactionNames )
|
||||
{
|
||||
$conditions[] = \IPS\Member::loggedIn()->language()->addToStack( 'achievements_title_filter_type', FALSE, [
|
||||
'htmlsprintf' => [
|
||||
\IPS\Theme::i()->getTemplate( 'achievements' )->ruleDescriptionBadge( 'other',
|
||||
\count( $reactionNames ) === 1 ? $reactionNames[0] : \IPS\Member::loggedIn()->language()->addToStack( 'AchievementAction__Reaction_types', FALSE, [ 'sprintf' => [
|
||||
\count( $reactionNames ),
|
||||
] ] ),
|
||||
\count( $reactionNames ) === 1 ? NULL : $reactionNames
|
||||
)
|
||||
],
|
||||
] );
|
||||
}
|
||||
}
|
||||
if ( $nodeCondition = $this->_nodeFilterDescription( $rule ) )
|
||||
{
|
||||
$conditions[] = $nodeCondition;
|
||||
}
|
||||
|
||||
return \IPS\Theme::i()->getTemplate( 'achievements' )->ruleDescription(
|
||||
\IPS\Member::loggedIn()->language()->addToStack( 'AchievementAction__Reaction_title' ),
|
||||
$conditions
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get rebuild data
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
static public function rebuildData()
|
||||
{
|
||||
return [ [
|
||||
'table' => 'core_reputation_index',
|
||||
'pkey' => 'id',
|
||||
'date' => 'rep_date',
|
||||
'where' => [],
|
||||
] ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the rebuild row
|
||||
*
|
||||
* @param array $row Row from database
|
||||
* @param array $data Data collected when starting rebuild [table, pkey...]
|
||||
* @return void
|
||||
*/
|
||||
public static function rebuildRow( $row, $data )
|
||||
{
|
||||
if ( !$row['rep_class'] OR !\class_exists( $row['rep_class'] ) )
|
||||
{
|
||||
/* Class either isn't set or doesn't exist, so move on. */
|
||||
return;
|
||||
}
|
||||
|
||||
$object = $row['rep_class']::load( $row['item_id'] );
|
||||
$reaction = \IPS\Content\Reaction::load( $row['reaction'] );
|
||||
|
||||
/* Figure out the owner of this - if it is content, it will be the author. If it is a node, then it will be the person who created it */
|
||||
if ( $object instanceof \IPS\Content )
|
||||
{
|
||||
$owner = $object->author();
|
||||
}
|
||||
else if ( $object instanceof \IPS\Node\Model )
|
||||
{
|
||||
$owner = $object->owner();
|
||||
}
|
||||
|
||||
/* Give points */
|
||||
$owner->achievementAction( 'core', 'Reaction', [
|
||||
'giver' => \IPS\Member::load( $row['member_id'] ),
|
||||
'content' => $object,
|
||||
'reaction' => $reaction
|
||||
] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a query to use for multiple methods within this extension
|
||||
* @param string $select Select for the query
|
||||
* @param array|NULL $where Where for the query
|
||||
* @param int|NULL $limit Limit for the query
|
||||
* @param array $filters Rule filters
|
||||
* @return \IPS\Db\Select
|
||||
*/
|
||||
public function getQuery( $select, $where, $limit, $filters ): \IPS\Db\Select
|
||||
{
|
||||
$joinContainers = FALSE;
|
||||
$extraJoinCondition = NULL;
|
||||
$where = \is_array( $where ) ? $where : array();
|
||||
|
||||
/* Limit by type and node */
|
||||
if ( isset( $filters['type'] ) )
|
||||
{
|
||||
$where[] = ['rep_class=?', $filters['type']];
|
||||
$itemClass = $filters['type'];
|
||||
if ( \in_array( 'IPS\Content\Comment', class_parents( $filters['type'] ) ) )
|
||||
{
|
||||
$itemClass = $filters['type']::$itemClass;
|
||||
}
|
||||
|
||||
if ( isset( $filters['nodes_' . str_replace( '\\', '-', $itemClass )] ) )
|
||||
{
|
||||
$joinContainers = TRUE;
|
||||
$extraJoinCondition = ' AND ' . \IPS\Db::i()->in( $itemClass::$databaseTable . '.' . $itemClass::$databaseColumnMap['container'], $filters['nodes_' . str_replace( '\\', '-', $itemClass )] );
|
||||
}
|
||||
}
|
||||
|
||||
/* Limit by reaction type */
|
||||
if ( isset( $filters['reactions'] ) )
|
||||
{
|
||||
$where[] = [ \IPS\Db::i()->in( 'reaction', $filters['reactions'] ) ];
|
||||
}
|
||||
|
||||
$query = \IPS\Db::i()->select( $select, 'core_reputation_index', $where, NULL, $limit );
|
||||
|
||||
if ( $joinContainers )
|
||||
{
|
||||
$query->join( $itemClass::$databaseTable, 'core_reputation_index.item_id=' . $itemClass::$databaseTable . '.' . $itemClass::$databasePrefix . $itemClass::$databaseColumnId . $extraJoinCondition, 'INNER' );
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Achievement Action 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 03 Mar 2021
|
||||
*/
|
||||
|
||||
namespace IPS\core\extensions\core\AchievementAction;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Achievement Action Extension
|
||||
*/
|
||||
class _Review extends \IPS\core\Achievements\Actions\AbstractContentAchievementAction
|
||||
{
|
||||
protected static $includeItems = FALSE;
|
||||
protected static $includeComments = FALSE;
|
||||
|
||||
/**
|
||||
* Work out if the filters applies for a given action
|
||||
*
|
||||
* Important note for milestones: consider the context. This method is called by \IPS\Member::achievementAction(). If your code
|
||||
* calls that BEFORE making its change in the database (or there is read/write separation), you will need to add
|
||||
* 1 to the value being considered for milestones
|
||||
*
|
||||
* @param \IPS\Member $subject The subject member
|
||||
* @param array $filters The value returned by formatFilterValues()
|
||||
* @param mixed $extra Any additional information about what is happening (e.g. if a post is being made: the post object)
|
||||
* @return bool
|
||||
*/
|
||||
public function filtersMatch( \IPS\Member $subject, array $filters, $extra = NULL ): bool
|
||||
{
|
||||
if ( !parent::filtersMatch( $subject, $filters, $extra ) )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ( isset( $filters['milestone'] ) )
|
||||
{
|
||||
$count = 0;
|
||||
$classes = [];
|
||||
if ( isset( $filters['type'] ) )
|
||||
{
|
||||
if ( isset( $filters[ 'nodes_' . str_replace( '\\', '-', $filters['type'] ) ] ) )
|
||||
{
|
||||
$class = $filters['type'];
|
||||
$where = [];
|
||||
$where[] = [ $class::$databasePrefix . $class::$databaseColumnMap['author'] . '=?', $subject->member_id ];
|
||||
$where[] = [ \IPS\Db::i()->in( $class::$databasePrefix . $class::$databaseColumnMap['container'] ), $filters[ 'nodes_' . str_replace( '\\', '-', $filters['type'] ) ] ];
|
||||
|
||||
$count += \IPS\Db::i()->select( 'COUNT(*)', $class::$databaseTable, $where )->first();
|
||||
}
|
||||
else
|
||||
{
|
||||
$classes[] = $filters['type'];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach ( \IPS\Application::allExtensions( 'core', 'ContentRouter' ) as $contentRouter )
|
||||
{
|
||||
foreach ( $contentRouter->classes as $class )
|
||||
{
|
||||
$exploded = explode( '\\', $class );
|
||||
if ( \in_array( 'IPS\Content\Item', class_parents( $class ) ) and isset( $class::$reviewClass ) )
|
||||
{
|
||||
$classes[] = $class::$reviewClass;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ( $classes as $class )
|
||||
{
|
||||
$count += $class::memberPostCount( $subject, TRUE, FALSE );
|
||||
}
|
||||
|
||||
if ( $count < $filters['milestone'] )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the labels for the people this action might give awards to
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function awardOptions(): array
|
||||
{
|
||||
return [
|
||||
'subject' => 'achievement_filter_Review_author',
|
||||
'other' => 'achievement_filter_Review_item_author'
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the "other" people we need to award =stuff to
|
||||
*
|
||||
* @param mixed $extra Any additional information about what is happening (e.g. if a post is being made: the post object)
|
||||
* @return array
|
||||
*/
|
||||
public function awardOther( $extra = NULL ): array
|
||||
{
|
||||
return [ $extra->item()->author() ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a description for this action to show in the log
|
||||
*
|
||||
* @param string $identifier The identifier as returned by identifier()
|
||||
* @param array $actor If the member was the "subject", "other", or both
|
||||
* @return string
|
||||
*/
|
||||
public function logRow( string $identifier, array $actor ): string
|
||||
{
|
||||
$exploded = explode( ':', $identifier );
|
||||
|
||||
$sprintf = [];
|
||||
try
|
||||
{
|
||||
$comment = $exploded[0]::load( $exploded[1] );
|
||||
$item = $comment->item();
|
||||
$sprintf = [ 'htmlsprintf' => [
|
||||
\IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->basicUrl( $comment->url(), TRUE, $item->mapped('title') ?: $item->indefiniteArticle(), FALSE )
|
||||
] ];
|
||||
}
|
||||
catch ( \OutOfRangeException $e )
|
||||
{
|
||||
$sprintf = [ 'sprintf' => [ \IPS\Member::loggedIn()->language()->addToStack('modcp_deleted') ] ];
|
||||
}
|
||||
|
||||
return \IPS\Member::loggedIn()->language()->addToStack( 'AchievementAction__Review_log', FALSE, $sprintf );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get "description" for rule
|
||||
*
|
||||
* @param \IPS\core\Achievements\Rule $rule The rule
|
||||
* @return string|NULL
|
||||
*/
|
||||
public function ruleDescription( \IPS\core\Achievements\Rule $rule ): ?string
|
||||
{
|
||||
$type = $rule->filters['type'] ?? NULL;
|
||||
|
||||
$conditions = [];
|
||||
if ( isset( $rule->filters['milestone'] ) )
|
||||
{
|
||||
$conditions[] = \IPS\Member::loggedIn()->language()->addToStack( 'achievements_title_filter_milestone', FALSE, [
|
||||
'htmlsprintf' => [
|
||||
\IPS\Theme::i()->getTemplate( 'achievements' )->ruleDescriptionBadge( 'milestone', \IPS\Member::loggedIn()->language()->addToStack( 'achievements_title_filter_milestone_nth', FALSE, [ 'pluralize' => [ $rule->filters['milestone'] ] ] ) )
|
||||
],
|
||||
'sprintf' => [ $type ? \IPS\Member::loggedIn()->language()->addToStack( $type::$title, FALSE, [ 'strtolower' => TRUE ] ) : \IPS\Member::loggedIn()->language()->addToStack('AchievementAction__Review_title_generic') ]
|
||||
] );
|
||||
}
|
||||
if ( $nodeCondition = $this->_nodeFilterDescription( $rule ) )
|
||||
{
|
||||
$conditions[] = $nodeCondition;
|
||||
}
|
||||
|
||||
return \IPS\Theme::i()->getTemplate( 'achievements' )->ruleDescription(
|
||||
$type ? \IPS\Member::loggedIn()->language()->addToStack( 'AchievementAction__NewContentItem_title_t', FALSE, [ 'sprintf' => [ \IPS\Member::loggedIn()->language()->addToStack( $type::$title ) ] ] ) : \IPS\Member::loggedIn()->language()->addToStack( 'AchievementAction__Review_title' ),
|
||||
$conditions
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,219 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Achievement Action Extension: Member visits the community, and has not previously done so that day
|
||||
* @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 24 Feb 2021
|
||||
*/
|
||||
|
||||
namespace IPS\core\extensions\core\AchievementAction;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Achievement Action Extension: Member visits the community, and has not previously done so that day
|
||||
*/
|
||||
class _SessionStartDaily extends \IPS\core\Achievements\Actions\AbstractAchievementAction
|
||||
{
|
||||
/**
|
||||
* Get filter form elements
|
||||
*
|
||||
* @param array|NULL $filters Current filter values (if editing)
|
||||
* @param \IPS\Http\Url $url The URL the form is being shown on
|
||||
* @return array
|
||||
*/
|
||||
public function filters( ?array $filters, \IPS\Http\Url $url ): array
|
||||
{
|
||||
$return['milestone_registered'] = new \IPS\Helpers\Form\Interval( 'achievement_filter_SessionStartDaily', ( $filters and isset( $filters['milestone_registered'] ) and $filters['milestone_registered'] ) ? $filters['milestone_registered'] : 0, FALSE, [ 'valueAs' => \IPS\Helpers\Form\Interval::DAYS, 'min' => NULL ], NULL, \IPS\Member::loggedIn()->language()->addToStack('achievement_filter_SessionStartDaily_prefix') );
|
||||
$return['milestone_concurrent'] = new \IPS\Helpers\Form\Number( 'achievement_filter_SessionStartDaily_concurrent', ( $filters and isset( $filters['milestone_concurrent'] ) and $filters['milestone_concurrent'] ) ? $filters['milestone_concurrent'] : 0, FALSE, [], NULL, \IPS\Member::loggedIn()->language()->addToStack('achievement_filter_SessionStartDaily_concurrent_prefix'), \IPS\Member::loggedIn()->language()->addToStack('achievement_filter_SessionStartDaily_concurrent_suffix') );
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format filter form values
|
||||
*
|
||||
* @param array $values The values from the form
|
||||
* @return array
|
||||
*/
|
||||
public function formatFilterValues( array $values ): array
|
||||
{
|
||||
$return = [];
|
||||
if ( isset( $values['achievement_filter_SessionStartDaily'] ) )
|
||||
{
|
||||
$return['milestone_registered'] = $values['achievement_filter_SessionStartDaily'];
|
||||
}
|
||||
if ( isset( $values['achievement_filter_SessionStartDaily_concurrent'] ) )
|
||||
{
|
||||
$return['milestone_concurrent'] = $values['achievement_filter_SessionStartDaily_concurrent'];
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Work out if the filters applies for a given action
|
||||
*
|
||||
* Important note for milestones: consider the context. This method is called by \IPS\Member::achievementAction(). If your code
|
||||
* calls that BEFORE making its change in the database (or there is read/write separation), you will need to add
|
||||
* 1 to the value being considered for milestones
|
||||
*
|
||||
* @param \IPS\Member $subject The subject member
|
||||
* @param array $filters The value returned by formatFilterValues()
|
||||
* @param mixed $extra Any additional information about what is happening (e.g. if a post is being made: the post object)
|
||||
* @return bool
|
||||
*/
|
||||
public function filtersMatch( \IPS\Member $subject, array $filters, $extra = NULL ): bool
|
||||
{
|
||||
if ( isset( $filters['milestone_registered'] ) )
|
||||
{
|
||||
if ( $subject->joined->getTimestamp() > ( time() - ( 86400 * $filters['milestone_registered'] ) ) )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if ( isset( $filters['milestone_concurrent'] ) )
|
||||
{
|
||||
/* Get the count of all logins since milestone ago. If it matches the count with milestone, then we have one for each day */
|
||||
if ( $subject->timezone )
|
||||
{
|
||||
$date = ( new \DateTime( 'now', new \DateTimeZone( $subject->timezone ) ) )->sub( new \DateInterval( 'P' . $filters['milestone_concurrent'] . 'D' ) )->format( 'Y-m-d' );
|
||||
}
|
||||
else
|
||||
{
|
||||
$date = ( new \DateTime( 'now' ) )->sub( new \DateInterval( 'P' . $filters['milestone_concurrent'] . 'D' ) )->format( 'Y-m-d' );
|
||||
}
|
||||
if ( $filters['milestone_concurrent'] > (int) \IPS\Db::i()->select( 'COUNT(*)', 'core_members_logins', [ 'member_id=? and member_date >=?', $subject->member_id, $date ] )->first() )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @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)
|
||||
* @return string
|
||||
*/
|
||||
public function identifier( \IPS\Member $subject, $extra = NULL ): string
|
||||
{
|
||||
if ( $subject->timezone )
|
||||
{
|
||||
return $subject->member_id . '.' . ( new \DateTime( 'now', new \DateTimeZone( $subject->timezone ) ) )->format( 'Y-m-d' ); // User's own timezone: Jordan's idea
|
||||
}
|
||||
else
|
||||
{
|
||||
return $subject->member_id . '.' . ( new \DateTime( 'now' ) )->format( 'Y-m-d' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a description for this action to show in the log
|
||||
*
|
||||
* @param string $identifier The identifier as returned by identifier()
|
||||
* @param array $actor If the member was the "subject", "other", or both
|
||||
* @return string
|
||||
*/
|
||||
public function logRow( string $identifier, array $actor ): string
|
||||
{
|
||||
return \IPS\Member::loggedIn()->language()->addToStack( 'AchievementAction__SessionStartDaily_log', FALSE, array( 'sprintf' => ( new \IPS\DateTime( $identifier ) )->dayAndMonth() ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get "description" for rule
|
||||
*
|
||||
* @param \IPS\core\Achievements\Rule $rule The rule
|
||||
* @return string|NULL
|
||||
*/
|
||||
public function ruleDescription( \IPS\core\Achievements\Rule $rule ): ?string
|
||||
{
|
||||
$conditions = [];
|
||||
if ( isset( $rule->filters['milestone_registered'] ) )
|
||||
{
|
||||
$conditions[] = \IPS\Member::loggedIn()->language()->addToStack( 'AchievementAction__SessionStartDaily_milestone', FALSE, [
|
||||
'htmlsprintf' => [
|
||||
\IPS\Theme::i()->getTemplate( 'achievements' )->ruleDescriptionBadge( 'milestone_registered', \IPS\Member::loggedIn()->language()->addToStack( 'f_days', FALSE, [ 'pluralize' => [ $rule->filters['milestone_registered'] ] ] ) )
|
||||
],
|
||||
] );
|
||||
}
|
||||
elseif ( isset( $rule->filters['milestone_concurrent'] ) )
|
||||
{
|
||||
$conditions[] = \IPS\Member::loggedIn()->language()->addToStack( 'AchievementAction__SessionStartDaily_concurrent_milestone', FALSE, [
|
||||
'htmlsprintf' => [
|
||||
\IPS\Theme::i()->getTemplate( 'achievements' )->ruleDescriptionBadge( 'milestone', \IPS\Member::loggedIn()->language()->addToStack( 'f_days', FALSE, [ 'pluralize' => [ $rule->filters['milestone_concurrent'] ] ] ) )
|
||||
],
|
||||
] );
|
||||
}
|
||||
|
||||
return \IPS\Theme::i()->getTemplate( 'achievements', 'core', 'admin' )->ruleDescription(
|
||||
\IPS\Member::loggedIn()->language()->addToStack( 'AchievementAction__SessionStartDaily_title' ),
|
||||
$conditions
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a user friendly description of why this was awarded
|
||||
*
|
||||
* @param \IPS\core\Achievements\Rule $rule The rule
|
||||
* @return string|NULL
|
||||
*/
|
||||
public function awardDescription( \IPS\core\Achievements\Rule $rule ): ?string
|
||||
{
|
||||
if ( isset( $rule->filters['milestone_registered'] ) )
|
||||
{
|
||||
return \IPS\Member::loggedIn()->language()->addToStack( 'AchievementAction__SessionStartDaily_registered_badge_blurb', FALSE, [
|
||||
'pluralize' => [
|
||||
$rule->filters['milestone_registered']
|
||||
],
|
||||
] );
|
||||
}
|
||||
elseif ( isset( $rule->filters['milestone_concurrent'] ) )
|
||||
{
|
||||
return \IPS\Member::loggedIn()->language()->addToStack( 'AchievementAction__SessionStartDaily_concurrent_badge_blurb', FALSE, [
|
||||
'pluralize' => [
|
||||
$rule->filters['milestone_registered']
|
||||
],
|
||||
] );
|
||||
}
|
||||
|
||||
return \IPS\Member::loggedIn()->language()->addToStack( 'AchievementAction__SessionStartDaily_badge_blurb' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get rebuild data
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
static public function rebuildData()
|
||||
{
|
||||
return [ [
|
||||
'table' => 'core_members',
|
||||
'pkey' => 'member_id',
|
||||
'date' => 'joined',
|
||||
'where' => [ [ 'last_visit > 0 AND ( ! ' . \IPS\Db::i()->bitwiseWhere( \IPS\Member::$bitOptions['members_bitoptions'], 'bw_is_spammer' ) . ')' ] ],
|
||||
] ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the rebuild row
|
||||
*
|
||||
* @param array $row Row from database
|
||||
* @param array $data Data collected when starting rebuild [table, pkey...]
|
||||
* @return void
|
||||
*/
|
||||
public static function rebuildRow( $row, $data )
|
||||
{
|
||||
\IPS\Member::constructFromData( $row )->achievementAction( 'core', 'SessionStartDaily' );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Achievement Action 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 08 Mar 2021
|
||||
*/
|
||||
|
||||
namespace IPS\core\extensions\core\AchievementAction;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Achievement Action Extension
|
||||
*/
|
||||
class _VotePoll extends \IPS\core\Achievements\Actions\AbstractAchievementAction // NOTE: Other classes exist to provided bases for common situations, like where node-based filters will be required
|
||||
{
|
||||
/**
|
||||
* Get filter form elements
|
||||
*
|
||||
* @param array|NULL $filters Current filter values (if editing)
|
||||
* @param \IPS\Http\Url $url The URL the form is being shown on
|
||||
* @return array
|
||||
*/
|
||||
public function filters( ?array $filters, \IPS\Http\Url $url ): array
|
||||
{
|
||||
$nthFilter = new \IPS\Helpers\Form\Number( 'achievement_filter_poll_vote_nth', ( $filters and isset( $filters['milestone'] ) and $filters['milestone'] ) ? $filters['milestone'] : 0, FALSE, [], NULL, \IPS\Member::loggedIn()->language()->addToStack('achievement_filter_nth_their'), \IPS\Member::loggedIn()->language()->addToStack('achievement_filter_VotePoll_nth_suffix') );
|
||||
$nthFilter->label = \IPS\Member::loggedIn()->language()->addToStack('achievement_filter_NewPoll_nth');
|
||||
|
||||
$return = array();
|
||||
|
||||
$return['milestone'] = $nthFilter;
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format filter form values
|
||||
*
|
||||
* @param array $values The values from the form
|
||||
* @return array
|
||||
*/
|
||||
public function formatFilterValues( array $values ): array
|
||||
{
|
||||
$return = [];
|
||||
|
||||
if ( isset( $values['achievement_filter_poll_vote_nth'] ) )
|
||||
{
|
||||
$return['milestone'] = $values['achievement_filter_poll_vote_nth'];
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Work out if the filters applies for a given action
|
||||
*
|
||||
* Important note for milestones: consider the context. This method is called by \IPS\Member::achievementAction(). If your code
|
||||
* calls that BEFORE making its change in the database (or there is read/write separation), you will need to add
|
||||
* 1 to the value being considered for milestones
|
||||
*
|
||||
* @param \IPS\Member $subject The subject member
|
||||
* @param array $filters The value returned by formatFilterValues()
|
||||
* @param mixed $extra Any additional information about what is happening (e.g. if a post is being made: the post object)
|
||||
* @return bool
|
||||
*/
|
||||
public function filtersMatch( \IPS\Member $subject, array $filters, $extra = NULL ): bool
|
||||
{
|
||||
if ( isset( $filters['milestone'] ) )
|
||||
{
|
||||
$where = [];
|
||||
$where[] = [ 'member_id=?', $subject->member_id ];
|
||||
|
||||
$count = \IPS\Db::i()->select( 'COUNT(*)', 'core_voters', $where )->first();
|
||||
|
||||
if ( $count < $filters['milestone'] )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the labels for the people this action might give awards to
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function awardOptions(): array
|
||||
{
|
||||
return [
|
||||
'subject' => 'achievement_filter_VotePoll_voter',
|
||||
'other' => 'achievement_filter_VotePoll_author'
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the "other" people we need to award =stuff to
|
||||
*
|
||||
* @param mixed $extra Any additional information about what is happening (e.g. if a post is being made: the post object)
|
||||
* @return array
|
||||
*/
|
||||
|
||||
public function awardOther( $extra = NULL ): array
|
||||
{
|
||||
return [ $extra->author() ];
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @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)
|
||||
* @return string
|
||||
*/
|
||||
public function identifier( \IPS\Member $subject, $extra = NULL ): string
|
||||
{
|
||||
return (string) $extra->pid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a description for this action to show in the log
|
||||
*
|
||||
* @param string $identifier The identifier as returned by identifier()
|
||||
* @param array $actor If the member was the "subject", "other", or both
|
||||
* @return string
|
||||
*/
|
||||
public function logRow( string $identifier, array $actor ): string
|
||||
{
|
||||
return \IPS\Member::loggedIn()->language()->addToStack( 'AchievementAction__VotePoll_log', FALSE );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get "description" for rule
|
||||
*
|
||||
* @param \IPS\core\Achievements\Rule $rule The rule
|
||||
* @return string|NULL
|
||||
*/
|
||||
public function ruleDescription( \IPS\core\Achievements\Rule $rule ): ?string
|
||||
{
|
||||
$conditions = [];
|
||||
if ( isset( $rule->filters['milestone'] ) )
|
||||
{
|
||||
$conditions[] = \IPS\Member::loggedIn()->language()->addToStack( 'achievements_title_filter_milestone', FALSE, [
|
||||
'htmlsprintf' => [
|
||||
\IPS\Theme::i()->getTemplate( 'achievements' )->ruleDescriptionBadge( 'milestone', \IPS\Member::loggedIn()->language()->addToStack( 'achievements_title_filter_milestone_nth', FALSE, [ 'pluralize' => [ $rule->filters['milestone'] ] ] ) )
|
||||
],
|
||||
'sprintf' => [ \IPS\Member::loggedIn()->language()->addToStack('AchievementAction__VotePoll_title_generic') ]
|
||||
] );
|
||||
}
|
||||
|
||||
return \IPS\Theme::i()->getTemplate( 'achievements' )->ruleDescription(
|
||||
\IPS\Member::loggedIn()->language()->addToStack( 'AchievementAction__VotePoll_title' ),
|
||||
$conditions
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get rebuild data
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
static public function rebuildData()
|
||||
{
|
||||
return [ [
|
||||
'table' => 'core_voters',
|
||||
'pkey' => 'vid',
|
||||
'date' => 'vote_date',
|
||||
'where' => [],
|
||||
] ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the rebuild row
|
||||
*
|
||||
* @param array $row Row from database
|
||||
* @param array $data Data collected when starting rebuild [table, pkey...]
|
||||
* @return void
|
||||
*/
|
||||
public static function rebuildRow( $row, $data )
|
||||
{
|
||||
\IPS\Member::load( $row['member_id'] )->achievementAction( 'core', 'VotePoll', \IPS\Poll::load( $row['poll'] ) );
|
||||
}
|
||||
}
|
||||
@@ -95,7 +95,14 @@ class _Bulletin extends \IPS\core\AdminNotification
|
||||
return $this->_bulletinData;
|
||||
}
|
||||
|
||||
$data = \IPS\Db::i()->select( '*', 'core_ips_bulletins', array( 'id=?', $this->extra ) )->first();
|
||||
try
|
||||
{
|
||||
$data = \IPS\Db::i()->select( '*', 'core_ips_bulletins', array( 'id=?', $this->extra ) )->first();
|
||||
}
|
||||
catch( \UnderflowException $e )
|
||||
{
|
||||
$data = array( 'cached' => 0, 'id' => $this->extra );
|
||||
}
|
||||
|
||||
if ( ( time() - $data['cached'] ) > 3600 ) // If data was cached more than an hour ago, check again in case it's been updated
|
||||
{
|
||||
@@ -113,7 +120,9 @@ class _Bulletin extends \IPS\core\AdminNotification
|
||||
'dismissible' => $bulletin['dismissible'],
|
||||
'link' => $bulletin['link'],
|
||||
'conditions' => $bulletin['conditions'],
|
||||
'cached' => time()
|
||||
'cached' => time(),
|
||||
'min_version' => $bulletin['minVersion'],
|
||||
'max_version' => $bulletin['maxVersion']
|
||||
);
|
||||
\IPS\Db::i()->update( 'core_ips_bulletins', $data, array( 'id=?', $this->extra ) );
|
||||
}
|
||||
@@ -125,6 +134,20 @@ class _Bulletin extends \IPS\core\AdminNotification
|
||||
catch ( \Exception $e )
|
||||
{
|
||||
\IPS\Db::i()->update( 'core_ips_bulletins', array( 'cached' => ( time() + 3600 - 900 ) ), array( 'id=?', $this->extra ) ); // Try again in 15 minutes
|
||||
|
||||
$data = array(
|
||||
'id' => $data['id'],
|
||||
'title' => null,
|
||||
'body' => null,
|
||||
'severity' => null,
|
||||
'style' => null,
|
||||
'dismissible' => false,
|
||||
'link' => null,
|
||||
'conditions' => null,
|
||||
'cached' => ( time() + 3600 - 900 ),
|
||||
'min_version' => null,
|
||||
'max_version' => null
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,6 +226,16 @@ class _Bulletin extends \IPS\core\AdminNotification
|
||||
{
|
||||
try
|
||||
{
|
||||
if( $this->data()['min_version'] AND $this->data()['min_version'] > \IPS\Application::load('core')->long_version )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if( $this->data()['max_version'] AND $this->data()['max_version'] < \IPS\Application::load('core')->long_version )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return !@eval( $this->data()['conditions'] );
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
|
||||
@@ -158,11 +158,9 @@ class _ConfigurationError extends \IPS\core\AdminNotification
|
||||
/* CiC Email Quota */
|
||||
if ( \IPS\CIC )
|
||||
{
|
||||
preg_match( '/^\/var\/www\/html\/(.+?)(?:\/|$)/i', \IPS\ROOT_PATH, $matches );
|
||||
|
||||
try
|
||||
{
|
||||
$cicEmails = \IPS\Http\Url::external( "http://ips-cic-email.invisioncic.com/blocked.php?account={$matches[1]}" )->request()->get()->decodeJson();
|
||||
$cicEmails = \IPS\Http\Url::external( \IPS\IPS::$cicConfig['email']['quota_check'] )->setQueryString('account', \IPS\Cicloud\getCicUsername() )->request()->get()->decodeJson();
|
||||
|
||||
if ( isset( $cicEmails['status'] ) AND $cicEmails['status'] == 'BLOCKED' )
|
||||
{
|
||||
@@ -184,6 +182,18 @@ class _ConfigurationError extends \IPS\core\AdminNotification
|
||||
else
|
||||
{
|
||||
\IPS\core\AdminNotification::remove( 'core', 'ConfigurationError', 'failedMail' );
|
||||
\IPS\Db::i()->update( 'core_mail_error_logs', array( 'mlog_notification_sent' => TRUE ) );
|
||||
}
|
||||
|
||||
/* Username logins enabled */
|
||||
$login = new \IPS\Login;
|
||||
if( $login->authType() & \IPS\Login::AUTH_TYPE_USERNAME )
|
||||
{
|
||||
\IPS\core\AdminNotification::send( 'core', 'ConfigurationError', 'usernameLoginEnabled', FALSE );
|
||||
}
|
||||
else
|
||||
{
|
||||
\IPS\core\AdminNotification::remove( 'core', 'ConfigurationError', 'usernameLoginEnabled' );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -255,7 +265,8 @@ class _ConfigurationError extends \IPS\core\AdminNotification
|
||||
$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' )
|
||||
$member->hasAcpRestriction( 'core', 'marketplace', 'marketplace_manage' ) or
|
||||
$member->hasAcpRestriction( 'core', 'settings', 'login_access' )
|
||||
);
|
||||
}
|
||||
|
||||
@@ -319,6 +330,10 @@ class _ConfigurationError extends \IPS\core\AdminNotification
|
||||
{
|
||||
return $member->hasAcpRestriction( 'core', 'marketplace', 'marketplace_manage' );
|
||||
}
|
||||
elseif ( $this->extra === 'usernameLoginEnabled' )
|
||||
{
|
||||
return $member->hasAcpRestriction( 'core', 'settings', 'login_access' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -380,6 +395,10 @@ class _ConfigurationError extends \IPS\core\AdminNotification
|
||||
{
|
||||
return \IPS\Member::loggedIn()->language()->addToStack('marketplace_onboard_title');
|
||||
}
|
||||
elseif ( $this->extra === 'usernameLoginEnabled' )
|
||||
{
|
||||
return \IPS\Member::loggedIn()->language()->addToStack('username_login_enabled');
|
||||
}
|
||||
else
|
||||
{
|
||||
return htmlentities( $this->extra, ENT_DISALLOWED, 'UTF-8', FALSE );
|
||||
@@ -445,6 +464,10 @@ class _ConfigurationError extends \IPS\core\AdminNotification
|
||||
{
|
||||
return \IPS\Member::loggedIn()->language()->addToStack('marketplace_onboard_notification');
|
||||
}
|
||||
elseif ( $this->extra === 'usernameLoginEnabled' )
|
||||
{
|
||||
return \IPS\Member::loggedIn()->language()->addToStack('username_login_enabled_desc');
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -489,7 +512,16 @@ class _ConfigurationError extends \IPS\core\AdminNotification
|
||||
elseif ( $this->extra === 'recommendations' )
|
||||
{
|
||||
$requirementsAndRecommendations = \IPS\core\Setup\Upgrade::systemRequirements();
|
||||
return \IPS\Theme::i()->getTemplate( 'notifications', 'core' )->systemRecommendations( isset( $requirementsAndRecommendations['advice'] ) ? $requirementsAndRecommendations['advice'] : array() );
|
||||
$advice = array();
|
||||
|
||||
if( isset( $requirementsAndRecommendations['advice'] ) )
|
||||
{
|
||||
foreach( $requirementsAndRecommendations['advice'] as $category )
|
||||
{
|
||||
$advice = array_merge( $advice, $category );
|
||||
}
|
||||
}
|
||||
return \IPS\Theme::i()->getTemplate( 'notifications', 'core' )->systemRecommendations( $advice );
|
||||
}
|
||||
elseif ( $this->extra === 'origTables' )
|
||||
{
|
||||
@@ -526,6 +558,10 @@ class _ConfigurationError extends \IPS\core\AdminNotification
|
||||
{
|
||||
return \IPS\Theme::i()->getTemplate( 'notifications', 'core' )->marketplaceSetup();
|
||||
}
|
||||
elseif ( $this->extra === 'usernameLoginEnabled' )
|
||||
{
|
||||
return \IPS\Theme::i()->getTemplate( 'notifications', 'core' )->usernameLoginEnabled();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -560,6 +596,10 @@ class _ConfigurationError extends \IPS\core\AdminNotification
|
||||
{
|
||||
return static::DISMISSIBLE_NO;
|
||||
}
|
||||
elseif( $this->extra == 'usernameLoginEnabled' )
|
||||
{
|
||||
return static::DISMISSIBLE_PERMANENT;
|
||||
}
|
||||
else
|
||||
{
|
||||
return static::DISMISSIBLE_TEMPORARY;
|
||||
@@ -651,21 +691,10 @@ class _ConfigurationError extends \IPS\core\AdminNotification
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete AdminCP Notification
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function delete()
|
||||
{
|
||||
/* If deleting a failedMail notification, mark previous logs as notification sent */
|
||||
if( $this->extra == 'failedMail' )
|
||||
elseif( $this->extra == 'usernameLoginEnabled' )
|
||||
{
|
||||
\IPS\Db::i()->update( 'core_mail_error_logs', array( 'mlog_notification_sent' => TRUE ) );
|
||||
$login = new \IPS\Login;
|
||||
return !( $login->authType() & \IPS\Login::AUTH_TYPE_USERNAME );
|
||||
}
|
||||
|
||||
parent::delete();
|
||||
}
|
||||
}
|
||||
@@ -121,7 +121,7 @@ class _NewVersion extends \IPS\core\AdminNotification
|
||||
*/
|
||||
public function body()
|
||||
{
|
||||
return \IPS\Theme::i()->getTemplate( 'notifications', 'core', 'admin' )->newVersion( $this->_details );
|
||||
return \IPS\Theme::i()->getTemplate( 'notifications', 'core', 'global' )->newVersion( $this->_details );
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -184,7 +184,7 @@ class _Spammer extends \IPS\core\AdminNotification
|
||||
) as $user
|
||||
)
|
||||
{
|
||||
$users[ $user['member_id'] ]['member'] = \IPS\Member::constructFromData( $user );
|
||||
$users[ $user['member_id'] ] = array( 'member' => \IPS\Member::constructFromData( $user ), 'blurb' => '' );
|
||||
|
||||
foreach ( \IPS\Db::i()->select( '*', 'core_member_history', array( "log_member=? AND log_type='account'", $user['member_id'] ), 'log_date DESC', 50 ) as $row )
|
||||
{
|
||||
|
||||
@@ -89,8 +89,9 @@ class _Pixabay
|
||||
{
|
||||
$groups[ $group->g_id ] = $group->name;
|
||||
}
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\Select( 'pixabay_editor_permissions', \IPS\Settings::i()->pixabay_editor_permissions == '*' ? '*' : explode( ',', \IPS\Settings::i()->pixabay_editor_permissions ), NULL, array( 'multiple' => TRUE, 'options' => $groups, 'unlimited' => '*', 'unlimitedLang' => 'everyone' ), NULL, NULL, NULL, 'pixabay_editor_permissions_access' ) );
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'pixabay_safesearch', \IPS\Settings::i()->pixabay_safesearch, FALSE, array(), NULL, NULL, NULL, 'pixabay_safesearch' ) );
|
||||
$form->add( new \IPS\Helpers\Form\CheckboxSet( 'pixabay_editor_permissions', \IPS\Settings::i()->pixabay_editor_permissions == '*' ? '*' : explode( ',', \IPS\Settings::i()->pixabay_editor_permissions ), NULL, array( 'multiple' => TRUE, 'options' => $groups, 'unlimited' => '*', 'unlimitedLang' => 'everyone', 'impliedUnlimited' => TRUE ), NULL, NULL, NULL, 'pixabay_editor_permissions_access' ) );
|
||||
|
||||
if ( $values = $form->values() )
|
||||
{
|
||||
|
||||
@@ -77,7 +77,7 @@ class _SpamMonitoring
|
||||
}
|
||||
catch ( \LogicException $e )
|
||||
{
|
||||
// \IPS\Output::i()->error( $e->getMessage(), '2C116/2', 403, '' );
|
||||
\IPS\Output::i()->error( $e->getMessage(), '2C116/2', 403, '' );
|
||||
}
|
||||
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=moderation&controller=spam&tab=service' ) );
|
||||
|
||||
@@ -79,8 +79,8 @@ class _Viglink
|
||||
$form->add( new \IPS\Helpers\Form\Text( 'viglink_api_key', \IPS\Settings::i()->viglink_api_key, FALSE, array(), NULL, NULL, NULL, 'viglink_api_key' ) );
|
||||
}
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\Select( 'viglink_groups', ( \IPS\Settings::i()->viglink_groups == 'all' ) ? 'all' : explode( ',', \IPS\Settings::i()->viglink_groups ), FALSE, array( 'options' => \IPS\Member\Group::groups(), 'parse' => 'normal', 'multiple' => true, 'unlimited' => 'all', 'unlimitedLang' => 'all_groups' ), NULL, NULL, NULL, 'viglink_groups' ) );
|
||||
$form->add( new \IPS\Helpers\Form\Select( 'viglink_norewrite', explode( ',', \IPS\Settings::i()->viglink_norewrite ), FALSE, array( 'options' => \IPS\Member\Group::groups(), 'parse' => 'normal', 'multiple' => true ), NULL, NULL, NULL, 'viglink_norewrite' ) );
|
||||
$form->add( new \IPS\Helpers\Form\CheckboxSet( 'viglink_groups', ( \IPS\Settings::i()->viglink_groups == 'all' ) ? 'all' : explode( ',', \IPS\Settings::i()->viglink_groups ), FALSE, array( 'options' => \IPS\Member\Group::groups(), 'parse' => 'normal', 'multiple' => true, 'unlimited' => 'all', 'unlimitedLang' => 'all_groups', 'impliedUnlimited' => TRUE ), NULL, NULL, NULL, 'viglink_groups' ) );
|
||||
$form->add( new \IPS\Helpers\Form\CheckboxSet( 'viglink_norewrite', explode( ',', \IPS\Settings::i()->viglink_norewrite ), FALSE, array( 'options' => \IPS\Member\Group::groups(), 'parse' => 'normal', 'multiple' => true ), NULL, NULL, NULL, 'viglink_norewrite' ) );
|
||||
|
||||
if ( $values = $form->values( TRUE ) )
|
||||
{
|
||||
|
||||
@@ -261,6 +261,8 @@ class _Zapier
|
||||
|
||||
if ( $isNew )
|
||||
{
|
||||
\IPS\Lang::saveCustom( 'core', "core_api_name_{$apiKey->id}", "Zapier" );
|
||||
|
||||
throw new \DomainException;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -194,6 +194,48 @@ class _Reports
|
||||
{
|
||||
\IPS\Db::i()->update( 'core_rc_reports', $update, array( 'id=?', $report['id'] ) );
|
||||
}
|
||||
|
||||
/* Now rebuild any comments on this report */
|
||||
foreach( \IPS\Db::i()->select( '*', 'core_rc_comments', array( 'rid=?', $report['id'] ) ) as $comment )
|
||||
{
|
||||
$updateComment = NULL;
|
||||
|
||||
try
|
||||
{
|
||||
if( $callback == 'parseImageProxy' )
|
||||
{
|
||||
$updateComment = \IPS\Text\Parser::removeImageProxy( $comment['comment'], $this->proxyUrl );
|
||||
}
|
||||
elseif( $callback == 'parseLazyLoad' )
|
||||
{
|
||||
$updateComment = \IPS\Text\Parser::parseLazyLoad( $comment['comment'], $this->_lazyLoadStatus );
|
||||
}
|
||||
elseif( $callback[1] == 'rebuildAttachmentUrls' )
|
||||
{
|
||||
$updateComment = \IPS\Text\Parser::rebuildAttachmentUrls( $comment['comment'], \IPS\Member::load( $comment['comment_by'] ) );
|
||||
}
|
||||
elseif( $callback[1] == 'parseStatic' )
|
||||
{
|
||||
$updateComment = $callback( $comment['comment'], \IPS\Member::load( $comment['comment_by'] ), FALSE, 'core_Reports', $comment['id'], NULL, NULL );
|
||||
}
|
||||
}
|
||||
catch( \InvalidArgumentException $e )
|
||||
{
|
||||
if( $callback[1] == 'parseStatic' AND $e->getcode() == 103014 )
|
||||
{
|
||||
$updateComment = preg_replace( "#\[/?([^\]]+?)\]#", '', $comment['comment'] );
|
||||
}
|
||||
else
|
||||
{
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
if( $updateComment )
|
||||
{
|
||||
\IPS\Db::i()->update( 'core_rc_comments', array( 'comment' => $updateComment ), array( 'id=?', $comment['id'] ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $did;
|
||||
|
||||
@@ -75,6 +75,10 @@ class _Attachment
|
||||
foreach ( \IPS\Db::i()->select( 'core_attachments.*', 'core_attachments', $where, 'attach_date DESC', array( ( $page - 1 ) * $limit, $limit ) ) as $row )
|
||||
{
|
||||
$url = \IPS\Settings::i()->base_url . "applications/core/interface/file/attachment.php?id={$row['attach_id']}";
|
||||
if ( $row['attach_security_key'] )
|
||||
{
|
||||
$url .= "&key={$row['attach_security_key']}";
|
||||
}
|
||||
$obj = \IPS\File::get( 'core_Attachment', $row['attach_location'] );
|
||||
$obj->originalFilename = $row['attach_file'];
|
||||
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief File Storage Extension: Badges
|
||||
* @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 23 Feb 2021
|
||||
*/
|
||||
|
||||
namespace IPS\core\extensions\core\FileStorage;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* File Storage Extension: Badges
|
||||
*/
|
||||
class _Badges
|
||||
{
|
||||
/**
|
||||
* Count stored files
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function count()
|
||||
{
|
||||
return \IPS\Db::i()->select( 'COUNT(*)', 'core_badges', 'image IS NOT NULL' )->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* Move stored files
|
||||
*
|
||||
* @param int $offset This will be sent starting with 0, increasing to get all files stored by this extension
|
||||
* @param int $storageConfiguration New storage configuration ID
|
||||
* @param int|NULL $oldConfiguration Old storage configuration ID
|
||||
* @throws \UnderflowException When file record doesn't exist. Indicating there are no more files to move
|
||||
* @return void|int An offset integer to use on the next cycle, or nothing
|
||||
*/
|
||||
public function move( $offset, $storageConfiguration, $oldConfiguration=NULL )
|
||||
{
|
||||
$badgeData = \IPS\Db::i()->select( '*', 'core_badges', 'image IS NOT NULL', 'id', array( $offset, 1 ) )->first();
|
||||
|
||||
try
|
||||
{
|
||||
$file = \IPS\File::get( $oldConfiguration ?: 'core_Badges', $badgeData['image'] )->move( $storageConfiguration );
|
||||
|
||||
if ( (string) $file != $badgeData['image'] )
|
||||
{
|
||||
\IPS\Db::i()->update( 'core_badges', array( 'image' => (string) $file ), array( 'id=?', $badgeData['id'] ) );
|
||||
}
|
||||
}
|
||||
catch( \Exception $e )
|
||||
{
|
||||
/* Any issues are logged */
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fix all URLs
|
||||
*
|
||||
* @param int $offset This will be sent starting with 0, increasing to get all files stored by this extension
|
||||
* @return void
|
||||
*/
|
||||
public function fixUrls( $offset )
|
||||
{
|
||||
$badgeData = \IPS\Db::i()->select( '*', 'core_badges', 'image IS NOT NULL', 'id', array( $offset, 1 ) )->first();
|
||||
|
||||
try
|
||||
{
|
||||
if ( $new = \IPS\File::repairUrl( $badgeData['image'] ) )
|
||||
{
|
||||
\IPS\Db::i()->update( 'core_badges', [ 'image' => $new ], array( 'id=?', $badgeData['id'] ) );
|
||||
}
|
||||
}
|
||||
catch( \Exception $e ) { }
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a file is valid
|
||||
*
|
||||
* @param string $file The file path to check
|
||||
* @return bool
|
||||
*/
|
||||
public function isValidFile( $file )
|
||||
{
|
||||
try
|
||||
{
|
||||
$badgeData = \IPS\Db::i()->select( '*', 'core_badges', array( 'image=?', (string) $file ) )->first();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
catch ( \UnderflowException $e )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all stored files
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function delete()
|
||||
{
|
||||
foreach( \IPS\Db::i()->select( '*', 'core_badges', 'image IS NOT NULL' ) as $badgeData )
|
||||
{
|
||||
try
|
||||
{
|
||||
\IPS\File::get( 'core_Badges', $badgeData['image'] )->delete();
|
||||
}
|
||||
catch( \Exception $e ){}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief File Storage Extension: Feature
|
||||
* @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 10 Sep 2019
|
||||
*/
|
||||
|
||||
namespace IPS\core\extensions\core\FileStorage;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* File Storage Extension: Feature
|
||||
*/
|
||||
class _Feature
|
||||
{
|
||||
/**
|
||||
* Count stored files
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function count()
|
||||
{
|
||||
return \IPS\Db::i()->select( 'COUNT(*)', 'core_members_features', array( "feature_image IS NOT NULL" ) )->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* Move stored files
|
||||
*
|
||||
* @param int $offset This will be sent starting with 0, increasing to get all files stored by this extension
|
||||
* @param int $storageConfiguration New storage configuration ID
|
||||
* @param int|NULL $oldConfiguration Old storage configuration ID
|
||||
* @throws \UnderflowException When file record doesn't exist. Indicating there are no more files to move
|
||||
* @return void|int An offset integer to use on the next cycle, or nothing
|
||||
*/
|
||||
public function move( $offset, $storageConfiguration, $oldConfiguration=NULL )
|
||||
{
|
||||
$feature = \IPS\Db::i()->select( '*', 'core_members_features', array( "feature_image IS NOT NULL" ), 'feature_id', array( $offset, 1 ) )->first();
|
||||
|
||||
$url = (string) \IPS\File::get( $oldConfiguration ?: 'core_Feature', $feature['feature_image'] )->move( $storageConfiguration );
|
||||
|
||||
if ( $url != $feature['feature_image'] )
|
||||
{
|
||||
\IPS\Db::i()->update( 'core_members_features', array( 'feature_image' => $url ), array( 'feature_id=?', $feature['feature_id'] ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a file is valid
|
||||
*
|
||||
* @param string $file The file path to check
|
||||
* @return bool
|
||||
*/
|
||||
public function isValidFile( $file )
|
||||
{
|
||||
try
|
||||
{
|
||||
\IPS\Db::i()->select( '*', 'core_members_features', array( "feature_image=?", $file ) )->first();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
catch( \UnderflowException $e )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all stored files
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function delete()
|
||||
{
|
||||
foreach( \IPS\Db::i()->select( 'feature_image', 'core_members_features', array( "feature_image IS NOT NULL" ) ) AS $file )
|
||||
{
|
||||
\IPS\File::get( 'core_Feature', $file )->delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -41,6 +41,11 @@ class _Icons
|
||||
$count += \count( json_decode( \IPS\Settings::i()->icons_homescreen, TRUE ) );
|
||||
}
|
||||
|
||||
if( \IPS\Settings::i()->icons_apple_startup )
|
||||
{
|
||||
$count += \count( json_decode( \IPS\Settings::i()->icons_apple_startup, TRUE ) );
|
||||
}
|
||||
|
||||
if( \IPS\Settings::i()->icons_mask_icon )
|
||||
{
|
||||
$count += 1;
|
||||
@@ -62,7 +67,14 @@ class _Icons
|
||||
{
|
||||
if( \IPS\Settings::i()->icons_favicon )
|
||||
{
|
||||
\IPS\File::get( $oldConfiguration ?: 'core_Icons', \IPS\Settings::i()->icons_favicon )->move( $storageConfiguration );
|
||||
try
|
||||
{
|
||||
\IPS\File::get( $oldConfiguration ?: 'core_Icons', \IPS\Settings::i()->icons_favicon )->move( $storageConfiguration );
|
||||
}
|
||||
catch( \Exception $e )
|
||||
{
|
||||
/* Any issues are logged */
|
||||
}
|
||||
}
|
||||
|
||||
if( \IPS\Settings::i()->icons_sharer_logo )
|
||||
@@ -71,7 +83,14 @@ class _Icons
|
||||
|
||||
foreach( $logos as $logo )
|
||||
{
|
||||
\IPS\File::get( $oldConfiguration ?: 'core_Icons', $logo )->move( $storageConfiguration );
|
||||
try
|
||||
{
|
||||
\IPS\File::get( $oldConfiguration ?: 'core_Icons', $logo )->move( $storageConfiguration );
|
||||
}
|
||||
catch( \Exception $e )
|
||||
{
|
||||
/* Any issues are logged */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,13 +100,44 @@ class _Icons
|
||||
|
||||
foreach( $homeScreen as $key => $logo )
|
||||
{
|
||||
\IPS\File::get( $oldConfiguration ?: 'core_Icons', ( $key == 'original' ) ? $logo : $logo['url'] )->move( $storageConfiguration );
|
||||
try
|
||||
{
|
||||
\IPS\File::get( $oldConfiguration ?: 'core_Icons', ( $key == 'original' ) ? $logo : $logo['url'] )->move( $storageConfiguration );
|
||||
}
|
||||
catch( \Exception $e )
|
||||
{
|
||||
/* Any issues are logged */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( \IPS\Settings::i()->icons_apple_startup )
|
||||
{
|
||||
$apple = json_decode( \IPS\Settings::i()->icons_apple_startup, TRUE );
|
||||
|
||||
foreach( $apple as $key => $logo )
|
||||
{
|
||||
try
|
||||
{
|
||||
\IPS\File::get( $oldConfiguration ?: 'core_Icons', ( $key == 'original' ) ? $logo : $logo['url'] )->move( $storageConfiguration );
|
||||
}
|
||||
catch( \Exception $e )
|
||||
{
|
||||
/* Any issues are logged */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( \IPS\Settings::i()->icons_mask_icon )
|
||||
{
|
||||
\IPS\File::get( $oldConfiguration ?: 'core_Icons', \IPS\Settings::i()->icons_mask_icon )->move( $storageConfiguration );
|
||||
try
|
||||
{
|
||||
\IPS\File::get( $oldConfiguration ?: 'core_Icons', \IPS\Settings::i()->icons_mask_icon )->move( $storageConfiguration );
|
||||
}
|
||||
catch( \Exception $e )
|
||||
{
|
||||
/* Any issues are logged */
|
||||
}
|
||||
}
|
||||
|
||||
throw new \UnderflowException;
|
||||
@@ -140,6 +190,26 @@ class _Icons
|
||||
$updated['icons_homescreen'] = json_encode( $newLogos );
|
||||
}
|
||||
|
||||
if( \IPS\Settings::i()->icons_apple_startup )
|
||||
{
|
||||
$newLogos = array();
|
||||
|
||||
foreach( json_decode( \IPS\Settings::i()->icons_apple_startup, TRUE ) as $key => $logo )
|
||||
{
|
||||
if( $key == 'original' )
|
||||
{
|
||||
$newLogos[ $key ] = \IPS\File::repairUrl( $logo );
|
||||
}
|
||||
else
|
||||
{
|
||||
$newLogos[ $key ] = $logo;
|
||||
$newLogos[ $key ]['url'] = \IPS\File::repairUrl( $logo['url'] );
|
||||
}
|
||||
}
|
||||
|
||||
$updated['icons_apple_startup'] = json_encode( $newLogos );
|
||||
}
|
||||
|
||||
if( \IPS\Settings::i()->icons_mask_icon )
|
||||
{
|
||||
$updated['icons_mask_icon'] = \IPS\File::repairUrl( \IPS\Settings::i()->icons_mask_icon );
|
||||
@@ -187,6 +257,17 @@ class _Icons
|
||||
}
|
||||
}
|
||||
|
||||
if( \IPS\Settings::i()->icons_apple_startup )
|
||||
{
|
||||
foreach( json_decode( \IPS\Settings::i()->icons_apple_startup, TRUE ) as $key => $logo )
|
||||
{
|
||||
if( ( $key == 'original' AND $file == $logo ) OR ( $key != 'original' AND $file == $logo['url'] ) )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( \IPS\Settings::i()->icons_mask_icon AND $file == \IPS\Settings::i()->icons_mask_icon )
|
||||
{
|
||||
return TRUE;
|
||||
@@ -235,6 +316,18 @@ class _Icons
|
||||
}
|
||||
}
|
||||
|
||||
if( \IPS\Settings::i()->icons_apple_startup )
|
||||
{
|
||||
foreach( json_decode( \IPS\Settings::i()->icons_apple_startup, TRUE ) as $key => $logo )
|
||||
{
|
||||
try
|
||||
{
|
||||
\IPS\File::get( 'core_Icons', ( $key == 'original' ) ? $logo : $logo['url'] )->delete();
|
||||
}
|
||||
catch( \OutOfRangeException $e ){}
|
||||
}
|
||||
}
|
||||
|
||||
if( \IPS\Settings::i()->icons_mask_icon )
|
||||
{
|
||||
try
|
||||
@@ -244,6 +337,6 @@ class _Icons
|
||||
catch( \OutOfRangeException $e ){}
|
||||
}
|
||||
|
||||
\IPS\Settings::i()->changeValues( array( 'icons_favicon' => NULL, 'icons_sharer_logo' => NULL, 'icons_homescreen' => NULL, 'icons_mask_icon' => NULL ) );
|
||||
\IPS\Settings::i()->changeValues( array( 'icons_favicon' => NULL, 'icons_sharer_logo' => NULL, 'icons_homescreen' => NULL, 'icons_apple_startup' => NULL, 'icons_mask_icon' => NULL ) );
|
||||
}
|
||||
}
|
||||
@@ -45,7 +45,14 @@ class _Reaction
|
||||
{
|
||||
$reaction = \IPS\Db::i()->select( '*', 'core_reactions', array(), 'reaction_id', array( $offset, 1 ) )->first();
|
||||
|
||||
$url = (string) \IPS\File::get( $oldConfiguration ?: 'core_Reaction', $reaction['reaction_icon'] )->move( $storageConfiguration );
|
||||
try
|
||||
{
|
||||
$url = (string) \IPS\File::get( $oldConfiguration ?: 'core_Reaction', $reaction['reaction_icon'] )->move( $storageConfiguration );
|
||||
}
|
||||
catch( \Exception $e )
|
||||
{
|
||||
/* Any issues are logged */
|
||||
}
|
||||
|
||||
if ( $url != $reaction['reaction_icon'] )
|
||||
{
|
||||
|
||||
@@ -73,6 +73,25 @@ class _Content
|
||||
$form->addHeader( 'group_viewing_title' );
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'gbw_post_highlight', $group->g_id ? $group->g_bitoptions['gbw_post_highlight'] : FALSE ) );
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'gbw_hide_inline_modevents', $group->g_id ? !$group->g_bitoptions['gbw_hide_inline_modevents'] : TRUE ) );
|
||||
|
||||
$groupItemPostedIn = 'disabled';
|
||||
if ( $group->g_bitoptions['gbw_posted_in'] )
|
||||
{
|
||||
$groupItemPostedIn = 'primary';
|
||||
}
|
||||
if ( $group->g_bitoptions['gbw_posted_in_secondary'] )
|
||||
{
|
||||
$groupItemPostedIn = 'both';
|
||||
}
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\Radio( 'gbw_posted_in', $groupItemPostedIn, FALSE, array(
|
||||
'options' => array(
|
||||
'primary' => 'gbw_posted_in_primary',
|
||||
'both' => 'gbw_posted_in_secondary',
|
||||
'disabled' => 'gbw_posted_in_disabled'
|
||||
)
|
||||
) ) );
|
||||
|
||||
/* Tags */
|
||||
$form->addHeader( 'tags' );
|
||||
@@ -138,7 +157,6 @@ class _Content
|
||||
|
||||
if( $group->g_id != \IPS\Settings::i()->guest_group )
|
||||
{
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'gbw_immune_auto_mod', $group->g_bitoptions['gbw_immune_auto_mod'] ) );
|
||||
$form->add( new \IPS\Helpers\Form\CheckboxSet( 'g_lock_unlock_own', !$group->g_lock_unlock_own ? 0 : ( $group->g_lock_unlock_own == '1' ? '1' : explode( ',', $group->g_lock_unlock_own ) ), FALSE, array(
|
||||
'options' => array_filter( $contentClasses, function( $class ) {
|
||||
@@ -224,7 +242,26 @@ class _Content
|
||||
$values['gbw_disable_tagging'] = \IPS\Settings::i()->tags_enabled ? !$values['gbw_disable_tagging'] : $group->g_bitoptions['gbw_disable_tagging'];
|
||||
$values['gbw_disable_prefixes'] = ( \IPS\Settings::i()->tags_enabled AND \IPS\Settings::i()->tags_can_prefix ) ? !$values['gbw_disable_prefixes'] : $group->g_bitoptions['gbw_disable_prefixes'];
|
||||
|
||||
$bwKeys = array( 'gbw_disable_tagging', 'gbw_disable_prefixes', 'gbw_delete_attachments', 'gbw_post_highlight', 'gbw_promote', 'gbw_immune_auto_mod' );
|
||||
/* This is an inverse setting - the UI says "Show .." but the setting actually causes it to be hidden. */
|
||||
$values['gbw_hide_inline_modevents'] = !$values['gbw_hide_inline_modevents'];
|
||||
|
||||
switch( $values['gbw_posted_in'] )
|
||||
{
|
||||
case 'primary':
|
||||
$values['gbw_posted_in'] = 1;
|
||||
$values['gbw_posted_in_secondary'] = 0;
|
||||
break;
|
||||
case 'both':
|
||||
$values['gbw_posted_in'] = 1;
|
||||
$values['gbw_posted_in_secondary'] = 1;
|
||||
break;
|
||||
case 'disabled':
|
||||
$values['gbw_posted_in'] = 0;
|
||||
$values['gbw_posted_in_secondary'] = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
$bwKeys = array( 'gbw_disable_tagging', 'gbw_disable_prefixes', 'gbw_delete_attachments', 'gbw_post_highlight', 'gbw_promote', 'gbw_immune_auto_mod', 'gbw_hide_inline_modevents', 'gbw_posted_in', 'gbw_posted_in_secondary' );
|
||||
|
||||
foreach ( $bwKeys as $k )
|
||||
{
|
||||
|
||||
@@ -191,6 +191,8 @@ class _GroupSettings
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'can_be_ignored', $group->g_id ? ( !$group->g_bitoptions['gbw_cannot_be_ignored'] ) : TRUE, FALSE, array(), NULL, NULL, NULL, 'gbw_cannot_be_ignored' ) );
|
||||
}
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'can_post_anonymously', $group->g_id ? ( $group->g_bitoptions['gbw_can_post_anonymously'] ) : FALSE, FALSE, array(), NULL, NULL, NULL, 'gbw_can_post_anonymously' ) );
|
||||
|
||||
/* Signatures */
|
||||
if( \IPS\Settings::i()->signatures_enabled AND $group->g_id != \IPS\Settings::i()->guest_group )
|
||||
{
|
||||
@@ -302,6 +304,11 @@ class _GroupSettings
|
||||
{
|
||||
$group->g_bitoptions['gbw_cannot_be_ignored'] = !$values['can_be_ignored'];
|
||||
}
|
||||
|
||||
if ( isset( $values['can_post_anonymously'] ) )
|
||||
{
|
||||
$group->g_bitoptions['gbw_can_post_anonymously'] = $values['can_post_anonymously'];
|
||||
}
|
||||
|
||||
/* Update existing sessions if this setting is changed */
|
||||
if( isset( $values['g_hide_online_list'] ) AND $group->g_hide_online_list != (int) $values['g_hide_online_list'] )
|
||||
|
||||
@@ -36,7 +36,7 @@ class _GroupLimits
|
||||
'exclude' => array( 'g_id', 'g_icon', 'prefix', 'suffix', 'g_promotion', 'g_bitoptions' ),
|
||||
'lessIsMore' => array( 'g_search_flood', 'g_pm_flood_mins' ),
|
||||
'neg1IsBest' => array( 'g_attach_max', 'g_max_bgimg_upload', 'g_max_messages', 'g_pm_perday', 'g_pm_flood_mins', 'g_max_mass_pm', 'g_rep_max_positive' ),
|
||||
'zeroIsBest' => array( 'g_displayname_unit', 'g_sig_unit', 'g_mod_preview', 'g_ppd_limit', 'g_ppd_unit', 'gbw_no_status_update', 'g_max_bgimg_upload', 'gbw_disable_prefixes', 'gbw_disable_tagging', 'g_hide_online_list' ),
|
||||
'zeroIsBest' => array( 'g_displayname_unit', 'g_sig_unit', 'g_mod_preview', 'g_ppd_limit', 'g_ppd_unit', 'gbw_no_status_update', 'g_max_bgimg_upload', 'gbw_disable_prefixes', 'gbw_disable_tagging' ),
|
||||
'callback' => array(
|
||||
'g_edit_cutoff' => array( $this, '_editCutoff' ),
|
||||
'g_attach_per_post' => array( $this, '_attachMaxPerPost' ),
|
||||
@@ -53,10 +53,39 @@ class _GroupLimits
|
||||
'g_can_report' => array( $this, '_perAppSettings' ),
|
||||
'g_club_allowed_nodes' => array( $this, '_clubNodes' ),
|
||||
'g_create_clubs' => array( $this, '_createClub' ),
|
||||
'g_hide_online_list' => array( $this, '_hideOnlineList' ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow users in the group to login anonymously?
|
||||
*
|
||||
* @param array $a Group A's values
|
||||
* @param array $b Group B's values
|
||||
* @param string $k The key we want to get the combined value for
|
||||
* @param array $member Member data
|
||||
* @return mixed
|
||||
*/
|
||||
public function _hideOnlineList( $a, $b, $k, $member )
|
||||
{
|
||||
/* If any group is forced, use that as priority */
|
||||
if( $a[$k] == 1 OR $b[$k] == 1 )
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
/* Else if any group allows anonymous logins, allow them */
|
||||
elseif( $a[$k] == 0 OR $b[$k] == 0 )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
/* Otherwise disable them */
|
||||
else
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cutoff for editing - only use a group's value if the group is able to edit
|
||||
*
|
||||
|
||||
@@ -119,6 +119,6 @@ class _Ratings
|
||||
*/
|
||||
public function findByMember( $member )
|
||||
{
|
||||
return \IPS\Db::i()->select( "ip, count(*) AS count, 0 AS first, 0 AS last", 'core_ratings', array( '`member`=?', $member->member_id ), NULL, NULL, 'ip' )->setKeyField( 'ip' );
|
||||
return \IPS\Db::i()->select( "ip, count(*) AS count, MIN(rating_date) AS first, MAX(rating_date) AS last", 'core_ratings', array( '`member`=?', $member->member_id ), NULL, NULL, 'ip' )->setKeyField( 'ip' );
|
||||
}
|
||||
}
|
||||
@@ -124,7 +124,7 @@ class _ContentStatistics extends \IPS\core\MemberACPProfile\TabbedBlock
|
||||
$this->rawCounts[ $app ][ $class ] = 0;
|
||||
}
|
||||
|
||||
$count = $class::rawMemberPostCount( $member );
|
||||
$count = $class::memberPostCount( $member, TRUE );
|
||||
$sum += $count;
|
||||
$counts[ $app ][ $type ] += $count;
|
||||
$this->rawCounts[ $app ][ $class ] += $count;
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief ACP Member Profile Block
|
||||
* @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 25 Feb 2021
|
||||
*/
|
||||
|
||||
namespace IPS\core\extensions\core\MemberACPProfileBlocks;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief ACP Member Profile Block
|
||||
*/
|
||||
class _Points extends \IPS\core\MemberACPProfile\Block
|
||||
{
|
||||
/**
|
||||
* Get output
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function output()
|
||||
{
|
||||
return \IPS\Theme::i()->getTemplate('memberprofile')->rank( $this->member );
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit Window
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function edit()
|
||||
{
|
||||
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'members', 'member_edit' ) )
|
||||
{
|
||||
\IPS\Output::i()->sidebar['actions']['addpoints'] = array(
|
||||
'primary' => true,
|
||||
'icon' => 'pencil',
|
||||
'link' => $this->member->acpUrl()->setQueryString('do', 'points')->csrf(),
|
||||
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('acp_profile_points_manage_title' ) ),
|
||||
'title' => \IPS\Member::loggedIn()->language()->addToStack('acp_profile_edit_points', NULL, [ 'sprintf' => $this->member->name ] ),
|
||||
);
|
||||
}
|
||||
|
||||
$table = new \IPS\Helpers\Table\Db( 'core_points_log', $this->member->acpUrl()->setQueryString( array( 'do' => 'editBlock', 'block' => \get_class( $this ) ) ), [ [ 'member=?', $this->member->member_id ] ] );
|
||||
$table->joins[] = [
|
||||
'select' => 'action,identifier',
|
||||
'from' => 'core_achievements_log',
|
||||
'where' => 'core_achievements_log.id=core_points_log.action_log',
|
||||
'type' => 'LEFT'
|
||||
];
|
||||
|
||||
$table->include = [ 'action_log', 'new_rank', 'points', 'balance', 'datetime' ];
|
||||
$table->sortBy = $table->sortBy ?: 'datetime';
|
||||
$table->langPrefix = 'acp_points_log_table_';
|
||||
|
||||
/* Filters */
|
||||
$table->filters = [
|
||||
'acp_manage_points_manual' => '(LENGTH(core_points_log.rules)=0)',
|
||||
'acp_manage_points_rule' => '(LENGTH(core_points_log.rules)>0)',
|
||||
'acp_manage_points_promote' => '(new_rank IS NOT NULL)'
|
||||
];
|
||||
|
||||
$table->parsers = [
|
||||
'action_log' => function( $val, $row ) {
|
||||
$exploded = explode( '_', $row['action'] );
|
||||
|
||||
if ( isset( $exploded[1] ) )
|
||||
{
|
||||
$extension = \IPS\Application::load( $exploded[0] )->extensions( 'core', 'AchievementAction' )[$exploded[1]];
|
||||
return $extension->logRow( $row['identifier'], explode( ',', $row['actor'] ) );
|
||||
}
|
||||
else if ( isset( $row['rules'] ) and empty( $row['rules'] ) )
|
||||
{
|
||||
return \IPS\Member::loggedIn()->language()->addToStack( 'acp_points_log_manual');
|
||||
}
|
||||
else
|
||||
{
|
||||
return \IPS\Member::loggedIn()->language()->addToStack( 'acp_points_rule_deleted');
|
||||
}
|
||||
},
|
||||
'datetime' => function( $val ) {
|
||||
return \IPS\DateTime::ts( $val );
|
||||
},
|
||||
'new_rank' => function( $val, $row )
|
||||
{
|
||||
if ( ! $val )
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
$rank = \IPS\core\Achievements\Rank::load( $val );
|
||||
return \IPS\Theme::i()->getTemplate( 'global' )->genericLink( \IPS\Http\Url::internal( "app=core&module=achievements&controller=ranks", 'admin' ), $rank->_title );
|
||||
}
|
||||
catch( \Exception $e )
|
||||
{
|
||||
return \IPS\Member::loggedIn()->language()->addToStack('deleted');
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('acp_profile_points_manage_title');
|
||||
return \IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'members' )->pointsLog( $table, $this->member );
|
||||
}
|
||||
}
|
||||
@@ -64,7 +64,7 @@ class _ProfileData extends \IPS\core\MemberACPProfile\TabbedBlock
|
||||
public function tabs()
|
||||
{
|
||||
$return = array();
|
||||
if ( \count( $this->fields ) || $this->member->member_title || $this->member->rank['title'] || $this->member->rank['image'] || \IPS\Settings::i()->profile_birthday_type != 'none' || \IPS\Settings::i()->signatures_enabled )
|
||||
if ( \count( $this->fields ) || $this->member->rank['title'] || $this->member->rank['image'] || \IPS\Settings::i()->profile_birthday_type != 'none' || \IPS\Settings::i()->signatures_enabled )
|
||||
{
|
||||
$return['fields'] = 'profile_fields';
|
||||
}
|
||||
@@ -113,7 +113,6 @@ class _ProfileData extends \IPS\core\MemberACPProfile\TabbedBlock
|
||||
/* Build basic form */
|
||||
$form = new \IPS\Helpers\Form;
|
||||
$form->addHeader('profile_data');
|
||||
$form->add( new \IPS\Helpers\Form\Text( 'member_title', $this->member->member_title, FALSE, array( 'maxLength' => 64 ) ) );
|
||||
if ( \IPS\Settings::i()->profile_birthday_type !== 'none' )
|
||||
{
|
||||
$form->add( new \IPS\Helpers\Form\Custom( 'bday', array( 'year' => $this->member->bday_year, 'month' => $this->member->bday_month, 'day' => $this->member->bday_day ), FALSE, array( 'getHtml' => function( $element )
|
||||
@@ -188,7 +187,6 @@ class _ProfileData extends \IPS\core\MemberACPProfile\TabbedBlock
|
||||
\IPS\Db::i()->replace( 'core_pfields_content', $profileFields );
|
||||
|
||||
/* Profile Preferences */
|
||||
$this->member->member_title = $values['member_title'];
|
||||
if ( $values['bday'] )
|
||||
{
|
||||
$this->member->bday_day = $values['bday']['day'];
|
||||
|
||||
@@ -59,6 +59,7 @@ class _Main extends \IPS\core\MemberACPProfile\MainTab
|
||||
return array(
|
||||
'IPS\core\extensions\core\MemberACPProfileBlocks\Header',
|
||||
'IPS\core\extensions\core\MemberACPProfileBlocks\ContentStatistics',
|
||||
'IPS\core\extensions\core\MemberACPProfileBlocks\Points',
|
||||
'IPS\core\extensions\core\MemberACPProfileBlocks\Quotas',
|
||||
'IPS\core\extensions\core\MemberACPProfileBlocks\Warnings',
|
||||
'IPS\core\extensions\core\MemberACPProfileBlocks\ProfileData',
|
||||
|
||||
@@ -43,7 +43,6 @@ class _Main
|
||||
'last_post',
|
||||
'birthday',
|
||||
'allow_admin_mails',
|
||||
'member_title'
|
||||
);
|
||||
|
||||
foreach( $columns as $col )
|
||||
|
||||
@@ -56,11 +56,12 @@ class _Group
|
||||
}
|
||||
|
||||
return array(
|
||||
new \IPS\Helpers\Form\Select( 'bmf_members_groups', ( isset( $criteria['groups'] ) AND $criteria['groups'] != 'all' ) ? explode( ',', $criteria['groups'] ) : 'all', FALSE, array(
|
||||
new \IPS\Helpers\Form\CheckboxSet( 'bmf_members_groups', ( isset( $criteria['groups'] ) AND $criteria['groups'] != 'all' ) ? explode( ',', $criteria['groups'] ) : 'all', FALSE, array(
|
||||
'options' => $criteria['options'],
|
||||
'multiple' => TRUE,
|
||||
'unlimited' => 'all',
|
||||
'unlimitedLang' => 'all_groups'
|
||||
'unlimitedLang' => 'all_groups',
|
||||
'impliedUnlimited' => TRUE
|
||||
) )
|
||||
);
|
||||
}
|
||||
|
||||
@@ -43,7 +43,9 @@ class _Core
|
||||
'mfa',
|
||||
'oauth',
|
||||
'admin_mails',
|
||||
'terms_acceptance'
|
||||
'terms_acceptance',
|
||||
'points',
|
||||
'badges'
|
||||
);
|
||||
}
|
||||
|
||||
@@ -62,7 +64,7 @@ class _Core
|
||||
$byStaff = '';
|
||||
if ( $row['log_by'] )
|
||||
{
|
||||
if ( $row['log_by'] === $row['log_member'] )
|
||||
if ( $row['log_by'] === $row['log_member'] and ( $row['log_type'] !== 'points' and $row['log_type'] !== 'badges' ) )
|
||||
{
|
||||
$byMember = \IPS\Member::loggedIn()->language()->addToStack('history_by_member');
|
||||
}
|
||||
@@ -559,7 +561,7 @@ class _Core
|
||||
$consequences = array();
|
||||
if ( isset( $jsonValue['consequences'] ) )
|
||||
{
|
||||
foreach ( array( 'modq' => 'mod_posts', 'nopost' => 'restrict_post', 'banned' => 'temp_ban' ) as $k => $v )
|
||||
foreach ( array( 'modq' => 'mod_posts', 'nopost' => 'restrict_post', 'banned' => 'temp_ban', 'cheev_point_reduction' => 'cheev_point_reduction' ) as $k => $v )
|
||||
{
|
||||
if ( isset( $jsonValue['consequences'][ $v ] ) )
|
||||
{
|
||||
@@ -576,16 +578,23 @@ class _Core
|
||||
$consequences = array();
|
||||
if ( isset( $jsonValue['consequences'] ) )
|
||||
{
|
||||
foreach ( array( 'modq' => 'mod_posts', 'nopost' => 'restrict_post', 'banned' => 'temp_ban' ) as $k => $v )
|
||||
foreach ( array( 'modq' => 'mod_posts', 'nopost' => 'restrict_post', 'banned' => 'temp_ban', 'cheev_point_reduction' => 'cheev_point_reduction' ) as $k => $v )
|
||||
{
|
||||
if ( isset( $jsonValue['consequences'][ $v ] ) )
|
||||
{
|
||||
$c = \IPS\Member::loggedIn()->language()->addToStack( 'moderation_' . $k );
|
||||
if ( $jsonValue['consequences'][ $v ] != -1 )
|
||||
if( $v == 'cheev_point_reduction' )
|
||||
{
|
||||
$c = \IPS\Member::loggedIn()->language()->addToStack( 'history_received_warning_penalty_time', FALSE, array( 'sprintf' => array( $c, \IPS\DateTime::formatInterval( new \DateInterval( $jsonValue['consequences'][ $v ] ), 2 ) ) ) );
|
||||
$consequences[]= \IPS\Member::loggedIn()->language()->addToStack( 'moderation_cheev_point_reduction', FALSE, array('sprintf' => array( $jsonValue['consequences'][ $v ] ) ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
$c = \IPS\Member::loggedIn()->language()->addToStack( 'moderation_' . $k );
|
||||
if ( $jsonValue['consequences'][$v] != -1 )
|
||||
{
|
||||
$c = \IPS\Member::loggedIn()->language()->addToStack( 'history_received_warning_penalty_time', FALSE, array('sprintf' => array($c, \IPS\DateTime::formatInterval( new \DateInterval( $jsonValue['consequences'][$v] ), 2 ))) );
|
||||
}
|
||||
$consequences[] = $c;
|
||||
}
|
||||
$consequences[] = $c;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -696,8 +705,48 @@ class _Core
|
||||
return \IPS\Member::loggedIn()->language()->addToStack('history_terms_accepted_terms');
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'points':
|
||||
if ( isset( $jsonValue['recognize'] ) )
|
||||
{
|
||||
try
|
||||
{
|
||||
$recognize = \IPS\core\Achievements\Recognize::load( $jsonValue['recognize'] );
|
||||
return \IPS\Member::loggedIn()->language()->addToStack( 'history_recognize_points_adjustment', FALSE, array( 'sprintf' => array( $recognize->points, $recognize->content()->url(), $recognize->content()->indefiniteArticle() ) ) );
|
||||
|
||||
}
|
||||
catch( \Exception $e )
|
||||
{
|
||||
return \IPS\Member::loggedIn()->language()->addToStack( 'history_recognize_points_adjustment_deleted' );
|
||||
}
|
||||
}
|
||||
else if ( isset( $jsonValue['by'] ) and $jsonValue['by'] === 'manual' )
|
||||
{
|
||||
return \IPS\Member::loggedIn()->language()->addToStack( 'history_manual_points_adjustment', FALSE, array( 'htmlsprintf' => array( \intval( $jsonValue['old'] ), \intval( $jsonValue['new'] ), $byMember ?: $byStaff ) ) );
|
||||
}
|
||||
|
||||
break;
|
||||
case 'badges':
|
||||
if ( isset( $jsonValue['action'] ) )
|
||||
{
|
||||
try
|
||||
{
|
||||
$badge = \IPS\core\Achievements\Badge::load( $jsonValue['id'] );
|
||||
|
||||
if ( $jsonValue['action'] == 'manual' )
|
||||
{
|
||||
return \IPS\Member::loggedIn()->language()->addToStack( 'history_manual_badge_addition', FALSE, array('htmlsprintf' => array( $badge->_title, $byMember ?: $byStaff ) ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
return \IPS\Member::loggedIn()->language()->addToStack( 'history_manual_badge_deletion', FALSE, array('htmlsprintf' => array( $badge->_title, $byMember ?: $byStaff ) ) );
|
||||
}
|
||||
}
|
||||
catch( \Exception $e ) { }
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
$member->logHistory( 'core', 'badges', [ 'action' => 'manual', 'id' => $values['acp_manual_badge']->_id ] );
|
||||
return $value;
|
||||
}
|
||||
|
||||
|
||||
@@ -107,7 +107,10 @@ class _System
|
||||
array( 'core_members_known_devices', 'member_id' ),
|
||||
array( 'core_members_known_ip_addresses', 'member_id' ),
|
||||
array( 'core_streams', 'member' ),
|
||||
array( 'core_rss_import', 'rss_import_member' )
|
||||
array( 'core_rss_import', 'rss_import_member' ),
|
||||
array( 'core_anonymous_posts', 'anonymous_member_id' ),
|
||||
array( 'core_member_badges', 'member' ),
|
||||
array( 'core_notifications_pwa_keys', 'member' )
|
||||
) as $toMerge
|
||||
)
|
||||
{
|
||||
@@ -200,6 +203,27 @@ class _System
|
||||
{
|
||||
\IPS\Db::i()->delete( 'core_follow', array( "follow_id IN('" . implode( "','", $duplicateFollows ) . "')" ) );
|
||||
}
|
||||
|
||||
/* Remove duplicate PWA subscriptions */
|
||||
$duplicatePwa = array();
|
||||
$uniquePwa = array();
|
||||
foreach( \IPS\Db::i()->select( '*', 'core_notifications_pwa_keys', array( "`member`=?", $member->member_id ) ) AS $pwa )
|
||||
{
|
||||
$key = "{$pwa['p256dh']}-{$pwa['auth']}";
|
||||
if ( !\in_array( $key, $uniquePwa ) )
|
||||
{
|
||||
$uniquePwa[ $pwa['id'] ] = $key;
|
||||
}
|
||||
else
|
||||
{
|
||||
$duplicatePwa[ $pwa['id'] ] = $key;
|
||||
}
|
||||
}
|
||||
|
||||
if ( \count( $duplicatePwa ) )
|
||||
{
|
||||
\IPS\Db::i()->delete( 'core_notifications_pwa_keys', array( \IPS\Db::i()->in( 'id', \array_keys( $duplicatePwa ) ) ) );
|
||||
}
|
||||
|
||||
/* Set warning level */
|
||||
$member->warn_level += $member2->warn_level;
|
||||
@@ -279,7 +303,10 @@ class _System
|
||||
array( 'core_streams', 'member' ),
|
||||
array( 'core_referrals', 'referred_by' ),
|
||||
array( 'core_referrals', 'member_id' ),
|
||||
array( 'core_marketplace_tokens', 'id' )
|
||||
array( 'core_anonymous_posts', 'anonymous_member_id' ),
|
||||
array( 'core_marketplace_tokens', 'id' ),
|
||||
array( 'core_member_badges', 'member' ),
|
||||
array( 'core_notifications_pwa_keys', 'member' )
|
||||
) as $toDelete )
|
||||
{
|
||||
\IPS\Db::i()->delete( $toDelete[0], array( '`' . $toDelete[1] . '`=?', $member->member_id ) );
|
||||
@@ -303,10 +330,10 @@ class _System
|
||||
\IPS\Db::i()->delete( 'core_follow', array( 'follow_app=? AND follow_area=? AND follow_rel_id=?', 'core', 'member', $member->member_id ) );
|
||||
\IPS\Db::i()->delete( 'core_follow_count_cache', array( 'id=? AND class=?', $member->member_id, 'IPS\core\Member' ) );
|
||||
\IPS\Db::i()->delete( 'core_moderators', array( 'id=? AND type=?', $member->member_id, 'm' ) );
|
||||
\IPS\Db::i()->delete( 'core_member_recognize', array( 'r_member_id=? OR r_given_by=?', $member->member_id, $member->member_id ) );
|
||||
|
||||
unset ( \IPS\Data\Store::i()->moderators );
|
||||
|
||||
|
||||
/* Remove the group from the staff directory */
|
||||
foreach ( \IPS\core\StaffDirectory\User::roots() as $staff )
|
||||
{
|
||||
@@ -320,8 +347,8 @@ class _System
|
||||
\IPS\File::unclaimAttachments( 'core_Staffdirectory', $member->member_id );
|
||||
\IPS\File::unclaimAttachments( 'core_Members', NULL, NULL, $member->member_id );
|
||||
|
||||
|
||||
$member->deletePhoto();
|
||||
$member->coverPhoto()->delete();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -353,7 +380,7 @@ class _System
|
||||
foreach( $groupIds as $id )
|
||||
{
|
||||
$key = 'groupMembersCount_' . $id;
|
||||
unset( \IPS\Data\Cache::i()->$key );
|
||||
unset( \IPS\Data\Store::i()->$key );
|
||||
}
|
||||
|
||||
/* Reset profile completion flag to see if there are any items to complete now permissions are elevated */
|
||||
|
||||
@@ -83,7 +83,7 @@ class _ContentMessages
|
||||
* @param bool $isPublic Who should see the message
|
||||
* @return int
|
||||
*/
|
||||
public function addMessage( $message, $color = NULL, \IPS\Content\Item $item, \IPS\Member $member = NULL, bool $isPublic = TRUE )
|
||||
public function addMessage( $message, $color, \IPS\Content\Item $item, \IPS\Member $member = NULL, bool $isPublic = TRUE )
|
||||
{
|
||||
$member = $member ?: \IPS\Member::loggedIn();
|
||||
|
||||
@@ -109,7 +109,7 @@ class _ContentMessages
|
||||
* @param bool $isPublic Who should see the message
|
||||
* @return void
|
||||
*/
|
||||
public function editMessage( $id, $message, $color = NULL, \IPS\Content\Item $item, \IPS\Member $member = NULL, bool $isPublic = TRUE )
|
||||
public function editMessage( $id, $message, $color, \IPS\Content\Item $item, \IPS\Member $member = NULL, bool $isPublic = TRUE )
|
||||
{
|
||||
$member = $member ?: \IPS\Member::loggedIn();
|
||||
|
||||
|
||||
@@ -94,11 +94,11 @@ class _ItemModeration
|
||||
|
||||
try
|
||||
{
|
||||
return $item::modPermission( 'can_toggle_item_moderation', $member, $item->container() );
|
||||
return $item::modPermission( 'toggle_item_moderation', $member, $item->container() );
|
||||
}
|
||||
catch( \BadMethodCallException $e )
|
||||
{
|
||||
return $member->modPermission( 'can_toggle_item_moderation' );
|
||||
return $member->modPermission( 'can_toggle_item_moderation_content' );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,7 +109,7 @@ class _ItemModeration
|
||||
* @param \IPS\Member|NULL $member The member enabling moderation, or NULL for currently logged in member.
|
||||
* @return void
|
||||
*/
|
||||
public function enable( \IPS\Content\Item $item, ?\IPS\Member $member = NULL ): void
|
||||
public function enable( \IPS\Content\Item $item, ?\IPS\Member $member = NULL )
|
||||
{
|
||||
$member = $member ?: \IPS\Member::loggedIn();
|
||||
|
||||
@@ -141,7 +141,7 @@ class _ItemModeration
|
||||
* @return void
|
||||
* @throws \OutOfRangeException
|
||||
*/
|
||||
public function disable( \IPS\Content\Item $item ): void
|
||||
public function disable( \IPS\Content\Item $item )
|
||||
{
|
||||
$meta = $item->getMeta();
|
||||
|
||||
|
||||
@@ -109,74 +109,21 @@ class _Deleted
|
||||
switch( \IPS\Request::i()->modaction )
|
||||
{
|
||||
case 'restore':
|
||||
if ( isset( $class::$databaseColumnMap['hidden'] ) )
|
||||
{
|
||||
$column = $class::$databaseColumnMap['hidden'];
|
||||
$content->$column = 0;
|
||||
}
|
||||
else if ( isset( $class::$databaseColumnMap['approved'] ) )
|
||||
{
|
||||
$column = $class::$databaseColumnMap['approved'];
|
||||
$content->$column = 1;
|
||||
}
|
||||
|
||||
\IPS\Session::i()->modLog( 'modlog__action_restore', array(
|
||||
$content::$title => FALSE,
|
||||
$content->url()->__toString() => FALSE
|
||||
) );
|
||||
|
||||
try
|
||||
{
|
||||
if ( $content->container() )
|
||||
{
|
||||
if ( $content->container()->_comments !== NULL )
|
||||
{
|
||||
if ( $content instanceof \IPS\Content\Item )
|
||||
{
|
||||
$content->container()->_comments = ( $content->container()->_comments + $content->mapped('num_comments') );
|
||||
}
|
||||
else
|
||||
{
|
||||
$content->container()->_comments = $content->container()->_comments + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if ( $content->container()->_unapprovedComments !== NULL )
|
||||
{
|
||||
if ( $content instanceof \IPS\Content\Item )
|
||||
{
|
||||
$content->container()->_unapprovedComments = ( $content->container()->_unapprovedComments + $content->mapped('unapproved_comments') );
|
||||
}
|
||||
}
|
||||
$content->container()->setLastComment();
|
||||
$content->container()->save();
|
||||
}
|
||||
}
|
||||
catch( \BadMethodCallException $e ) {}
|
||||
|
||||
$content->save();
|
||||
$log->delete();
|
||||
$content->modAction( 'restore' );
|
||||
break;
|
||||
|
||||
case 'restore_as_hidden':
|
||||
if ( isset( $class::$databaseColumnMap['hidden'] ) )
|
||||
{
|
||||
$column = $class::$databaseColumnMap['hidden'];
|
||||
}
|
||||
else if ( isset( $class::$databaseColumnMap['approved'] ) )
|
||||
{
|
||||
$column = $class::$databaseColumnMap['approved'];
|
||||
}
|
||||
|
||||
$content->$column = -1;
|
||||
|
||||
\IPS\Session::i()->modLog( 'modlog__action_restore_hidden', array(
|
||||
$content::$title => FALSE,
|
||||
$content->url()->__toString() => FALSE
|
||||
) );
|
||||
|
||||
$content->save();
|
||||
$log->delete();
|
||||
$content->modAction( 'restoreAsHidden' );
|
||||
break;
|
||||
|
||||
case 'delete':
|
||||
|
||||
@@ -58,7 +58,14 @@ class _Members
|
||||
$form = new \IPS\Helpers\Form( 'form', 'edit' );
|
||||
|
||||
$form->class = 'ipsForm_vertical';
|
||||
$form->add( new \IPS\Helpers\Form\Member( 'modcp_member_find', NULL, TRUE, array( 'multiple' => 1, 'placeholder' => \IPS\Member::loggedIn()->language()->addToStack('modcp_member_find') ) ) );
|
||||
$form->add( new \IPS\Helpers\Form\Member( 'modcp_member_find', NULL, TRUE, array( 'multiple' => 1, 'placeholder' => \IPS\Member::loggedIn()->language()->addToStack('modcp_member_find'), 'autocomplete' => array(
|
||||
'source' => 'app=core&module=system&controller=ajax&do=findMember&type=mod', 'resultItemTemplate' => 'core.autocomplete.memberItem',
|
||||
'commaTrigger' => false,
|
||||
'unique' => true,
|
||||
'minAjaxLength' => 3,
|
||||
'disallowedCharacters' => array(),
|
||||
'lang' => 'mem_optional',
|
||||
) ) ) );
|
||||
|
||||
if ( $values = $form->values() )
|
||||
{
|
||||
|
||||
@@ -73,16 +73,48 @@ class _Reports extends \IPS\Content\Controller
|
||||
*/
|
||||
public function manage()
|
||||
{
|
||||
$where = '( perm_id IN (?) OR perm_id IS NULL )';
|
||||
$where = [];
|
||||
|
||||
/* Make sure we're only loading reports where we have permission to view the content */
|
||||
$classWhere = [];
|
||||
$classBinds = [];
|
||||
$viewPermIds = 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='*'" ) );
|
||||
$permIds = [];
|
||||
foreach ( array_merge( [ 'IPS\core\Messenger\Conversation', 'IPS\core\Messenger\Message' ], array_values( \IPS\Content::routedClasses( FALSE, TRUE ) ) ) as $class )
|
||||
{
|
||||
$workingClass = $class;
|
||||
if ( isset( $workingClass::$itemClass ) )
|
||||
{
|
||||
$workingClass = $workingClass::$itemClass;
|
||||
}
|
||||
if ( isset( $workingClass::$containerNodeClass ) )
|
||||
{
|
||||
$workingClass = $workingClass::$containerNodeClass;
|
||||
}
|
||||
if ( isset( $workingClass::$permissionMap ) and isset( $workingClass::$permissionMap['read'] ) and $workingClass::$permissionMap['read'] !== 'view' )
|
||||
{
|
||||
if ( !isset( $permIds[ $workingClass::$permissionMap['read'] ] ) )
|
||||
{
|
||||
$permIds[ $workingClass::$permissionMap['read'] ] = 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'] . "='*'" ) );
|
||||
}
|
||||
|
||||
$classWhere[] = "( class='" . str_replace( '\\', '\\\\', $class ) . "' AND ( perm_id IN(" . implode( ',', array_intersect( $viewPermIds, $permIds[ $workingClass::$permissionMap['read'] ] ) ) . ") ) OR perm_id IS NULL )";
|
||||
}
|
||||
else
|
||||
{
|
||||
$classWhere[] = "( class='" . str_replace( '\\', '\\\\', $class ) . "' AND ( perm_id IN(" . implode( ',', $viewPermIds ) . ") ) OR perm_id IS NULL )";
|
||||
}
|
||||
}
|
||||
$where[] = array( '(' . implode( ' OR ', $classWhere ) . ')' );
|
||||
|
||||
/* Make sure we're loading the correct statuses */
|
||||
if( \IPS\Request::i()->isAjax() and isset( \IPS\Request::i()->overview ) )
|
||||
{
|
||||
$where .= " AND status IN( 1,2 )";
|
||||
$where[] = array( "status IN( 1,2 )" );
|
||||
}
|
||||
|
||||
/* fetch only reports for content of enabled applications */
|
||||
$where .= " AND " . \IPS\Db::i()->in( 'class', array_merge( array( 'IPS\core\Messenger\Conversation', 'IPS\core\Messenger\Message' ), array_values( \IPS\Content::routedClasses( FALSE, TRUE ) ) ) );
|
||||
|
||||
$table = new \IPS\Helpers\Table\Content( '\IPS\core\Reports\Report', \IPS\Http\Url::internal( 'app=core&module=modcp&controller=modcp&tab=reports', NULL, 'modcp_reports' ), array( array( $where, \IPS\Db::i()->select( 'perm_id', 'core_permission_index', \IPS\Db::i()->findInSet( 'perm_view', \IPS\Member::loggedIn()->permissionArray() ) . " OR perm_view='*'" ) ) ) );
|
||||
|
||||
/* Create table */
|
||||
$table = new \IPS\Helpers\Table\Content( '\IPS\core\Reports\Report', \IPS\Http\Url::internal( 'app=core&module=modcp&controller=modcp&tab=reports', NULL, 'modcp_reports' ), $where );
|
||||
$table->sortBy = $table->sortBy ?: 'first_report_date';
|
||||
$table->sortDirection = 'desc';
|
||||
|
||||
@@ -124,6 +156,27 @@ class _Reports extends \IPS\Content\Controller
|
||||
\IPS\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='*'" ) );
|
||||
$workingClass = $report->class;
|
||||
if ( isset( $workingClass::$itemClass ) )
|
||||
{
|
||||
$workingClass = $workingClass::$itemClass;
|
||||
}
|
||||
if ( isset( $workingClass::$containerNodeClass ) )
|
||||
{
|
||||
$workingClass = $workingClass::$containerNodeClass;
|
||||
}
|
||||
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'] . "='*'" ) ) );
|
||||
}
|
||||
|
||||
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, '' );
|
||||
}
|
||||
|
||||
/* Setting status? */
|
||||
if( isset( \IPS\Request::i()->setStatus ) and \in_array( \IPS\Request::i()->setStatus, range( 1, 3 ) ) )
|
||||
{
|
||||
|
||||
@@ -64,7 +64,15 @@ class _Content
|
||||
'can_add_item_message_content' => array( 'YesNo', array( 'togglesOff' => $toggles['add_item_message'] ) ),
|
||||
'can_edit_item_message_content' => array( 'YesNo', array( 'togglesOff' => $toggles['edit_item_message'] ) ),
|
||||
'can_delete_item_message_content'=> array( 'YesNo', array( 'togglesOff' => $toggles['delete_item_message'] ) ),
|
||||
'can_toggle_item_moderation' => array( 'YesNo', array( 'togglesOff' => $toggles['toggle_item_moderation'] ) ),
|
||||
'can_toggle_item_moderation_content' => array( 'YesNo', array( 'togglesOff' => $toggles['toggle_item_moderation'] ) ),
|
||||
'can_recognize_content' => array( 'YesNo', array( 'togglesOn' => [ 'can_recognize_content_options', 'can_recognize_content_no_point_limit' ] ) ),
|
||||
'can_recognize_content_options' => array( 'CheckboxSet', array(
|
||||
'options' => [
|
||||
'points' => 'can_recognize_content_points',
|
||||
'badges' => 'can_recognize_content_badges',
|
||||
]
|
||||
) ),
|
||||
'can_recognize_content_no_point_limit' => 'YesNo'
|
||||
);
|
||||
|
||||
if ( \IPS\Settings::i()->edit_log == 2 )
|
||||
@@ -81,6 +89,7 @@ class _Content
|
||||
$return['can_close_polls'] = 'YesNo';
|
||||
|
||||
$return['can_manage_deleted_content'] = 'YesNo';
|
||||
$return['can_view_anonymous_posters'] = 'YesNo';
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,270 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Notification Options
|
||||
* @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 18 Feb 2021
|
||||
*/
|
||||
|
||||
namespace IPS\core\extensions\core\Notifications;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notification Options
|
||||
*/
|
||||
class _Achievements
|
||||
{
|
||||
/**
|
||||
* Get fields for configuration
|
||||
*
|
||||
* @param \IPS\Member|null $member The member (to take out any notification types a given member will never see) or NULL if this is for the ACP
|
||||
* @return array
|
||||
*/
|
||||
public static function configurationOptions( \IPS\Member $member = NULL )
|
||||
{
|
||||
// Return an array defining each notification type, including the form elements necessary to allow its configuration
|
||||
|
||||
return array(
|
||||
'core_Achievements' => array(
|
||||
'type' => 'standard',
|
||||
'notificationTypes' => array( 'new_rank', 'new_badge', 'new_recognize' ),
|
||||
'title' => 'notifications__core_Achievements',
|
||||
'showTitle' => FALSE,
|
||||
'description' => 'notifications__core_Achievements_desc',
|
||||
'default' => array( 'inline' ),
|
||||
'disabled' => array()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse notification: new_rank
|
||||
*
|
||||
* @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_new_rank( \IPS\Notification\Inline $notification, $htmlEscape=TRUE )
|
||||
{
|
||||
if ( $notification->extra )
|
||||
{
|
||||
/* \IPS\Notification->extra will always be an array, but for bulk content notifications we are only storing a single badge ID,
|
||||
so we need to grab just the one array entry (the badge ID we stored) */
|
||||
$rankId = $notification->extra;
|
||||
|
||||
if( \is_array( $rankId ) )
|
||||
{
|
||||
$rankId = array_pop( $rankId );
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
$rank = \IPS\core\Achievements\Rank::load( $rankId );
|
||||
$title = $rank->_title;
|
||||
}
|
||||
catch( \Exception $e )
|
||||
{
|
||||
throw new \OutOfRangeException;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$title = \IPS\Member::loggedIn()->rank['title'];
|
||||
}
|
||||
|
||||
return array(
|
||||
'title' => \IPS\Member::loggedIn()->language()->addToStack( 'notification__new_rank', FALSE, array( 'sprintf' => array( $title ) ) ),
|
||||
'url' => \IPS\Member::loggedIn()->url(),
|
||||
'author' => \IPS\Member::loggedIn()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse notification for mobile: new_rank
|
||||
*
|
||||
* @param \IPS\Lang $language The language that the notification should be in
|
||||
* @param \IPS\Member $member The member that earned the rank
|
||||
* @return array
|
||||
*/
|
||||
public static function parse_mobile_new_rank( \IPS\Lang $language, \IPS\Member $member )
|
||||
{
|
||||
return array(
|
||||
'body' => $language->addToStack( 'notification__new_rank', FALSE, array( 'sprintf' => array( $member->rank['title'] ) ) ),
|
||||
'data' => array(
|
||||
'url' => (string) $member->url(),
|
||||
'author' => $member,
|
||||
),
|
||||
'channelId' => 'achievements',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse notification: new_badge
|
||||
*
|
||||
* @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_new_badge( \IPS\Notification\Inline $notification, $htmlEscape=TRUE )
|
||||
{
|
||||
if ( $notification->extra )
|
||||
{
|
||||
/* \IPS\Notification->extra will always be an array, but for bulk content notifications we are only storing a single badge ID,
|
||||
so we need to grab just the one array entry (the badge ID we stored) */
|
||||
$badgeId = $notification->extra;
|
||||
|
||||
if( \is_array( $badgeId ) )
|
||||
{
|
||||
$badgeId = array_pop( $badgeId );
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
$badge = \IPS\core\Achievements\Badge::load( $badgeId );
|
||||
$content = \IPS\Member::loggedIn()->language()->addToStack( 'notification__new_badge_content', NULL, [ 'sprintf' => [ $badge->_title ] ] );
|
||||
$title = \IPS\Member::loggedIn()->language()->addToStack( 'notification__new_badge', NULL, [ 'sprintf' => [ $badge->_title ] ] );
|
||||
}
|
||||
catch( \Exception $e )
|
||||
{
|
||||
throw new \OutOfRangeException;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$title = \IPS\Member::loggedIn()->language()->addToStack( 'mailsub__core_notification_new_badge' );
|
||||
$content = NULL;
|
||||
}
|
||||
|
||||
return array(
|
||||
'title' => $title,
|
||||
'url' => (string) \IPS\Http\Url::internal( "app=core&module=members&controller=profile&do=badges&id=" . \IPS\Member::loggedIn()->member_id, 'front', 'profile_badges', \IPS\Member::loggedIn()->members_seo_name ),
|
||||
'content' => $content,
|
||||
'author' => \IPS\Member::loggedIn()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse notification for mobile: new_badge
|
||||
*
|
||||
* @param \IPS\Lang $language The language that the notification should be in
|
||||
* @param \IPS\Member $member The member that earned the badge
|
||||
* @param \IPS\core\Achievements\Badge $badge The badge the member earned
|
||||
* @return array
|
||||
*/
|
||||
public static function parse_mobile_new_badge( \IPS\Lang $language, \IPS\Member $member, \IPS\core\Achievements\Badge $badge )
|
||||
{
|
||||
return array(
|
||||
'body' => $language->addToStack( 'notification__new_badge', NULL, [ 'sprintf' => [ $badge->_title ] ] ),
|
||||
'data' => array(
|
||||
'url' => (string) \IPS\Http\Url::internal( "app=core&module=members&controller=profile&do=badges&id={$member->member_id}", 'front', 'profile_badges', $member->members_seo_name ),
|
||||
'author' => $member,
|
||||
),
|
||||
'channelId' => 'achievements',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse notification: new_badge
|
||||
*
|
||||
* @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_new_recognize( \IPS\Notification\Inline $notification, $htmlEscape=TRUE )
|
||||
{
|
||||
if ( $notification->extra )
|
||||
{
|
||||
/* \IPS\Notification->extra will always be an array, but for bulk content notifications we are only storing a single badge ID,
|
||||
so we need to grab just the one array entry (the badge ID we stored) */
|
||||
$recognizeId = $notification->extra;
|
||||
|
||||
if( \is_array( $recognizeId ) )
|
||||
{
|
||||
$recognizeId = array_pop( $recognizeId );
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
$recognize = \IPS\core\Achievements\Recognize::load( $recognizeId );
|
||||
$url = $recognize->content()->url();
|
||||
}
|
||||
catch( \Exception $e )
|
||||
{
|
||||
throw new \OutOfRangeException;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
$url = NULL;
|
||||
}
|
||||
|
||||
$content = \IPS\Member::loggedIn()->language()->addToStack( 'notification__new_recognized' );
|
||||
$title = \IPS\Member::loggedIn()->language()->addToStack( 'notification__new_recognized' );
|
||||
|
||||
return array(
|
||||
'title' => $title,
|
||||
'url' => (string) $url,
|
||||
'content' => $content,
|
||||
'author' => \IPS\Member::loggedIn()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse notification for mobile: new_badge
|
||||
*
|
||||
* @param \IPS\Lang $language The language that the notification should be in
|
||||
* @param \IPS\Member $member The member that earned the badge
|
||||
* @param \IPS\core\Achievements\Badge $badge The badge the member earned
|
||||
* @return array
|
||||
*/
|
||||
public static function parse_mobile_new_recognize( \IPS\Lang $language, \IPS\Member $member, \IPS\core\Achievements\Recognize $recognize )
|
||||
{
|
||||
return array(
|
||||
'body' => $language->addToStack( 'notification__new_recognized' ),
|
||||
'data' => array(
|
||||
'url' => $recognize->content()->url(),
|
||||
'author' => $member,
|
||||
),
|
||||
'channelId' => 'achievements',
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -66,7 +66,7 @@ class _BulkMails
|
||||
* @param bool $value The value
|
||||
* @return void
|
||||
*/
|
||||
public static function saveExtra( \IPS\Member $member = NULL, $key, $value )
|
||||
public static function saveExtra( ?\IPS\Member $member, $key, $value )
|
||||
{
|
||||
switch ( $key )
|
||||
{
|
||||
@@ -94,7 +94,7 @@ class _BulkMails
|
||||
* @param string $method The method type
|
||||
* @return void
|
||||
*/
|
||||
public static function disableExtra( \IPS\Member $member = NULL, $method )
|
||||
public static function disableExtra( ?\IPS\Member $member, $method )
|
||||
{
|
||||
if ( $method === 'email' and $member->allow_admin_mails )
|
||||
{
|
||||
|
||||
@@ -112,6 +112,7 @@ class _Clubs
|
||||
public static function parse_mobile_club_invitation( \IPS\Lang $language, \IPS\Member\Club $club, \IPS\Member $invitedBy )
|
||||
{
|
||||
return array(
|
||||
'title' => $language->addToStack( 'notification__club_invitation_by_title' ),
|
||||
'body' => $language->addToStack( $invitedBy->member_id ? 'notification__club_invitation_by' : 'notification__club_invitation_generic', FALSE, array( 'htmlsprintf' => array( $invitedBy->name, $club->name ) ) ),
|
||||
'data' => array(
|
||||
'url' => (string) $club->url(),
|
||||
@@ -168,8 +169,9 @@ class _Clubs
|
||||
public static function parse_mobile_club_response( \IPS\Lang $language, \IPS\Member\Club $club, $response )
|
||||
{
|
||||
$memberStatus = $club->memberStatus( \IPS\Member::loggedIn(), 2 );
|
||||
|
||||
|
||||
return array(
|
||||
'title' => $language->addToStack( "notification__club_response_title" ),
|
||||
'body' => $language->addToStack( $response ? 'notification__club_response_accepted' : 'notification__club_response_declined', FALSE, array( 'htmlsprintf' => array( $club->name ) ) ),
|
||||
'data' => array(
|
||||
'url' => (string) $club->url(),
|
||||
@@ -258,6 +260,7 @@ class _Clubs
|
||||
public static function parse_mobile_club_request( \IPS\Lang $language, \IPS\Member\Club $club, \IPS\Member $member )
|
||||
{
|
||||
return array(
|
||||
'title' => $language->addToStack( 'notification__club_request_title' ),
|
||||
'body' => $language->addToStack( 'notification__club_request', FALSE, array(
|
||||
'pluralize' => array( 1 ),
|
||||
'htmlsprintf' => array(
|
||||
@@ -352,6 +355,7 @@ class _Clubs
|
||||
public static function parse_mobile_club_join( \IPS\Lang $language, \IPS\Member\Club $club, \IPS\Member $member )
|
||||
{
|
||||
return array(
|
||||
'title' => $language->addToStack( 'notification__club_join_title' ),
|
||||
'body' => $language->addToStack( 'notification__club_join', FALSE, array(
|
||||
'pluralize' => array( 1 ),
|
||||
'htmlsprintf' => array(
|
||||
@@ -418,6 +422,7 @@ class _Clubs
|
||||
public static function parse_mobile_unapproved_club( \IPS\Lang $language, \IPS\Member\Club $club )
|
||||
{
|
||||
return array(
|
||||
'title' => $language->addToStack( 'notification__new_club_unapproved_title' ),
|
||||
'body' => $language->addToStack( 'notification__new_club_unapproved', FALSE, array( 'htmlsprintf' => array( $club->owner->name, $club->name ) ) ),
|
||||
'data' => array(
|
||||
'url' => (string) $club->url(),
|
||||
|
||||
@@ -127,7 +127,7 @@ class _Content
|
||||
* @param bool $value The value
|
||||
* @return void
|
||||
*/
|
||||
public static function saveExtra( \IPS\Member $member = NULL, $key, $value )
|
||||
public static function saveExtra( ?\IPS\Member $member, $key, $value )
|
||||
{
|
||||
switch ( $key )
|
||||
{
|
||||
@@ -178,9 +178,20 @@ class _Content
|
||||
* @param string $method The method type
|
||||
* @return void
|
||||
*/
|
||||
public static function disableExtra( \IPS\Member $member = NULL, $method )
|
||||
public static function disableExtra( ?\IPS\Member $member, $method )
|
||||
{
|
||||
// Do nothing
|
||||
/* If we are disabling all emails, set any digest follows to be "no notification" */
|
||||
if ( $method === 'email' )
|
||||
{
|
||||
\IPS\Db::i()->update( 'core_follow', [
|
||||
'follow_added' => time(),
|
||||
'follow_notify_do' => 0,
|
||||
'follow_notify_freq' => 'none',
|
||||
], [
|
||||
[ 'follow_member_id=?', $member->member_id ],
|
||||
[ "( follow_notify_freq='daily' OR follow_notify_freq='weekly' )" ],
|
||||
] );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -232,10 +243,12 @@ class _Content
|
||||
$url = $url->setQueryString( 'showDeleted', 1 );
|
||||
}
|
||||
|
||||
$name = ( $item->isAnonymous() ) ? \IPS\Member::loggedIn()->language()->addToStack( 'post_anonymously_placename' ) : $item->author()->name;
|
||||
|
||||
return array(
|
||||
'title' => \IPS\Member::loggedIn()->language()->addToStack( 'notification__new_content', FALSE, array(
|
||||
( $htmlEscape ? 'sprintf' : 'htmlsprintf' ) => array(
|
||||
$item->author()->name,
|
||||
$name,
|
||||
mb_strtolower( $item->indefiniteArticle() ),
|
||||
$item->searchIndexContainerClass()->getTitleForLanguage( \IPS\Member::loggedIn()->language(), $htmlEscape ? array( 'escape' => TRUE ) : array() ),
|
||||
$item->mapped('title')
|
||||
@@ -257,17 +270,39 @@ class _Content
|
||||
*/
|
||||
public static function parse_mobile_new_content( \IPS\Lang $language, \IPS\Content\Item $item )
|
||||
{
|
||||
$name = ( $item->isAnonymous() ) ? \IPS\Member::loggedIn()->language()->addToStack( 'post_anonymously_placename' ) : $item->author()->name;
|
||||
$container = $item->containerWrapper();
|
||||
$containerId = $container ? $container->_id : "-"; // This is used to generate the tag. Use ID if we have one, otherwise just a dash
|
||||
|
||||
return array(
|
||||
'title' => $language->addToStack( 'notification__new_content_title', FALSE, array( 'htmlsprintf' => array(
|
||||
mb_strtolower( $item->definiteArticle( $language ) ),
|
||||
) ) ),
|
||||
'body' => $language->addToStack( 'notification__new_content', FALSE, array( 'htmlsprintf' => array(
|
||||
$item->author()->name,
|
||||
$name,
|
||||
mb_strtolower( $item->indefiniteArticle( $language ) ),
|
||||
$item->searchIndexContainerClass()->getTitleForLanguage( $language ),
|
||||
$container ?
|
||||
$language->addToStack( 'notification__container', FALSE, array( 'sprintf' => array( $item->searchIndexContainerClass()->getTitleForLanguage( $language ) ) ) )
|
||||
: "",
|
||||
$item->mapped('title')
|
||||
) ) ),
|
||||
'data' => array(
|
||||
'url' => (string) $item->url(),
|
||||
'author' => $item->author()
|
||||
'author' => $item->author(),
|
||||
'grouped' => $language->addToStack( 'notification__new_content_grouped', FALSE, array(
|
||||
'htmlsprintf' => array(
|
||||
$item->definiteArticle( $language, TRUE ),
|
||||
$container ?
|
||||
$language->addToStack( 'notification__container', FALSE, array( 'sprintf' => array( $item->searchIndexContainerClass()->getTitleForLanguage( $language ) ) ) )
|
||||
: "",
|
||||
)
|
||||
) ),
|
||||
'groupedTitle' => $language->addToStack( 'notification__new_content_grouped_title', FALSE, array( 'htmlsprintf' => array(
|
||||
$item->definiteArticle( $language, TRUE ),
|
||||
) ) ),
|
||||
'groupedUrl' => $container ? $container->url() : NULL
|
||||
),
|
||||
'tag' => md5( 'newcontent' . \get_class( $item ) . $containerId ), // Group new item notifications by container ID (if available)
|
||||
'channelId' => 'followed',
|
||||
);
|
||||
}
|
||||
@@ -337,6 +372,9 @@ class _Content
|
||||
public static function parse_mobile_new_content_bulk( \IPS\Lang $language, \IPS\Node\Model $node, \IPS\Member $author, $contentClass )
|
||||
{
|
||||
return array(
|
||||
'title' => $language->addToStack( 'notification__new_content_bulk_title', FALSE, array( 'htmlsprintf' => array(
|
||||
$language->get( $contentClass::$title . '_pl_lc' ),
|
||||
) ) ),
|
||||
'body' => $language->addToStack( 'notification__new_content_bulk', FALSE, array( 'htmlsprintf' => array(
|
||||
$author->name,
|
||||
$language->get( $contentClass::$title . '_pl_lc' ),
|
||||
@@ -454,7 +492,13 @@ class _Content
|
||||
*/
|
||||
public static function parse_mobile_new_comment( \IPS\Lang $language, \IPS\Content\Comment $comment )
|
||||
{
|
||||
$item = $comment->item();
|
||||
$idColumn = $item::$databaseColumnId;
|
||||
|
||||
return array(
|
||||
'title' => $language->addToStack( 'notification__new_comment_title', FALSE, array(
|
||||
'pluralize' => array( 1 )
|
||||
) ),
|
||||
'body' => $language->addToStack( 'notification__new_comment', FALSE, array(
|
||||
'pluralize' => array( 1 ),
|
||||
'htmlsprintf'=> array(
|
||||
@@ -464,8 +508,16 @@ class _Content
|
||||
) ),
|
||||
'data' => array(
|
||||
'url' => (string) $comment->url(),
|
||||
'author' => $comment->author()
|
||||
'author' => $comment->author(),
|
||||
'grouped' => $language->addToStack( 'notification__new_comment_grouped', FALSE, array(
|
||||
'htmlsprintf' => array(
|
||||
$comment->item()->mapped('title')
|
||||
)
|
||||
) ),
|
||||
'groupedTitle' => $language->addToStack( 'notification__new_comment_title' ), // Pluralized on the client
|
||||
// No need for groupedUrl here - latest comment url will do
|
||||
),
|
||||
'tag' => md5( 'newcomment' . \get_class( $item ) . $item->$idColumn ), // Group comment notifications by item ID (if available)
|
||||
'channelId' => 'followed',
|
||||
);
|
||||
}
|
||||
@@ -565,7 +617,13 @@ class _Content
|
||||
*/
|
||||
public static function parse_mobile_new_review( \IPS\Lang $language, \IPS\Content\Review $review )
|
||||
{
|
||||
$item = $review->item();
|
||||
$idColumn = $item::$databaseColumnId;
|
||||
|
||||
return array(
|
||||
'title' => $language->addToStack( 'notification__new_review_title', FALSE, array(
|
||||
'pluralize' => array(1)
|
||||
) ),
|
||||
'body' => $language->addToStack( 'notification__new_review', FALSE, array(
|
||||
'pluralize' => array( 1 ),
|
||||
'htmlsprintf'=> array(
|
||||
@@ -575,8 +633,16 @@ class _Content
|
||||
) ),
|
||||
'data' => array(
|
||||
'url' => (string) $review->url(),
|
||||
'author' => $review->author()
|
||||
'author' => $review->author(),
|
||||
'grouped' => $language->addToStack( 'notification__new_review_grouped', FALSE, array(
|
||||
'htmlsprintf' => array(
|
||||
$review->item()->mapped('title')
|
||||
)
|
||||
) ),
|
||||
'groupedTitle' => $language->addToStack( 'notification__new_review_title' ), // Pluralized on the client
|
||||
// No need for groupedUrl here - latest comment url will do
|
||||
),
|
||||
'tag' => md5( 'newreview' . \get_class( $item ) . $item->$idColumn ), // Group review notifications by item ID (if available)
|
||||
'channelId' => 'followed',
|
||||
);
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ class _Messenger
|
||||
* @param bool $value The value
|
||||
* @return void
|
||||
*/
|
||||
public static function saveExtra( \IPS\Member $member = NULL, $key, $value )
|
||||
public static function saveExtra( ?\IPS\Member $member, $key, $value )
|
||||
{
|
||||
switch ( $key )
|
||||
{
|
||||
@@ -93,7 +93,7 @@ class _Messenger
|
||||
* @param string $method The method type
|
||||
* @return void
|
||||
*/
|
||||
public static function disableExtra( \IPS\Member $member = NULL, $method )
|
||||
public static function disableExtra( ?\IPS\Member $member, $method )
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
@@ -166,11 +166,19 @@ class _Messenger
|
||||
public static function parse_mobile_new_private_message( \IPS\Lang $language, \IPS\core\Messenger\Message $message )
|
||||
{
|
||||
return array(
|
||||
'title' => $language->addToStack( 'notification__new_private_message_title', FALSE, array(
|
||||
'pluralize' => array(1),
|
||||
'htmlsprintf' => array( $message->author()->name )
|
||||
) ),
|
||||
'body' => $language->addToStack( 'notification__new_private_message', FALSE, array( 'htmlsprintf' => array( $message->author()->name ) ) ),
|
||||
'data' => array(
|
||||
'url' => (string) $message->url(),
|
||||
'author' => $message->author()
|
||||
'author' => $message->author(),
|
||||
'grouped' => $language->addToStack( 'notification__new_private_message_grouped' ), // Pluralized on the client
|
||||
'groupedTitle' => $language->addToStack( 'notification__new_private_message_title' ), // Pluralized on the client
|
||||
'groupedUrl' => \IPS\Http\Url::internal( 'app=core&module=messaging&controller=messenger', 'front', 'messaging' ) // For more than one message, go to messenger
|
||||
),
|
||||
'tag' => md5( 'new-personal-messages' ), // Group all new personal messages
|
||||
'channelId' => 'personal-messages',
|
||||
);
|
||||
}
|
||||
@@ -217,11 +225,13 @@ class _Messenger
|
||||
public static function parse_mobile_private_message_added( \IPS\Lang $language, \IPS\core\Messenger\Conversation $conversation, \IPS\Member $added )
|
||||
{
|
||||
return array(
|
||||
'title' => $language->addToStack( 'notification__private_message_added_title', FALSE, array( 'pluralize' => array(1) ) ),
|
||||
'body' => $language->addToStack( 'notification__private_message_added', FALSE, array( 'htmlsprintf' => array( $added->name ) ) ),
|
||||
'data' => array(
|
||||
'url' => (string) $conversation->url(),
|
||||
'author' => $added
|
||||
),
|
||||
'tag' => md5( 'new-personal-messages-added' ), // Group all added-to personal messages
|
||||
'channelId' => 'personal-messages',
|
||||
);
|
||||
}
|
||||
|
||||
@@ -127,7 +127,7 @@ class _Moderation
|
||||
* @param bool $value The value
|
||||
* @return void
|
||||
*/
|
||||
public static function saveExtra( \IPS\Member $member, $key, $value )
|
||||
public static function saveExtra( ?\IPS\Member $member, $key, $value )
|
||||
{
|
||||
switch ( $key )
|
||||
{
|
||||
@@ -144,7 +144,7 @@ class _Moderation
|
||||
* @param string $method The method type
|
||||
* @return void
|
||||
*/
|
||||
public static function disableExtra( \IPS\Member $member = NULL, $method )
|
||||
public static function disableExtra( ?\IPS\Member $member, $method )
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
@@ -294,14 +294,19 @@ class _Moderation
|
||||
public static function parse_mobile_warning_mods( \IPS\Lang $language, \IPS\core\Warnings\Warning $warning )
|
||||
{
|
||||
return array(
|
||||
'title' => $language->addToStack( 'notification__warning_mods_title', FALSE, array( 'pluralize' => array(1) ) ),
|
||||
'body' => $language->addToStack( 'notification__warning_mods', FALSE, array( 'htmlsprintf' => array(
|
||||
\IPS\Member::load( $warning->member )->name,
|
||||
\IPS\Member::load( $warning->moderator )->name
|
||||
) ) ),
|
||||
'data' => array(
|
||||
'url' => (string) $warning->url(),
|
||||
'author' => $warning->moderator
|
||||
'author' => $warning->moderator,
|
||||
'grouped' => $language->addToStack( 'notification__warning_mods_grouped'), // Pluralized on the client
|
||||
'groupedTitle' => $language->addToStack( 'notification__warning_mods_title' ), // Pluralized on the client
|
||||
'groupedUrl' => \IPS\Http\Url::internal( 'app=core&module=modcp&controller=modcp&tab=recent_warnings', 'front', 'modcp_recent_warnings' )
|
||||
),
|
||||
'tag' => md5('recent-warnings'), // Group warning notifications
|
||||
'channelId' => 'moderation',
|
||||
);
|
||||
}
|
||||
@@ -318,6 +323,9 @@ class _Moderation
|
||||
public static function parse_mobile_unapproved_content_bulk( \IPS\Lang $language, \IPS\Node\Model $node, \IPS\Member $author, $contentClass )
|
||||
{
|
||||
return array(
|
||||
'title' => $language->addToStack( 'notification__unapproved_content_bulk_title', FALSE, array( 'htmlsprintf' => array(
|
||||
$language->get( $contentClass::$title . '_pl_lc' ),
|
||||
) ) ),
|
||||
'body' => $language->addToStack( 'notification__unapproved_content_bulk', FALSE, array( 'htmlsprintf' => array(
|
||||
$author->name,
|
||||
$language->get( $contentClass::$title . '_pl_lc' ),
|
||||
@@ -380,6 +388,7 @@ class _Moderation
|
||||
public static function parse_mobile_report_center( \IPS\Lang $language, \IPS\core\Reports\Report $report, array $latestReport, \IPS\Content $reportedContent )
|
||||
{
|
||||
return array(
|
||||
'title' => $language->addToStack( 'notification__report_center_title' ),
|
||||
'body' => $language->addToStack( 'notification__report_center', FALSE, array( 'htmlsprintf' => array(
|
||||
\IPS\Member::load( $latestReport['report_by'] )->name,
|
||||
mb_strtolower( $reportedContent->indefiniteArticle( $language ) ),
|
||||
@@ -387,8 +396,12 @@ class _Moderation
|
||||
) ) ),
|
||||
'data' => array(
|
||||
'url' => (string) $report->url(),
|
||||
'author' => $report->author()
|
||||
'author' => $report->author(),
|
||||
'grouped' => $language->addToStack( 'notification__report_center_grouped'), // Pluralized on the client
|
||||
'groupedTitle' => $language->addToStack( 'notification__report_center_title' ), // Pluralized on the client
|
||||
'groupedUrl' => \IPS\Http\Url::internal( 'app=core&module=modcp&controller=modcp&tab=reports', NULL, 'modcp_reports' )
|
||||
),
|
||||
'tag' => md5('report-center'),
|
||||
'channelId' => 'moderation',
|
||||
);
|
||||
}
|
||||
@@ -442,6 +455,7 @@ class _Moderation
|
||||
public static function parse_mobile_automatic_moderation( \IPS\Lang $language, \IPS\core\Reports\Report $report, array $latestReport, \IPS\Content $reportedContent )
|
||||
{
|
||||
return array(
|
||||
'title' => $language->addToStack( 'notification__automatic_moderation_title' ),
|
||||
'body' => $language->addToStack( 'notification__automatic_moderation', FALSE, array( 'htmlsprintf' => array(
|
||||
mb_strtolower( $reportedContent->indefiniteArticle( $language ) ),
|
||||
$report->mapped('title')
|
||||
@@ -489,8 +503,10 @@ class _Moderation
|
||||
$title = $item->mapped('title');
|
||||
}
|
||||
|
||||
$name = ( $item->isAnonymous() ) ? \IPS\Member::loggedIn()->language()->addToStack( 'post_anonymously_placename' ) : $item->author()->name;
|
||||
|
||||
return array(
|
||||
'title' => \IPS\Member::loggedIn()->language()->addToStack( 'notification__unapproved_content', FALSE, array( ( $htmlEscape ? 'sprintf' : 'htmlsprintf' ) => array( $item->author()->name, mb_strtolower( $item->indefiniteArticle() ), $title ) ) ),
|
||||
'title' => \IPS\Member::loggedIn()->language()->addToStack( 'notification__unapproved_content', FALSE, array( ( $htmlEscape ? 'sprintf' : 'htmlsprintf' ) => array( $name, mb_strtolower( $item->indefiniteArticle() ), $title ) ) ),
|
||||
'url' => $item->url(),
|
||||
'content' => $item->content(),
|
||||
'author' => $item->author(),
|
||||
@@ -507,8 +523,13 @@ class _Moderation
|
||||
public static function parse_mobile_unapproved_content( \IPS\Lang $language, \IPS\Content $content )
|
||||
{
|
||||
$item = ( $content instanceof \IPS\Content\Item ) ? $content : $content->item();
|
||||
|
||||
$container = $item->containerWrapper();
|
||||
$containerId = $container ? $container->_id : "-"; // This is used to generate the tag. Use ID if we have one, otherwise just a dash
|
||||
|
||||
return array(
|
||||
'title' => $language->addToStack( 'notification__unapproved_content_title', FALSE, array( 'htmlsprintf' => array(
|
||||
( $content instanceof \IPS\Content\Item ) ? $content->definiteArticle( $language ) : $language->get( $content::$title . '_lc' ),
|
||||
) ) ),
|
||||
'body' => $language->addToStack( 'notification__unapproved_content', FALSE, array( 'htmlsprintf' => array(
|
||||
$content->author()->name,
|
||||
mb_strtolower( $content->indefiniteArticle( $language ) ),
|
||||
@@ -516,8 +537,19 @@ class _Moderation
|
||||
) ) ),
|
||||
'data' => array(
|
||||
'url' => (string) $content->url(),
|
||||
'author' => $content->author()
|
||||
'author' => $content->author(),
|
||||
'grouped' => $language->addToStack( 'notification__unapproved_content_grouped', FALSE, array( 'htmlsprintf' => array(
|
||||
$content->definiteArticle( $language, TRUE ),
|
||||
$container ?
|
||||
$language->addToStack( 'notification__container', FALSE, array( 'sprintf' => array( $container->_title ) ) )
|
||||
: ""
|
||||
))), // Pluralized on the client
|
||||
'groupedTitle' => $language->addToStack( 'notification__unapproved_content_title', FALSE, array( 'htmlsprintf' => array(
|
||||
$content->definiteArticle( $language, TRUE ),
|
||||
)) ), // Pluralized on the client
|
||||
'groupedUrl' => $container ? $container->url() : NULL
|
||||
),
|
||||
'tag' => md5('unapproved' . \get_class( $item ) . $containerId ),
|
||||
'channelId' => 'moderation',
|
||||
);
|
||||
}
|
||||
|
||||
@@ -33,52 +33,22 @@ class _MyStuff
|
||||
return array(
|
||||
'core_MyStuff' => array(
|
||||
'type' => 'standard',
|
||||
'notificationTypes' => array( 'quote', 'mention', 'embed', 'new_likes', 'best_answer' ),
|
||||
'notificationTypes' => array( 'quote', 'mention', 'embed', 'my_solution', 'mine_solved', 'approved_content' ),
|
||||
'title' => 'notifications__core_MyStuff',
|
||||
'showTitle' => FALSE,
|
||||
'showTitle' => TRUE,
|
||||
'description' => 'notifications__core_MyStuff_desc',
|
||||
'default' => array( 'inline' ),
|
||||
'disabled' => array()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse notification: best_answer
|
||||
*
|
||||
* @param \IPS\Notification\Inline $notification The notification
|
||||
* @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_best_answer( $notification )
|
||||
{
|
||||
$item = ( $notification->item instanceof \IPS\Content\Comment ) ? $notification->item->item() : $notification->item;
|
||||
if ( !$item )
|
||||
{
|
||||
throw new \OutOfRangeException;
|
||||
}
|
||||
|
||||
$comment = $notification->item_sub ?: $item;
|
||||
if ( !$comment )
|
||||
{
|
||||
throw new \OutOfRangeException;
|
||||
}
|
||||
|
||||
return array(
|
||||
'title' => \IPS\Member::loggedIn()->language()->addToStack( 'notification__best_answer', FALSE, array( 'sprintf' => array( $item->mapped('title') ) ) ),
|
||||
'url' => $comment instanceof \IPS\Content\Item ? $item->url() : $comment->url('find'),
|
||||
'content' => $comment->truncated(),
|
||||
'author' => $comment->author(),
|
||||
'unread' => (bool) ( $item->unread() ),
|
||||
),
|
||||
'core_Reactions' => array(
|
||||
'type' => 'standard',
|
||||
'notificationTypes' => array( 'new_likes' ),
|
||||
'title' => 'notifications__core_Likes',
|
||||
'showTitle' => TRUE,
|
||||
'description' => 'notifications__core_Likes_desc',
|
||||
'default' => array( 'inline' ),
|
||||
'disabled' => array()
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -139,8 +109,15 @@ class _MyStuff
|
||||
public static function parse_mobile_mention( \IPS\Lang $language, \IPS\Content $content )
|
||||
{
|
||||
$item = ( $content instanceof \IPS\Content\Item ) ? $content : $content->item();
|
||||
|
||||
$idField = $item::$databaseColumnId;
|
||||
|
||||
return array(
|
||||
'title' => $language->addToStack( 'notification__new_mention_title', FALSE, array(
|
||||
'pluralize' => array(1),
|
||||
'htmlsprintf' => array(
|
||||
mb_strtolower( $item->indefiniteArticle( $language ) ),
|
||||
)
|
||||
) ),
|
||||
'body' => $language->addToStack( 'notification__new_mention', FALSE, array(
|
||||
'pluralize' => array( 1 ),
|
||||
'htmlsprintf' => array(
|
||||
@@ -149,10 +126,24 @@ class _MyStuff
|
||||
$item->mapped('title')
|
||||
)
|
||||
) ),
|
||||
'data' => array(
|
||||
'data' => array(
|
||||
'url' => (string) $content->url(),
|
||||
'author' => $content->author()
|
||||
'author' => $content->author(),
|
||||
'grouped' => $language->addToStack( 'notification__new_mention_grouped', FALSE, array(
|
||||
'htmlsprintf' => array(
|
||||
mb_strtolower( $item->indefiniteArticle( $language ) ),
|
||||
$item->mapped('title')
|
||||
)
|
||||
) ),
|
||||
'groupedTitle' => $language->addToStack( 'notification__new_mention_title', FALSE, array(
|
||||
// Pluralized on the client
|
||||
'htmlsprintf' => array(
|
||||
mb_strtolower( $item->indefiniteArticle( $language ) ),
|
||||
)
|
||||
) ),
|
||||
// No need for groupedUrl - just go to the most recent mention
|
||||
),
|
||||
'tag' => md5( 'mention' . \get_class( $item ) . $item->$idField ), // Group mention notifications by content item
|
||||
'channelId' => 'my-content',
|
||||
);
|
||||
}
|
||||
@@ -214,8 +205,14 @@ class _MyStuff
|
||||
public static function parse_mobile_quote( \IPS\Lang $language, \IPS\Content $content )
|
||||
{
|
||||
$item = ( $content instanceof \IPS\Content\Item ) ? $content : $content->item();
|
||||
|
||||
$idField = $item::$databaseColumnId;
|
||||
|
||||
return array(
|
||||
'title' => $language->addToStack( 'notification__new_quote_title', FALSE, array(
|
||||
'htmlsprintf' => array(
|
||||
mb_strtolower( $item->indefiniteArticle( $language ) ),
|
||||
)
|
||||
) ),
|
||||
'body' => $language->addToStack( 'notification__new_quote', FALSE, array(
|
||||
'pluralize' => array( 1 ),
|
||||
'htmlsprintf' => array(
|
||||
@@ -226,8 +223,16 @@ class _MyStuff
|
||||
) ),
|
||||
'data' => array(
|
||||
'url' => (string) $content->url(),
|
||||
'author' => $content->author()
|
||||
'author' => $content->author(),
|
||||
'grouped' => $language->addToStack( 'notification__new_quote_grouped', FALSE, array(
|
||||
'htmlsprintf' => array(
|
||||
mb_strtolower( $item->indefiniteArticle( $language ) ),
|
||||
$item->mapped('title')
|
||||
)
|
||||
) ),
|
||||
// No need for groupedUrl - just go to the most recent quote
|
||||
),
|
||||
'tag' => md5( 'quote' . \get_class( $item ) . $item->$idField ), // Group quote notifications by content item
|
||||
'channelId' => 'my-content',
|
||||
);
|
||||
}
|
||||
@@ -318,9 +323,17 @@ class _MyStuff
|
||||
public static function parse_mobile_new_likes( \IPS\Lang $language, \IPS\Content $content, \IPS\Member $liker )
|
||||
{
|
||||
$item = ( $content instanceof \IPS\Content\Item ) ? $content : $content->item();
|
||||
|
||||
$idField = $item::$databaseColumnId;
|
||||
$lang = \IPS\Content\Reaction::isLikeMode() ? 'notification__new_likes' : 'notification__new_react';
|
||||
|
||||
return array(
|
||||
'body' => $language->addToStack( \IPS\Content\Reaction::isLikeMode() ? 'notification__new_likes' : 'notification__new_react', FALSE, array(
|
||||
'title' => $language->addToStack( $lang . '_title', FALSE, array(
|
||||
'pluralize' => array(1),
|
||||
'htmlsprintf' => array(
|
||||
mb_strtolower( $item->indefiniteArticle( $language ) )
|
||||
)
|
||||
) ),
|
||||
'body' => $language->addToStack( $lang, FALSE, array(
|
||||
'pluralize' => array( 1 ),
|
||||
'htmlsprintf' => array(
|
||||
( $content->author()->group['gbw_view_reps'] ) ? $language->formatList( array( $liker->name ) ) : $language->pluralize(
|
||||
@@ -332,8 +345,21 @@ class _MyStuff
|
||||
) ) . ' ' . $item->mapped('title'),
|
||||
'data' => array(
|
||||
'url' => (string) $content->url(),
|
||||
'author' => $liker
|
||||
'author' => $liker,
|
||||
'grouped' => $language->addToStack( $lang . '_grouped', FALSE, array(
|
||||
'htmlsprintf' => array(
|
||||
mb_strtolower( $content->indefiniteArticle( $language ) )
|
||||
)
|
||||
) ),
|
||||
'groupedTitle' => $language->addToStack( $lang . '_title', FALSE, array(
|
||||
// Pluralized on the client
|
||||
'htmlsprintf' => array(
|
||||
mb_strtolower( $item->indefiniteArticle( $language ) )
|
||||
)
|
||||
) ),
|
||||
// No need for groupedUrl - just go to the most recent thing
|
||||
),
|
||||
'tag' => md5( 'likes' . \get_class( $item ) . $item->$idField ), // Group quote notifications by content item
|
||||
'channelId' => 'my-content',
|
||||
);
|
||||
}
|
||||
@@ -392,8 +418,10 @@ class _MyStuff
|
||||
public static function parse_mobile_embed( \IPS\Lang $language, \IPS\Content $content )
|
||||
{
|
||||
$item = ( $content instanceof \IPS\Content\Item ) ? $content : $content->item();
|
||||
|
||||
$idField = $item::$databaseColumnId;
|
||||
|
||||
return array(
|
||||
'title' => $language->addToStack( 'notification__new_embed_title' ),
|
||||
'body' => $language->addToStack( 'notification__new_embed', FALSE, array(
|
||||
'pluralize' => array( 1 ),
|
||||
'htmlsprintf' => array(
|
||||
@@ -402,6 +430,244 @@ class _MyStuff
|
||||
$item->mapped('title')
|
||||
)
|
||||
) ),
|
||||
'data' => array(
|
||||
'url' => (string) $content->url(),
|
||||
'author' => $content->author(),
|
||||
'grouped' => $language->addToStack( 'notification__new_embed_grouped', FALSE, array(
|
||||
'htmlsprintf' => array(
|
||||
mb_strtolower( $item->indefiniteArticle( $language ) ),
|
||||
$item->mapped('title')
|
||||
)
|
||||
) ),
|
||||
// No need for groupedUrl - just go to the most recent thing
|
||||
),
|
||||
'tag' => md5( 'embed' . \get_class( $item ) . $item->$idField ), // Group embed notifications by content item
|
||||
'channelId' => 'my-content',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse notification: mine_solved
|
||||
*
|
||||
* @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_mine_solved( \IPS\Notification\Inline $notification, $htmlEscape=TRUE )
|
||||
{
|
||||
$item = $notification->item;
|
||||
if ( !$item )
|
||||
{
|
||||
throw new \OutOfRangeException;
|
||||
}
|
||||
|
||||
$commentClass = $item::$commentClass;
|
||||
$comment = $commentClass::loadAndCheckPerms( $notification->item_sub_id );
|
||||
|
||||
$name = ( $comment->isAnonymous() ) ? \IPS\Member::loggedIn()->language()->addToStack( 'post_anonymously_placename' ) : $comment->author()->name;
|
||||
|
||||
/* Unread? */
|
||||
$unread = false;
|
||||
if ( $item->timeLastRead() instanceof \IPS\DateTime )
|
||||
{
|
||||
$unread = (bool) ( $item->timeLastRead()->getTimestamp() < $notification->updated_time->getTimestamp() );
|
||||
}
|
||||
|
||||
return array(
|
||||
'title' => \IPS\Member::loggedIn()->language()->addToStack( 'notification__minesolved', FALSE, array(
|
||||
( $htmlEscape ? 'sprintf' : 'htmlsprintf' ) => array(
|
||||
$name,
|
||||
mb_strtolower( $item->indefiniteArticle() ),
|
||||
$item->mapped('title')
|
||||
)
|
||||
) ),
|
||||
'url' => $comment->url('find'),
|
||||
'content' => $comment->content(),
|
||||
'author' => $comment->author(),
|
||||
'unread' => (bool) $unread
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse notification for mobile: mine_solved
|
||||
*
|
||||
* @param \IPS\Lang $language The language that the notification should be in
|
||||
* @param \IPS\Content $content The content
|
||||
* @return array
|
||||
*/
|
||||
public static function parse_mobile_mine_solved( \IPS\Lang $language, \IPS\Content $content )
|
||||
{
|
||||
$item = ( $content instanceof \IPS\Content\Item ) ? $content : $content->item();
|
||||
$name = ( $content->isAnonymous() ) ? \IPS\Member::loggedIn()->language()->addToStack( 'post_anonymously_placename' ) : $content->author()->name;
|
||||
|
||||
return array(
|
||||
'title' => $language->addToStack( 'notification__minesolved_title', FALSE, array(
|
||||
'htmlsprintf' => array(
|
||||
mb_strtolower( $item->definiteArticle() ),
|
||||
)
|
||||
) ),
|
||||
'body' => $language->addToStack( 'notification__minesolved', FALSE, array(
|
||||
'htmlsprintf' => array(
|
||||
$name,
|
||||
mb_strtolower( $item->indefiniteArticle() ),
|
||||
$item->mapped('title')
|
||||
)
|
||||
) ),
|
||||
'data' => array(
|
||||
'url' => (string) $content->url('find'),
|
||||
'author' => $content->author()
|
||||
),
|
||||
'channelId' => 'my-content',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse notification: my_solution
|
||||
*
|
||||
* @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_my_solution( \IPS\Notification\Inline $notification, $htmlEscape=TRUE )
|
||||
{
|
||||
$item = $notification->item;
|
||||
if ( !$item )
|
||||
{
|
||||
throw new \OutOfRangeException;
|
||||
}
|
||||
|
||||
$commentClass = $item::$commentClass;
|
||||
$comment = $commentClass::loadAndCheckPerms( $notification->item_sub_id );
|
||||
|
||||
/* Unread? */
|
||||
$unread = false;
|
||||
if ( $item->timeLastRead() instanceof \IPS\DateTime )
|
||||
{
|
||||
$unread = (bool) ( $item->timeLastRead()->getTimestamp() < $notification->updated_time->getTimestamp() );
|
||||
}
|
||||
|
||||
return array(
|
||||
'title' => \IPS\Member::loggedIn()->language()->addToStack( 'notification__mysolution', FALSE, array(
|
||||
( $htmlEscape ? 'sprintf' : 'htmlsprintf' ) => array(
|
||||
$item->mapped('title')
|
||||
)
|
||||
) ),
|
||||
'url' => $comment->url('find'),
|
||||
'content' => $comment->content(),
|
||||
'author' => $comment->author(),
|
||||
'unread' => (bool) $unread
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse notification for mobile: my_solution
|
||||
*
|
||||
* @param \IPS\Lang $language The language that the notification should be in
|
||||
* @param \IPS\Content $content The content
|
||||
* @return array
|
||||
*/
|
||||
public static function parse_mobile_my_solution( \IPS\Lang $language, \IPS\Content $content )
|
||||
{
|
||||
$item = ( $content instanceof \IPS\Content\Item ) ? $content : $content->item();
|
||||
|
||||
return array(
|
||||
'title' => $language->addToStack( 'notification__mysolution_title', FALSE, array(
|
||||
'htmlsprintf' => array(
|
||||
mb_strtolower( $item->indefiniteArticle() ),
|
||||
)
|
||||
) ),
|
||||
'body' => $language->addToStack( 'notification__mysolution', FALSE, array(
|
||||
'htmlsprintf' => array(
|
||||
$item->mapped('title')
|
||||
)
|
||||
) ),
|
||||
'data' => array(
|
||||
'url' => (string) $content->url('find'),
|
||||
'author' => $content->author()
|
||||
),
|
||||
'channelId' => 'my-content',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse notification: approved
|
||||
*
|
||||
* @param \IPS\Notification\Inline $notification The notification
|
||||
* @param bool $htmlEscape TRUE to escape HTML in title
|
||||
* @return array|NULL
|
||||
* @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_approved_content( \IPS\Notification\Inline $notification, $htmlEscape=TRUE ): array
|
||||
{
|
||||
$item = ( $notification->item instanceof \IPS\Content\Comment ) ? $notification->item->item() : $notification->item;
|
||||
if ( !$item )
|
||||
{
|
||||
throw new \OutOfRangeException;
|
||||
}
|
||||
|
||||
$comment = $notification->item_sub ?: $item;
|
||||
if ( !$comment )
|
||||
{
|
||||
throw new \OutOfRangeException;
|
||||
}
|
||||
|
||||
return array(
|
||||
'title' => \IPS\Member::loggedIn()->language()->addToStack( 'notification__approved_content', FALSE, array( ( $htmlEscape ? 'sprintf' : 'htmlsprintf' ) => array( mb_strtolower( $comment->definiteArticle() ), $item->mapped('title') ) ) ),
|
||||
'url' => $comment instanceof \IPS\Content\Item ? $item->url() : $comment->url('find'),
|
||||
'content' => $comment->truncated(),
|
||||
'author' => $comment->author(),
|
||||
'unread' => (bool) ( $item->unread() ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse notification for mobile: approved
|
||||
*
|
||||
* @param \IPS\Lang $language The language that the notification should be in
|
||||
* @param \IPS\Content $content The content
|
||||
* @return array
|
||||
*/
|
||||
public static function parse_mobile_approved_content( \IPS\Lang $language, \IPS\Content $content ): array
|
||||
{
|
||||
$item = ( $content instanceof \IPS\Content\Item ) ? $content : $content->item();
|
||||
|
||||
return array(
|
||||
'title' => $language->addToStack( 'notification__approved_content_title' ),
|
||||
'body' => $language->addToStack( 'notification__approved_content', FALSE, array(
|
||||
'htmlsprintf' => array(
|
||||
mb_strtolower( $content->definiteArticle( $language ) ),
|
||||
$item->mapped('title')
|
||||
)
|
||||
) ),
|
||||
'data' => array(
|
||||
'url' => (string) $content->url(),
|
||||
'author' => $content->author()
|
||||
|
||||
@@ -35,16 +35,19 @@ class _Profile
|
||||
$module = \IPS\Application\Module::get( 'core', 'members', 'front' );
|
||||
if ( $module->_enabled and ( $member === NULL or $member->canAccessModule( $module ) ) )
|
||||
{
|
||||
$return['core_Profile_status'] = array(
|
||||
'type' => 'standard',
|
||||
'notificationTypes' => array( 'profile_comment', 'profile_reply', 'new_status' ),
|
||||
'title' => 'notifications__core_Profile_status',
|
||||
'showTitle' => TRUE,
|
||||
'description' => 'notifications__core_Profile_status_desc',
|
||||
'default' => array( 'inline', 'push' ),
|
||||
'disabled' => array(),
|
||||
);
|
||||
|
||||
if( $member == NULL or $member->canAccessModule( \IPS\Application\Module::get( 'core', 'status', 'front' ) ) and \IPS\Settings::i()->profile_comments )
|
||||
{
|
||||
$return['core_Profile_status'] = array(
|
||||
'type' => 'standard',
|
||||
'notificationTypes' => array( 'profile_comment', 'profile_reply', 'new_status' ),
|
||||
'title' => 'notifications__core_Profile_status',
|
||||
'showTitle' => TRUE,
|
||||
'description' => 'notifications__core_Profile_status_desc',
|
||||
'default' => array( 'inline', 'push' ),
|
||||
'disabled' => array(),
|
||||
);
|
||||
}
|
||||
|
||||
$return['core_Profile_follow'] = array(
|
||||
'type' => 'standard',
|
||||
'notificationTypes' => array( 'member_follow' ),
|
||||
@@ -110,6 +113,7 @@ class _Profile
|
||||
public static function parse_mobile_member_follow( \IPS\Lang $language, \IPS\Member $member )
|
||||
{
|
||||
return array(
|
||||
'title' => $language->addToStack( 'notification__member_follow_title' ),
|
||||
'body' => $language->addToStack( 'notification__member_follow', FALSE, array( 'htmlsprintf' => array( $member->name ) ) ),
|
||||
'data' => array(
|
||||
'url' => (string) $member->url(),
|
||||
@@ -163,6 +167,7 @@ class _Profile
|
||||
public static function parse_mobile_profile_comment( \IPS\Lang $language, \IPS\core\Statuses\Status $comment )
|
||||
{
|
||||
return array(
|
||||
'body' => $language->addToStack( 'notification__profile_comment_title' ),
|
||||
'body' => $language->addToStack( 'notification__profile_comment', FALSE, array( 'htmlsprintf' => array( $comment->author()->name ) ) ),
|
||||
'data' => array(
|
||||
'url' => (string) $comment->url(),
|
||||
@@ -216,6 +221,7 @@ class _Profile
|
||||
public static function parse_mobile_new_status( \IPS\Lang $language, \IPS\core\Statuses\Status $status )
|
||||
{
|
||||
return array(
|
||||
'title' => $language->addToStack( 'notification__new_status_title' ),
|
||||
'body' => $language->addToStack( 'notification__new_status', FALSE, array( 'htmlsprintf' => array( $status->author()->name ) ) ),
|
||||
'data' => array(
|
||||
'url' => (string) $status->url(),
|
||||
@@ -269,6 +275,7 @@ class _Profile
|
||||
public static function parse_mobile_profile_reply( \IPS\Lang $language, \IPS\core\Statuses\Reply $reply )
|
||||
{
|
||||
return array(
|
||||
'title' => $language->addToStack( 'notification__profile_reply_title' ),
|
||||
'body' => $language->addToStack( 'notification__profile_reply', FALSE, array( 'htmlsprintf' => array( $reply->author()->name ) ) ),
|
||||
'data' => array(
|
||||
'url' => (string) $reply->item()->url(),
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Overview statistics extension: Badges
|
||||
* @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 10 Mar 2021
|
||||
*/
|
||||
|
||||
namespace IPS\core\extensions\core\OverviewStatistics;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Overview statistics extension: Badges
|
||||
*/
|
||||
class _Badges
|
||||
{
|
||||
/**
|
||||
* @brief Which statistics page (activity or user)
|
||||
*/
|
||||
public $page = 'user';
|
||||
|
||||
/**
|
||||
* Return the sub-block keys
|
||||
*
|
||||
* @note This is designed to allow one class to support multiple blocks, for instance using the ContentRouter to generate blocks.
|
||||
* @return array
|
||||
*/
|
||||
public function getBlocks()
|
||||
{
|
||||
return array( 'subblockKey' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return block details (title and description)
|
||||
*
|
||||
* @param string|NULL $subBlock The subblock we are loading as returned by getBlocks()
|
||||
* @return array
|
||||
*/
|
||||
public function getBlockDetails( $subBlock = NULL )
|
||||
{
|
||||
/* Description can be null and will not be shown if so */
|
||||
return array( 'app' => 'core', 'title' => 'stats_member_badges_overview', 'description' => null, 'refresh' => 60 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the block HTML to show
|
||||
*
|
||||
* @param array|NULL $dateRange NULL for all time, or an array with 'start' and 'end' \IPS\DateTime objects to restrict to
|
||||
* @param string|NULL $subBlock The subblock we are loading as returned by getBlocks()
|
||||
* @return string
|
||||
*/
|
||||
public function getBlock( $dateRange = NULL, $subBlock = NULL )
|
||||
{
|
||||
$where = NULL;
|
||||
$previousCount = NULL;
|
||||
|
||||
if( $dateRange !== NULL )
|
||||
{
|
||||
if( \is_array( $dateRange ) )
|
||||
{
|
||||
$where = array(
|
||||
array( 'datetime > ?', $dateRange['start']->getTimestamp() ),
|
||||
array( 'datetime < ?', $dateRange['end']->getTimestamp() ),
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
$currentDate = new \IPS\DateTime;
|
||||
$interval = NULL;
|
||||
|
||||
switch( $dateRange )
|
||||
{
|
||||
case '7':
|
||||
$interval = new \DateInterval( 'P7D' );
|
||||
break;
|
||||
|
||||
case '30':
|
||||
$interval = new \DateInterval( 'P1M' );
|
||||
break;
|
||||
|
||||
case '90':
|
||||
$interval = new \DateInterval( 'P3M' );
|
||||
break;
|
||||
|
||||
case '180':
|
||||
$interval = new \DateInterval( 'P6M' );
|
||||
break;
|
||||
|
||||
case '365':
|
||||
$interval = new \DateInterval( 'P1Y' );
|
||||
break;
|
||||
}
|
||||
|
||||
$initialTimestamp = $currentDate->sub( $interval )->getTimestamp();
|
||||
$where = array( array( 'datetime > ?', $initialTimestamp ) );
|
||||
|
||||
$previousCount = \IPS\Db::i()->select( 'COUNT(*)', 'core_member_badges', array( array( 'datetime BETWEEN ? AND ?', $currentDate->sub( $interval )->getTimestamp(), $initialTimestamp ) ) )->first();
|
||||
}
|
||||
}
|
||||
|
||||
$count = \IPS\Db::i()->select( 'COUNT(*)', 'core_member_badges', $where )->first();
|
||||
|
||||
return \IPS\Theme::i()->getTemplate( 'stats' )->overviewComparisonCount( $count, $previousCount );
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,6 @@
|
||||
* @copyright (c) Invision Power Services, Inc.
|
||||
* @license https://www.invisioncommunity.com/legal/standards/
|
||||
* @package Invision Community
|
||||
|
||||
* @since 16 Jan 2020
|
||||
*/
|
||||
|
||||
@@ -157,19 +156,7 @@ class _ContentActivity
|
||||
$initialTimestamp = $currentDate->sub( $interval )->getTimestamp();
|
||||
$where = array( array( $class::$databasePrefix . $dateColumn . ' > ?', $initialTimestamp ) );
|
||||
|
||||
if( isset( $class::$containerNodeClass ) AND \IPS\Request::i()->nodes )
|
||||
{
|
||||
$where[] = array( \IPS\Db::i()->in( $class::$databasePrefix . $class::$databaseColumnMap['container'], explode( ',', \IPS\Request::i()->nodes ) ) );
|
||||
}
|
||||
|
||||
$previousValues[ $class::$title . '_pl' ] = \IPS\Db::i()->select( 'COUNT(*)', $class::$databaseTable, array( array( $class::$databasePrefix . $dateColumn . ' BETWEEN ? AND ?', $currentDate->sub( $interval )->getTimestamp(), $initialTimestamp ) ) )->first();
|
||||
}
|
||||
}
|
||||
else if ( $dateRange === NULL and isset( \IPS\Request::i()->nodes ) )
|
||||
{
|
||||
if( isset( $class::$containerNodeClass ) AND \IPS\Request::i()->nodes )
|
||||
{
|
||||
$where = array( array( \IPS\Db::i()->in( $class::$databasePrefix . $class::$databaseColumnMap['container'], explode( ',', \IPS\Request::i()->nodes ) ) ) );
|
||||
$previousValues[ $class::$title . '_pl' ] = \IPS\Db::i()->select( 'COUNT(*)', $class::$databaseTable, $this->_modifyWhereClause( array( array( $class::$databasePrefix . $dateColumn . ' BETWEEN ? AND ?', $currentDate->sub( $interval )->getTimestamp(), $initialTimestamp ) ), $class ) )->first();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,12 +169,50 @@ class _ContentActivity
|
||||
}
|
||||
}
|
||||
|
||||
$values[ $class::$title . '_pl' ] = \IPS\Db::i()->select( 'COUNT(*)', $class::$databaseTable, $where )->first();
|
||||
$values[ $class::$title . '_pl' ] = \IPS\Db::i()->select( 'COUNT(*)', $class::$databaseTable, $this->_modifyWhereClause( $where, $class ) )->first();
|
||||
}
|
||||
|
||||
return \IPS\Theme::i()->getTemplate( 'activitystats' )->overviewCounts( $values, $previousValues, $nodeNames );
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify the where clause to apply other filters
|
||||
*
|
||||
* @param array $where Current where clause
|
||||
* @param \IPS\Content $class Class we are working with
|
||||
* @return array
|
||||
*/
|
||||
protected function _modifyWhereClause( $where, $class )
|
||||
{
|
||||
/* Don't include soft deleted content */
|
||||
$column = NULL;
|
||||
if ( isset( $class::$databaseColumnMap['hidden'] ) )
|
||||
{
|
||||
$column = $class::$databasePrefix . $class::$databaseColumnMap['hidden'];
|
||||
}
|
||||
elseif ( isset( $class::$databaseColumnMap['approved'] ) )
|
||||
{
|
||||
$column = $class::$databasePrefix . $class::$databaseColumnMap['approved'];
|
||||
}
|
||||
|
||||
if ( $column )
|
||||
{
|
||||
$where[] = array( \IPS\Db::i()->in( $column, array( -2, -3 ), TRUE ) );
|
||||
}
|
||||
|
||||
if ( method_exists( $class, 'overviewStatisticsWhere' ) )
|
||||
{
|
||||
$where = array_merge( $where, $class::overviewStatisticsWhere() );
|
||||
}
|
||||
|
||||
if( isset( $class::$containerNodeClass ) AND \IPS\Request::i()->nodes )
|
||||
{
|
||||
$where[] = array( \IPS\Db::i()->in( $class::$databasePrefix . $class::$databaseColumnMap['container'], explode( ',', \IPS\Request::i()->nodes ) ) );
|
||||
}
|
||||
|
||||
return $where;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return block filter form, or the updated block result upon submit
|
||||
*
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Overview statistics extension: Points
|
||||
* @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 10 Mar 2021
|
||||
*/
|
||||
|
||||
namespace IPS\core\extensions\core\OverviewStatistics;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Overview statistics extension: Points
|
||||
*/
|
||||
class _Points
|
||||
{
|
||||
/**
|
||||
* @brief Which statistics page (activity or user)
|
||||
*/
|
||||
public $page = 'user';
|
||||
|
||||
/**
|
||||
* Return the sub-block keys
|
||||
*
|
||||
* @note This is designed to allow one class to support multiple blocks, for instance using the ContentRouter to generate blocks.
|
||||
* @return array
|
||||
*/
|
||||
public function getBlocks()
|
||||
{
|
||||
return array( 'points' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return block details (title and description)
|
||||
*
|
||||
* @param string|NULL $subBlock The subblock we are loading as returned by getBlocks()
|
||||
* @return array
|
||||
*/
|
||||
public function getBlockDetails( $subBlock = NULL )
|
||||
{
|
||||
/* Description can be null and will not be shown if so */
|
||||
return array( 'app' => 'core', 'title' => 'stats_member_points_overview', 'description' => null, 'refresh' => 60 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the block HTML to show
|
||||
*
|
||||
* @param array|NULL $dateRange NULL for all time, or an array with 'start' and 'end' \IPS\DateTime objects to restrict to
|
||||
* @param string|NULL $subBlock The subblock we are loading as returned by getBlocks()
|
||||
* @return string
|
||||
*/
|
||||
public function getBlock( $dateRange = NULL, $subBlock = NULL )
|
||||
{
|
||||
$where = NULL;
|
||||
$previousCount = NULL;
|
||||
|
||||
if( $dateRange !== NULL )
|
||||
{
|
||||
if( \is_array( $dateRange ) )
|
||||
{
|
||||
$where = array(
|
||||
array( 'datetime > ?', $dateRange['start']->getTimestamp() ),
|
||||
array( 'datetime < ?', $dateRange['end']->getTimestamp() ),
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
$currentDate = new \IPS\DateTime;
|
||||
$interval = NULL;
|
||||
|
||||
switch( $dateRange )
|
||||
{
|
||||
case '7':
|
||||
$interval = new \DateInterval( 'P7D' );
|
||||
break;
|
||||
|
||||
case '30':
|
||||
$interval = new \DateInterval( 'P1M' );
|
||||
break;
|
||||
|
||||
case '90':
|
||||
$interval = new \DateInterval( 'P3M' );
|
||||
break;
|
||||
|
||||
case '180':
|
||||
$interval = new \DateInterval( 'P6M' );
|
||||
break;
|
||||
|
||||
case '365':
|
||||
$interval = new \DateInterval( 'P1Y' );
|
||||
break;
|
||||
}
|
||||
|
||||
$initialTimestamp = $currentDate->sub( $interval )->getTimestamp();
|
||||
$where = array( array( 'datetime > ?', $initialTimestamp ) );
|
||||
|
||||
$previousCount = \IPS\Db::i()->select( 'SUM(points)', 'core_points_log', array( array( 'datetime BETWEEN ? AND ?', $currentDate->sub( $interval )->getTimestamp(), $initialTimestamp ) ) )->first();
|
||||
}
|
||||
}
|
||||
|
||||
$count = \IPS\Db::i()->select( 'SUM(points)', 'core_points_log', $where )->first();
|
||||
|
||||
return \IPS\Theme::i()->getTemplate( 'stats' )->overviewComparisonCount( $count, $previousCount );
|
||||
}
|
||||
}
|
||||
@@ -101,7 +101,10 @@ class _Tags
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Only get visible tags */
|
||||
$where[] = array( 'tag_aai_lookup IN(?)', \IPS\Db::i()->select( 'tag_perm_aai_lookup', 'core_tags_perms', [ 'tag_perm_visible=1' ] ) );
|
||||
|
||||
foreach( \IPS\Db::i()->select( 'COUNT(*) as total, tag_text', 'core_tags', $where, 'total DESC', 5, 'tag_text' ) as $tag )
|
||||
{
|
||||
$topTags[ $tag['tag_text'] ] = $tag['total'];
|
||||
|
||||
@@ -119,7 +119,7 @@ class _ProfileFields
|
||||
{
|
||||
if ( $key == 'core_pfield_' . $fieldId )
|
||||
{
|
||||
if ( (bool) $value )
|
||||
if ( (bool) $value or $value === "0" )
|
||||
{
|
||||
$done++;
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ class _DeleteImageProxyFiles
|
||||
* @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 )
|
||||
{
|
||||
/* We don't want to delete the files if we are caching indefinitely */
|
||||
if( !$data['cachePeriod'] )
|
||||
@@ -53,6 +53,12 @@ class _DeleteImageProxyFiles
|
||||
throw new \IPS\Task\Queue\OutOfRangeException;
|
||||
}
|
||||
|
||||
/* Kill the process if there table doesn't exist anymore */
|
||||
if( !\IPS\Db::i()->checkForTable( 'core_image_proxy' ) )
|
||||
{
|
||||
throw new \IPS\Task\Queue\OutOfRangeException;
|
||||
}
|
||||
|
||||
$select = \IPS\Db::i()->select( 'location', 'core_image_proxy', array(), 'cache_time ASC', \IPS\REBUILD_SLOW );
|
||||
|
||||
$completed = 0;
|
||||
@@ -76,7 +82,7 @@ class _DeleteImageProxyFiles
|
||||
throw new \IPS\Task\Queue\OutOfRangeException;
|
||||
}
|
||||
|
||||
return $completed;
|
||||
return $completed + $offset;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,172 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Background Task
|
||||
* @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 05 Feb 2021
|
||||
*/
|
||||
|
||||
namespace IPS\core\extensions\core\Queue;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Background Task
|
||||
*/
|
||||
class _FileCleanup
|
||||
{
|
||||
/**
|
||||
* @brief Number of thumbnails to build per cycle
|
||||
*/
|
||||
public $perCycle = \IPS\REBUILD_SLOW;
|
||||
|
||||
/**
|
||||
* Parse data before queuing
|
||||
*
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
public function preQueueData( $data )
|
||||
{
|
||||
/* Make sure we have the minimal amount of data we need */
|
||||
if( !isset( $data['table'] ) OR empty( $data['column'] ) OR empty( $data['storageExtension'] ) )
|
||||
{
|
||||
throw new \OutOfRangeException;
|
||||
}
|
||||
|
||||
$data['maxId'] = NULL;
|
||||
|
||||
if( isset( $data['primaryId'] ) )
|
||||
{
|
||||
$data['maxId'] = \IPS\Db::i()->select( 'MAX(' . $data['primaryId'] . ')', $data['table'] )->first();
|
||||
}
|
||||
|
||||
$data['count'] = \IPS\Db::i()->select( 'count(*)', $data['table'] )->first();
|
||||
$data['deleted'] = 0;
|
||||
|
||||
/* Convert the storage extension to get the configuration ID */
|
||||
if( !\is_numeric( $data['storageExtension'] ) )
|
||||
{
|
||||
$data['storageExtension'] = (int) \IPS\File::getClass( $data['storageExtension'] )->configurationId;
|
||||
}
|
||||
|
||||
/* Normalize columns */
|
||||
$data['column'] = !\is_array( $data['column'] ) ? array( $data['column'] ) : $data['column'];
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run Background Task
|
||||
*
|
||||
* @param mixed $data Data as it was passed to \IPS\Task::queue()
|
||||
* @param int $offset Offset
|
||||
* @return int New offset
|
||||
* @throws \IPS\Task\Queue\OutOfRangeException Indicates offset doesn't exist and thus task is complete
|
||||
*/
|
||||
public function run( &$data, $offset )
|
||||
{
|
||||
$last = ( isset( $data['primaryId'] ) ) ? NULL : $offset;
|
||||
$deleted = 0;
|
||||
|
||||
\IPS\Log::debug( "Deleting files from an offset of " . $offset, 'deleteFilesTask' );
|
||||
|
||||
$where = isset( $data['where'] ) ? $data['where'] : array();
|
||||
if( isset( $data['primaryId'] ) )
|
||||
{
|
||||
$where[] = array( $data['primaryId'] . '> ?', $offset );
|
||||
$limit = array( 0, $this->perCycle );
|
||||
$order = $data['primaryId'] . ' ASC';
|
||||
}
|
||||
else
|
||||
{
|
||||
$limit = array( $offset, $this->perCycle );
|
||||
$order = NULL;
|
||||
}
|
||||
|
||||
foreach( \IPS\Db::i()->select( '*', $data['table'], $where, $order, $limit ) as $row )
|
||||
{
|
||||
/* Set the last ID we deleted now */
|
||||
$last = ( isset( $data['primaryId'] ) ) ? $row[ $data['primaryId'] ] : ( $last + 1 );
|
||||
|
||||
/* Increment the counter for the progress bar */
|
||||
$deleted++;
|
||||
|
||||
/* Handle each column */
|
||||
foreach( $data['column'] as $column )
|
||||
{
|
||||
if( isset( $row[ $column ] ) AND $row[ $column ] )
|
||||
{
|
||||
$values = ( isset( $data['multipleFiles'] ) AND $data['multipleFiles'] ) ? explode( ',', $row[ $column ] ) : array( $row[ $column ] );
|
||||
|
||||
foreach( $values as $fileLocation )
|
||||
{
|
||||
try
|
||||
{
|
||||
\IPS\File::get( $data['storageExtension'], $fileLocation )->delete();
|
||||
}
|
||||
catch( \Exception $e )
|
||||
{
|
||||
\IPS\Log::log( $e, 'fileCleanupDeleteFailed' );
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$data['deleted'] = $data['deleted'] + $deleted;
|
||||
|
||||
if( $deleted === 0 )
|
||||
{
|
||||
throw new \IPS\Task\Queue\OutOfRangeException;
|
||||
}
|
||||
|
||||
return $last;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Progress
|
||||
*
|
||||
* @param mixed $data Data as it was passed to \IPS\Task::queue()
|
||||
* @param int $offset Offset
|
||||
* @return array( 'text' => 'Doing something...', 'complete' => 50 ) Text explaining task and percentage complete
|
||||
* @throws \OutOfRangeException Indicates offset doesn't exist and thus task is complete
|
||||
*/
|
||||
public function getProgress( $data, $offset )
|
||||
{
|
||||
return array( 'text' => \IPS\Member::loggedIn()->language()->addToStack('deleting_files_generic'), 'complete' => $data['count'] ? ( round( ( 100 / $data['count'] ) * $data['deleted'], 2 ) ) : 100 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform post-completion processing
|
||||
*
|
||||
* @param array $data Data returned from preQueueData
|
||||
* @param bool $processed Was anything processed or not? If preQueueData returns NULL, this will be FALSE.
|
||||
* @return void
|
||||
*/
|
||||
public function postComplete( $data, $processed = TRUE )
|
||||
{
|
||||
$data = json_decode( $data['data'], TRUE );
|
||||
|
||||
if( isset( $data['dropTable'] ) )
|
||||
{
|
||||
\IPS\Db::i()->dropTable( $data['dropTable'], TRUE );
|
||||
}
|
||||
elseif( isset( $data['dropColumn'] ) AND isset( $data['dropColumnTable'] ) )
|
||||
{
|
||||
\IPS\Db::i()->dropColumn( $data['dropColumnTable'], $data['dropColumn'] );
|
||||
}
|
||||
elseif( isset( $data['deleteRows'] ) AND $data['deleteRows'] )
|
||||
{
|
||||
\IPS\Db::i()->delete( $data['table'], $data['where'] );
|
||||
}
|
||||
}
|
||||
}
|
||||
Loaded 100 of 2036 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user