Version 5.0.14
This commit is contained in:
1 parent
5efe744c5f
commit
dbd774b30c
364 files changed
+7048
-1377
No files matched your search
@@ -251,13 +251,16 @@ class Reaction extends ContentAchievementActionAbstract
|
||||
try
|
||||
{
|
||||
$class = $exploded[0];
|
||||
$content = $class::load( $exploded[1] );
|
||||
if( \IPS\IPS::classUsesTrait( $content, 'IPS\Content\Reactable' ) )
|
||||
if( class_exists( $class ) )
|
||||
{
|
||||
$contentLink = Theme::i()->getTemplate( 'global', 'core', 'global' )->basicUrl( $content->url(), TRUE, $content->indefiniteArticle(), FALSE );
|
||||
$content = $class::load( $exploded[1] );
|
||||
if( \IPS\IPS::classUsesTrait( $content, 'IPS\Content\Reactable' ) )
|
||||
{
|
||||
$contentLink = Theme::i()->getTemplate( 'global', 'core', 'global' )->basicUrl( $content->url(), TRUE, $content->indefiniteArticle(), FALSE );
|
||||
|
||||
$reaction = $content->reacted( Member::load( $exploded[2] ) );
|
||||
$reactionName = $reaction->_title;
|
||||
$reaction = $content->reacted( Member::load( $exploded[2] ) );
|
||||
$reactionName = $reaction->_title;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch ( Exception $e ) { }
|
||||
|
||||
@@ -0,0 +1,218 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Community Enhancements
|
||||
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) Invision Power Services, Inc.
|
||||
* @license https://www.invisioncommunity.com/legal/standards/
|
||||
* @package Invision Community
|
||||
|
||||
* @since 23 Oct 2025
|
||||
*/
|
||||
|
||||
namespace IPS\core\extensions\core\CommunityEnhancements;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
|
||||
use Exception;
|
||||
use IPS\Dispatcher;
|
||||
use IPS\Extensions\CommunityEnhancementsAbstract;
|
||||
use IPS\Helpers\Form;
|
||||
use IPS\Helpers\Form\Stack;
|
||||
use IPS\Helpers\Form\Text;
|
||||
use IPS\Helpers\Form\YesNo;
|
||||
use IPS\Http\Url;
|
||||
use IPS\Member;
|
||||
use IPS\Member as MemberClass;
|
||||
use IPS\Output;
|
||||
use IPS\Theme;
|
||||
use IPS\Settings;
|
||||
use LogicException;
|
||||
use function defined;
|
||||
use function explode;
|
||||
use function implode;
|
||||
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Community Enhancement
|
||||
*/
|
||||
class Iframely extends CommunityEnhancementsAbstract
|
||||
{
|
||||
/**
|
||||
* @brief Enhancement is enabled?
|
||||
*/
|
||||
public bool $enabled = false;
|
||||
|
||||
/**
|
||||
* @brief IPS-provided enhancement?
|
||||
*/
|
||||
public bool $ips = false;
|
||||
|
||||
/**
|
||||
* @brief Enhancement has configuration options?
|
||||
*/
|
||||
public bool $hasOptions = true;
|
||||
|
||||
/**
|
||||
* @brief Icon data
|
||||
*/
|
||||
public string $icon = "iframely.png";
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
foreach ( [ 'iframely_enabled', 'iframely_api_key', 'iframely_url_whitelist' ] as $key )
|
||||
{
|
||||
$this->_settings[$key] = Settings::i()->$key;
|
||||
}
|
||||
$this->enabled = (bool) Settings::i()->iframely_enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* The settings that this extension is currently using
|
||||
* @var array
|
||||
*/
|
||||
protected array $_settings = [];
|
||||
|
||||
/**
|
||||
* Edit
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function edit() : void
|
||||
{
|
||||
$form = new Form;
|
||||
|
||||
$message = Member::loggedIn()->language()->addToStack( 'enhancements__core_Iframely_desc_full' );
|
||||
if ( Dispatcher::i()->checkAcpPermission( "posting_manage_simplified_mode", return: true ) )
|
||||
{
|
||||
$message = "<p>{$message}</p><p>" . Member::loggedIn()->language()->addToStack( "enhancements__core_Iframely_embed_settings_link" ) . "</p>";
|
||||
}
|
||||
Member::loggedIn()->language()->parseOutputForDisplay( $message );
|
||||
Member::loggedIn()->language()->words['enhancements__core_Iframely_message'] = $message;
|
||||
$form->addMessage( 'enhancements__core_Iframely_message' );
|
||||
|
||||
$form->add( new YesNo( 'iframely_enabled', Settings::i()->iframely_enabled, false, ['togglesOn' => ['iframely_api_key', 'iframely_url_whitelist', 'iframely_builtin_services']] ) );
|
||||
$form->add( new Text( 'iframely_api_key', Settings::i()->iframely_api_key, false, id: 'iframely_api_key' ) );
|
||||
|
||||
$services = [];
|
||||
$enabled = [];
|
||||
foreach ( ['iframely_facebook_enabled', 'iframely_instagram_enabled'] as $serviceSetting )
|
||||
{
|
||||
if ( Settings::i()->$serviceSetting )
|
||||
{
|
||||
$enabled[] = $serviceSetting;
|
||||
}
|
||||
$services[$serviceSetting] = $serviceSetting;
|
||||
}
|
||||
$form->add( new Form\CheckboxSet( "iframely_builtin_services", $enabled, false, [
|
||||
'options' => $services
|
||||
], id: 'iframely_builtin_services' ) );
|
||||
$form->add( new Stack( 'iframely_url_whitelist', explode( ',', Settings::i()->iframely_url_whitelist ?: "" ), false, id: 'iframely_url_whitelist' ) );
|
||||
|
||||
if ( $values = $form->values() )
|
||||
{
|
||||
try
|
||||
{
|
||||
$values['iframely_url_whitelist'] = implode( ",", $values['iframely_url_whitelist'] );
|
||||
$this->_settings = array_replace( $this->_settings, $values );
|
||||
$this->testSettings();
|
||||
if ( array_key_exists( 'iframely_builtin_services', $values ) )
|
||||
{
|
||||
foreach( $services as $setting )
|
||||
{
|
||||
$values[$setting] = in_array( $setting, $values['iframely_builtin_services'] ) ? 1 : 0;
|
||||
}
|
||||
}
|
||||
unset( $values['iframely_builtin_services'] );
|
||||
Settings::i()->changeValues( $values );
|
||||
|
||||
Output::i()->inlineMessage = MemberClass::loggedIn()->language()->addToStack('saved');
|
||||
}
|
||||
catch ( LogicException $e )
|
||||
{
|
||||
$form->error = $e->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
Output::i()->sidebar['actions'] = array(
|
||||
'help' => array(
|
||||
'title' => 'help',
|
||||
'icon' => 'question-circle',
|
||||
'link' => Url::ips( 'docs/iframely' ),
|
||||
'target' => '_blank'
|
||||
),
|
||||
);
|
||||
|
||||
Output::i()->output = Theme::i()->getTemplate( 'global' )->block( 'enhancements__core_Iframely', $form );
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/Disable
|
||||
*
|
||||
* @param $enabled bool Enable/Disable
|
||||
* @return void
|
||||
* @throws LogicException
|
||||
*/
|
||||
public function toggle( bool $enabled ) : void
|
||||
{
|
||||
if ( $enabled )
|
||||
{
|
||||
$this->testSettings();
|
||||
}
|
||||
|
||||
Settings::i()->changeValues( array( 'iframely_enabled' => $enabled ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Settings
|
||||
*
|
||||
* @return void
|
||||
* @throws LogicException
|
||||
*/
|
||||
protected function testSettings() : void
|
||||
{
|
||||
/* If this is not enabled, no need to check the api key */
|
||||
if ( !@$this->_settings['iframely_enabled'] )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( empty( $this->_settings['iframely_api_key'] ) )
|
||||
{
|
||||
throw new LogicException( Member::loggedIn()->language()->get("iframely_err_no_api_key" ) );
|
||||
}
|
||||
|
||||
/* We only need to test the key if it's different from the saved value */
|
||||
if ( $this->_settings['iframely_api_key'] !== Settings::i()->iframely_api_key )
|
||||
{
|
||||
try
|
||||
{
|
||||
$response = Url::external( "https://iframe.ly/api/iframely" )
|
||||
->setQueryString([
|
||||
'key' => $this->_settings['iframely_api_key'],
|
||||
'url' => 'https://iframely.com',
|
||||
])
|
||||
->request()
|
||||
->get();
|
||||
|
||||
if ( $response->httpResponseCode == 403 )
|
||||
{
|
||||
throw new Exception();
|
||||
}
|
||||
}
|
||||
catch ( Exception )
|
||||
{
|
||||
throw new LogicException( Member::loggedIn()->language()->get( "iframely_err_invalid_api_key" ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,7 @@ namespace IPS\core\extensions\core\GroupForm;
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
|
||||
use IPS\Application;
|
||||
use IPS\Content\Hideable;
|
||||
use IPS\Extensions\GroupFormAbstract;
|
||||
use IPS\Helpers\Form;
|
||||
use IPS\Helpers\Form\CheckboxSet;
|
||||
@@ -184,7 +185,7 @@ class Content extends GroupFormAbstract
|
||||
$form->addHeader( 'group_deleting' );
|
||||
$form->add( new CheckboxSet( 'g_hide_own_posts', !$group->g_hide_own_posts ? 0 : ( $group->g_hide_own_posts == '1' ? '1' : explode( ',', $group->g_hide_own_posts ) ), FALSE, array(
|
||||
'options' => array_filter( $contentClasses, function( $class ) {
|
||||
return IPS::classUsesTrait( $class, 'IPS\Content\hideable' );
|
||||
return IPS::classUsesTrait( $class, Hideable::class );
|
||||
}, ARRAY_FILTER_USE_KEY ),
|
||||
'unlimited' => '1'
|
||||
) ) );
|
||||
|
||||
@@ -196,7 +196,7 @@ class IPTools extends ModCpAbstract
|
||||
'view' => array(
|
||||
'icon' => 'search',
|
||||
'title' => 'see_uses',
|
||||
'link' => Url::internal( 'app=core&module=modcp&controller=modcp&tab=ip_tools&ip=' ) . $row['ip'],
|
||||
'link' => Url::internal( 'app=core&module=modcp&controller=modcp&tab=ip_tools', 'front', 'modcp_ip_tools' )->setQueryString( 'ip', $row['ip'] ),
|
||||
),
|
||||
);
|
||||
};
|
||||
|
||||
@@ -75,11 +75,22 @@ class Unapproved extends ModCpAbstract
|
||||
*/
|
||||
public function getCounters() : array
|
||||
{
|
||||
$count = Request::i()->isAjax() ? $this->getApprovalQueueCount(true) : $this->getApprovalQueueCount();
|
||||
return [
|
||||
[ 'id' => 'elModCPApprovalCount', 'title' => 'modcp_approval', 'total' => $this->getApprovalQueueCount() ]
|
||||
[ 'id' => 'elModCPApprovalCount', 'title' => 'modcp_approval', 'total' => $count ]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* get unapproved counter for the ajax update
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function getCount(): void
|
||||
{
|
||||
Output::i()->json(['total' => $this->getApprovalQueueCount(true) ]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute
|
||||
*
|
||||
@@ -245,7 +256,7 @@ class Unapproved extends ModCpAbstract
|
||||
}
|
||||
|
||||
return array(
|
||||
array_merge( array( "(" . implode( " OR ", $clause ) . ")" ), $binds )
|
||||
array_merge( array( "(" . implode( " OR ", $clause ) . ")" ), $binds ),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -263,8 +274,8 @@ class Unapproved extends ModCpAbstract
|
||||
$rows = iterator_to_array(
|
||||
new ActiveRecordIterator(
|
||||
Db::i()->select( '*', 'core_approval_queue', Db::i()->in( 'approval_id', $ids ) ),
|
||||
Approval::class
|
||||
)
|
||||
Approval::class,
|
||||
),
|
||||
);
|
||||
|
||||
foreach( $rows as $row )
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace IPS\core\extensions\core\ModeratorPermissions;
|
||||
|
||||
use IPS\Extensions\ModeratorPermissionsAbstract;
|
||||
use IPS\Member;
|
||||
use IPS\Platform\Bridge;
|
||||
use IPS\Settings;
|
||||
use function defined;
|
||||
|
||||
@@ -71,7 +72,6 @@ class Content extends ModeratorPermissionsAbstract
|
||||
'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_content' => array( 'YesNo', array( 'togglesOff' => $toggles['toggle_item_moderation'] ) ),
|
||||
'can_assign_content' => array( 'YesNo', array( 'togglesOff' => $toggles['assign'] ) ),
|
||||
'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' => [
|
||||
@@ -81,6 +81,11 @@ class Content extends ModeratorPermissionsAbstract
|
||||
) ),
|
||||
'can_recognize_content_no_point_limit' => 'YesNo'
|
||||
);
|
||||
|
||||
if( Bridge::i()->featureIsEnabled( 'assignments' ) )
|
||||
{
|
||||
$return['can_assign_content'] = array( 'YesNo', array( 'togglesOff' => $toggles['assign'] ) );
|
||||
}
|
||||
|
||||
if ( Settings::i()->edit_log == 2 )
|
||||
{
|
||||
|
||||
@@ -122,7 +122,7 @@ class Editor extends ProfileStepsAbstract
|
||||
$wizards[ $step->key ] = function( $data ) use ( $member, $step ) {
|
||||
$form = new Form( 'profile_profile_fields_' . $step->id, 'profile_complete_next' );
|
||||
|
||||
$form->addHtml( $member->language()->addToStack( 'profile_step_subaction_custom_' . $step->id ) );
|
||||
$form->addHtml( Theme::i()->getTemplate( 'global', 'core', 'global' )->richText( $member->language()->addToStack( 'profile_step_subaction_custom_' . $step->id ), [ 'i-padding_3' ] ) );
|
||||
|
||||
/* Because there are no form elements, $values is an empty array - that's ok and means the form was submitted, while FALSE means it wasn't */
|
||||
if ( ( $values = $form->values() ) !== FALSE )
|
||||
|
||||
@@ -19,6 +19,7 @@ use IPS\Content\Tag;
|
||||
use IPS\Db;
|
||||
use IPS\Extensions\QueueAbstract;
|
||||
use IPS\Member;
|
||||
use IPS\Settings;
|
||||
use IPS\Task\Queue\OutOfRangeException as QueueOutOfRangeException;
|
||||
use OutOfRangeException;
|
||||
use function count;
|
||||
@@ -93,11 +94,13 @@ class UpdateTaggedItems extends QueueAbstract
|
||||
}
|
||||
|
||||
/* First we remove the old tag from the list */
|
||||
$index = array_search( $data['tag'], $currentTags );
|
||||
if( $index !== false )
|
||||
{
|
||||
unset( $currentTags[ $index ] );
|
||||
}
|
||||
foreach( $currentTags as $index => $_tag )
|
||||
{
|
||||
if( mb_strtolower( $_tag ) == mb_strtolower( $data['tag'] ) )
|
||||
{
|
||||
unset( $currentTags[ $index ] );
|
||||
}
|
||||
}
|
||||
|
||||
/* Are we renaming the tag? Put the new name in */
|
||||
if( isset( $data['new'] ) and $data['new'] )
|
||||
|
||||
@@ -48,30 +48,6 @@ class DeviceUsage extends \IPS\core\Statistics\Chart
|
||||
*/
|
||||
public function getChart( Url $url ): Chart
|
||||
{
|
||||
/* Determine minimum date */
|
||||
$minimumDate = NULL;
|
||||
|
||||
if( Settings::i()->stats_device_usage_prune )
|
||||
{
|
||||
$minimumDate = DateTime::create()->sub( new DateInterval( 'P' . Settings::i()->stats_device_usage_prune . 'D' ) );
|
||||
}
|
||||
|
||||
/* We can't retrieve any stats prior to the new tracking being implemented */
|
||||
try
|
||||
{
|
||||
$oldestLog = Db::i()->select( 'MIN(time)', 'core_statistics', array( 'type=?', 'online_users' ) )->first();
|
||||
|
||||
if( !$minimumDate OR $oldestLog < $minimumDate->getTimestamp() )
|
||||
{
|
||||
$minimumDate = DateTime::ts( $oldestLog );
|
||||
}
|
||||
}
|
||||
catch( UnderflowException $e )
|
||||
{
|
||||
/* We have nothing tracked, set minimum date to today */
|
||||
$minimumDate = DateTime::create();
|
||||
}
|
||||
|
||||
$chart = new Database( $url, 'core_statistics', 'time', '', array(
|
||||
'isStacked' => FALSE,
|
||||
'backgroundColor' => '#ffffff',
|
||||
|
||||
@@ -61,7 +61,10 @@ class EmailClicks extends \IPS\core\Statistics\Chart
|
||||
try
|
||||
{
|
||||
$oldestLog = Db::i()->select( 'MIN(time)', 'core_statistics', array( 'type=?', 'emails_sent' ) )->first();
|
||||
|
||||
if ( is_null( $oldestLog ) )
|
||||
{
|
||||
throw new UnderflowException; // If there are no rows, MIN(time) will be null
|
||||
}
|
||||
if( !$minimumDate OR $oldestLog < $minimumDate->getTimestamp() )
|
||||
{
|
||||
$minimumDate = DateTime::ts( $oldestLog );
|
||||
|
||||
@@ -45,7 +45,6 @@ class Language extends \IPS\core\Statistics\Chart
|
||||
*/
|
||||
public function getChart( Url $url ): Chart
|
||||
{
|
||||
$chart = new Chart;
|
||||
$counts = iterator_to_array( Db::i()->select( 'language, COUNT(member_id) as count', 'core_members', array( "language > ?", 0), NULL, NULL, "language" )->setKeyField( 'language' ) );
|
||||
|
||||
$chart = new Database( $url, 'core_members', 'language', '', array(
|
||||
|
||||
@@ -59,7 +59,10 @@ class OnlineUsers extends \IPS\core\Statistics\Chart
|
||||
try
|
||||
{
|
||||
$oldestLog = Db::i()->select( 'MIN(time)', 'core_statistics', array( 'type=?', 'online_users' ) )->first();
|
||||
|
||||
if ( is_null( $oldestLog ) )
|
||||
{
|
||||
throw new UnderflowException; // If there are no rows, MIN(time) will be null
|
||||
}
|
||||
if( !$minimumDate OR $oldestLog < $minimumDate->getTimestamp() )
|
||||
{
|
||||
$minimumDate = DateTime::ts( $oldestLog );
|
||||
|
||||
Reference in new issue
Block a user