Version 5.0.6
This commit is contained in:
1 parent
a3a4a9ccbd
commit
b89858b2ff
1214 files changed
+92828
-14859
No files matched your search
@@ -212,10 +212,13 @@ class Reaction extends ContentAchievementActionAbstract
|
||||
{
|
||||
$class = $exploded[0];
|
||||
$content = $class::load( $exploded[1] );
|
||||
$contentLink = Theme::i()->getTemplate( 'global', 'core', 'global' )->basicUrl( $content->url(), TRUE, $content->indefiniteArticle(), FALSE );
|
||||
|
||||
$reaction = $content->reacted( Member::load( $exploded[2] ) );
|
||||
$reactionName = $reaction->_title;
|
||||
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;
|
||||
}
|
||||
}
|
||||
catch ( Exception $e ) { }
|
||||
|
||||
|
||||
@@ -82,7 +82,7 @@ class Codemirror extends BuildAbstract
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function finish() : void
|
||||
public function finish() : void
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@@ -90,6 +90,6 @@ class GeoIP extends CommunityEnhancementsAbstract
|
||||
*/
|
||||
public function toggle( bool $enabled ) : void
|
||||
{
|
||||
Settings::i()->changeValues( array( 'ipsgeoip' => $enabled ) );
|
||||
Settings::i()->changeValues( array( 'ipsgeoip' => 0 ) );
|
||||
}
|
||||
}
|
||||
@@ -81,7 +81,7 @@ class GoogleAnalytics extends CommunityEnhancementsAbstract
|
||||
$form->add( new YesNo( 'ga_enabled', Settings::i()->ga_enabled, FALSE, array(
|
||||
'togglesOn' => [ 'ga_code' ]
|
||||
) ) );
|
||||
$form->add( new Codemirror( 'ga_code', Settings::i()->ga_code, null, array( 'height' => 150, 'codeModeAllowedLanguages' => [ 'xml' ] ), function( $val ){
|
||||
$form->add( new Codemirror( 'ga_code', Settings::i()->ga_code, null, array( 'height' => 150, 'codeModeAllowedLanguages' => [ 'html' ] ), function( $val ){
|
||||
if( empty( $val ) and Request::i()->ga_enabled_checkbox )
|
||||
{
|
||||
throw new InvalidArgumentException('form_required');
|
||||
|
||||
@@ -92,8 +92,8 @@ class GoogleTagManager extends CommunityEnhancementsAbstract
|
||||
$form->add( new YesNo( 'core_datalayer_use_gtm', Settings::i()->core_datalayer_use_gtm, FALSE ) );
|
||||
$form->add( new Text( 'core_datalayer_gtmkey', Settings::i()->core_datalayer_gtmkey, FALSE ) );
|
||||
}
|
||||
$form->add( new Codemirror( 'googletag_head_code', Settings::i()->googletag_head_code, FALSE, array( 'height' => 150, 'codeModeAllowedLanguages' => [ 'xml' ] ), NULL, NULL, NULL, 'googletag_head_code' ) );
|
||||
$form->add( new Codemirror( 'googletag_noscript_code', Settings::i()->googletag_noscript_code, FALSE, array( 'height' => 150, 'codeModeAllowedLanguages' => [ 'xml' ] ), NULL, NULL, NULL, 'googletag_noscript_code' ) );
|
||||
$form->add( new Codemirror( 'googletag_head_code', Settings::i()->googletag_head_code, FALSE, array( 'height' => 150, 'codeModeAllowedLanguages' => [ 'html' ] ), NULL, NULL, NULL, 'googletag_head_code' ) );
|
||||
$form->add( new Codemirror( 'googletag_noscript_code', Settings::i()->googletag_noscript_code, FALSE, array( 'height' => 150, 'codeModeAllowedLanguages' => [ 'html' ] ), NULL, NULL, NULL, 'googletag_noscript_code' ) );
|
||||
|
||||
if ( $form->values() )
|
||||
{
|
||||
|
||||
@@ -86,7 +86,7 @@ class Matomo extends CommunityEnhancementsAbstract
|
||||
$form = new Form;
|
||||
|
||||
$form->add( new YesNo( 'matomo_enabled', Settings::i()->matomo_enabled, FALSE, array(), $validation ) );
|
||||
$form->add( new Codemirror( 'matomo_code', Settings::i()->matomo_code, FALSE, array( 'height' => 150, 'codeModeAllowedLanguages' => [ 'xml' ] ), NULL, NULL, NULL, 'matomo_code' ) );
|
||||
$form->add( new Codemirror( 'matomo_code', Settings::i()->matomo_code, FALSE, array( 'height' => 150, 'codeModeAllowedLanguages' => [ 'html' ] ), NULL, NULL, NULL, 'matomo_code' ) );
|
||||
|
||||
if ( $form->values() )
|
||||
{
|
||||
|
||||
@@ -48,19 +48,7 @@ class LatestNews extends DashboardAbstract
|
||||
*/
|
||||
public function getBlock(): string
|
||||
{
|
||||
$ipsNews = ( isset( Store::i()->ips_news ) ) ? json_decode( Store::i()->ips_news, TRUE ) : array();
|
||||
|
||||
if( empty( $ipsNews ) or $ipsNews['time'] < ( time() - 43200 ) )
|
||||
{
|
||||
try
|
||||
{
|
||||
$this->refreshNews();
|
||||
$ipsNews = ( isset( Store::i()->ips_news ) ) ? json_decode( Store::i()->ips_news, TRUE ) : array();
|
||||
}
|
||||
catch( Exception | RuntimeException $e ) {}
|
||||
}
|
||||
|
||||
return Theme::i()->getTemplate( 'dashboard' )->ipsNews( $ipsNews['content'] ?? NULL );
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -151,23 +151,20 @@ class Attachment extends EditorMediaAbstract
|
||||
|
||||
if ( isset( static::$loadedExtensions[ $map['location_key'] ] ) )
|
||||
{
|
||||
|
||||
if( method_exists( static::$loadedExtensions[$map['location_key']], 'attachmentLookup'))
|
||||
try
|
||||
{
|
||||
try {
|
||||
$url = static::$loadedExtensions[$map['location_key']]->attachmentLookup($map['id1'], $map['id2'], $map['id3']);
|
||||
$url = static::$loadedExtensions[$map['location_key']]->attachmentLookup($map['id1'], $map['id2'], $map['id3']);
|
||||
|
||||
/* Test url() method to prevent BadMethodCallException from the template below - an attachment may be
|
||||
located within a Node class that doesn't support urls, such as CMS Blocks. */
|
||||
/* Test url() method to prevent BadMethodCallException from the template below - an attachment may be
|
||||
located within a Node class that doesn't support urls, such as CMS Blocks. */
|
||||
|
||||
if ($url instanceof Content or $url instanceof Model){
|
||||
$url->url();
|
||||
}
|
||||
|
||||
static::$locations[$attachId][] = $url;
|
||||
} catch (LogicException | BadMethodCallException $e) {
|
||||
if ($url instanceof Content or $url instanceof Model){
|
||||
$url->url();
|
||||
}
|
||||
|
||||
static::$locations[$attachId][] = $url;
|
||||
}
|
||||
catch ( LogicException | BadMethodCallException $e) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief File Storage Extension: CustomBadges
|
||||
* @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 2025
|
||||
*/
|
||||
|
||||
namespace IPS\core\extensions\core\FileStorage;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
|
||||
use IPS\Db;
|
||||
use IPS\Extensions\FileStorageAbstract;
|
||||
use IPS\File as SystemFile;
|
||||
use OutOfRangeException;
|
||||
use UnderflowException;
|
||||
use function defined;
|
||||
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* File Storage Extension: CustomBadges
|
||||
*/
|
||||
class CustomBadges extends FileStorageAbstract
|
||||
{
|
||||
/**
|
||||
* Count stored files
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function count(): int
|
||||
{
|
||||
return (int) Db::i()->select( "count(*)", 'core_custom_badges' )->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
|
||||
*/
|
||||
public function move( int $offset, int $storageConfiguration, int $oldConfiguration=NULL ) : void
|
||||
{
|
||||
$row = Db::i()->select( '*', 'core_custom_badges', null, 'id', [ $offset, 1 ] )->first();
|
||||
try
|
||||
{
|
||||
$file = SystemFile::get( $oldConfiguration ?: 'core_CustomBadges', $row['file'] )->move( $storageConfiguration );
|
||||
if( (string) $file != $row['file'] )
|
||||
{
|
||||
Db::i()->update( 'core_custom_badges', [ 'file' => (string) $file ], [ 'id=?', $row['id'] ] );
|
||||
}
|
||||
}
|
||||
catch( OutOfRangeException ){}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a file is valid
|
||||
*
|
||||
* @param SystemFile|string $file The file path to check
|
||||
* @return bool
|
||||
*/
|
||||
public function isValidFile( SystemFile|string $file ): bool
|
||||
{
|
||||
return (bool) Db::i()->select( 'count(*)', 'core_custom_badges', [ 'file=?', (string) $file ] )->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all stored files
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function delete() : void
|
||||
{
|
||||
foreach( Db::i()->select( '*', 'core_custom_badges' ) as $row )
|
||||
{
|
||||
try
|
||||
{
|
||||
SystemFile::get( 'core_CustomBadges', $row['file'] )->delete();
|
||||
}
|
||||
catch( OutOfRangeException ){}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,7 @@ use IPS\Helpers\Form\Translatable;
|
||||
use IPS\Http\Url;
|
||||
use IPS\Lang;
|
||||
use IPS\Member;
|
||||
use OutOfRangeException;
|
||||
use function defined;
|
||||
use function json_decode;
|
||||
|
||||
@@ -158,14 +159,12 @@ class Menu extends FrontNavigationAbstract
|
||||
{
|
||||
foreach ( $frontNavigation[ $this->id ] as $item )
|
||||
{
|
||||
if ( Application::appIsEnabled( $item['app'] ) )
|
||||
try
|
||||
{
|
||||
$class = 'IPS\\' . $item['app'] . '\extensions\core\FrontNavigation\\' . $item['extension'];
|
||||
if ( class_exists( $class ) )
|
||||
{
|
||||
$this->children[ $item['id'] ] = new $class( json_decode( $item['config'], TRUE ), $item['id'], $item['permissions'], $item['menu_types'], json_decode( (string) $item['icon'], TRUE ) );
|
||||
}
|
||||
$class = Application::getExtensionClass( $item['app'], 'FrontNavigation', $item['extension'] );
|
||||
$this->children[ $item['id'] ] = new $class( json_decode( $item['config'], TRUE ), $item['id'], $item['permissions'], $item['menu_types'], json_decode( (string) $item['icon'], TRUE ) );
|
||||
}
|
||||
catch( OutOfRangeException ){}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ use IPS\Http\Url;
|
||||
use IPS\Member;
|
||||
use IPS\Request;
|
||||
use OutOfRangeException;
|
||||
use function class_exists;
|
||||
use function count;
|
||||
use function defined;
|
||||
use function is_object;
|
||||
@@ -59,7 +60,7 @@ class Node extends FrontNavigationAbstract
|
||||
{
|
||||
parent::__construct( $configuration, $id, $permissions, $menuTypes, $icon );
|
||||
|
||||
if ( count( $configuration ) and isset( $configuration['nodeClass'] ) and ! empty( $configuration['id'] ) )
|
||||
if ( count( $configuration ) and isset( $configuration['nodeClass'] ) and class_exists( $configuration['nodeClass'] ) and ! empty( $configuration['id'] ) )
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
@@ -26,10 +26,14 @@ use IPS\Member;
|
||||
use IPS\Member\Group;
|
||||
use IPS\Settings;
|
||||
use IPS\Theme;
|
||||
use function array_filter;
|
||||
use function array_merge;
|
||||
use function count;
|
||||
use function defined;
|
||||
use function explode;
|
||||
use function intval;
|
||||
use function is_array;
|
||||
use const ARRAY_FILTER_USE_KEY;
|
||||
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
@@ -204,8 +208,16 @@ class Content extends GroupFormAbstract
|
||||
/* Moderation */
|
||||
$form->addHeader( 'group_moderation' );
|
||||
|
||||
$form->add( new CheckboxSet( 'g_can_report', !$group->g_can_report ? 0 : ( $group->g_can_report == '1' ? '1' : explode( ',', $group->g_can_report ) ), FALSE, array(
|
||||
'options' => array_filter( array_merge( array( 'IPS\core\Messenger\Message' => 'personal_conversation_pl' ), $contentClasses ), function( $class ) {
|
||||
return IPS::classUsesTrait( $class, 'IPS\Content\Reportable' );
|
||||
}, ARRAY_FILTER_USE_KEY ),
|
||||
'unlimited' => '1'
|
||||
) ) );
|
||||
|
||||
if( $group->g_id != Settings::i()->guest_group )
|
||||
{
|
||||
$form->add( new YesNo( 'gbw_can_mark_helpful', $group->g_bitoptions['gbw_can_mark_helpful'] ) );
|
||||
$form->add( new YesNo( 'gbw_immune_auto_mod', $group->g_bitoptions['gbw_immune_auto_mod'] ) );
|
||||
$form->add( new 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 ) {
|
||||
@@ -215,12 +227,6 @@ class Content extends GroupFormAbstract
|
||||
) ) );
|
||||
}
|
||||
|
||||
$form->add( new CheckboxSet( 'g_can_report', !$group->g_can_report ? 0 : ( $group->g_can_report == '1' ? '1' : explode( ',', $group->g_can_report ) ), FALSE, array(
|
||||
'options' => array_filter( array_merge( array( 'IPS\core\Messenger\Message' => 'personal_conversation_pl' ), $contentClasses ), function( $class ) {
|
||||
return IPS::classUsesTrait( $class, 'IPS\Content\Reportable' );
|
||||
}, ARRAY_FILTER_USE_KEY ),
|
||||
'unlimited' => '1'
|
||||
) ) );
|
||||
$form->add( new YesNo( 'g_avoid_flood', $group->g_avoid_flood ) );
|
||||
$form->add( new YesNo( 'g_avoid_q', $group->g_avoid_q, FALSE, array( 'togglesOff' => array( 'g_mod_preview' ), 'toggleValue' => FALSE ) ) );
|
||||
$form->add( new YesNo( 'g_mod_preview', $group->g_mod_preview, FALSE, array( 'togglesOn' => array( 'g_mod_post_unit' ) ), NULL, NULL, NULL, 'g_mod_preview' ) );
|
||||
@@ -314,7 +320,7 @@ class Content extends GroupFormAbstract
|
||||
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' );
|
||||
$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', 'gbw_can_mark_helpful' );
|
||||
|
||||
foreach ( $bwKeys as $k )
|
||||
{
|
||||
|
||||
@@ -222,7 +222,7 @@ class GroupSettings extends GroupFormAbstract
|
||||
if( Settings::i()->signatures_enabled AND $group->g_id != Settings::i()->guest_group )
|
||||
{
|
||||
$form->addHeader( 'group_signatures' );
|
||||
$signatureLimits = ( $group->g_id ) ? explode( ':', $group->g_signature_limits ) : array( 0, '', '', '', '', '' );
|
||||
$signatureLimits = ( $group->g_id and $group->g_signature_limits ) ? explode( ':', $group->g_signature_limits ) : array( 0, '', '', '', '', '' );
|
||||
$form->add( new YesNo( 'g_use_signatures', !$signatureLimits[0], FALSE, array( 'togglesOn' => array( 'g_signature_limit', 'g_sig_max_images', 'g_sig_max_image_size', 'g_sig_max_urls', 'g_sig_max_lines' ) ), NULL, NULL, NULL, 'g_use_signatures' ) );
|
||||
$form->add( new Custom( 'g_signature_limit', array( $group->g_sig_unit, $group->g_bitoptions['gbw_sig_unit_type'] ), FALSE, array( 'getHtml' => function( $element )
|
||||
{
|
||||
|
||||
@@ -129,12 +129,13 @@ class Content extends ExtensionGenerator
|
||||
try
|
||||
{
|
||||
$comment = $class::load( $data[ $class::$databasePrefix . $class::$databaseColumnId ] );
|
||||
return Theme::i()->getTemplate( 'global', 'core', 'global' )->basicUrl( $comment->url(), TRUE, $comment->item()->mapped('title') );
|
||||
}
|
||||
catch ( OutOfRangeException $e )
|
||||
{
|
||||
return '';
|
||||
if( $comment->canView() )
|
||||
{
|
||||
return Theme::i()->getTemplate( 'global', 'core', 'global' )->basicUrl( $comment->url(), TRUE, $comment->item()->mapped('title') );
|
||||
}
|
||||
}
|
||||
catch ( OutOfRangeException $e ){}
|
||||
return Member::loggedIn()->language()->addToStack( 'ipaddress_no_permission' );
|
||||
}
|
||||
);
|
||||
|
||||
@@ -171,7 +172,16 @@ class Content extends ExtensionGenerator
|
||||
}
|
||||
}
|
||||
|
||||
return Theme::i()->getTemplate( 'global', 'core', 'global' )->basicUrl( $class::load( $data[ $class::$databasePrefix . $class::$databaseColumnId ] )->url(), TRUE, $val );
|
||||
try
|
||||
{
|
||||
$item = $class::load( $data[ $class::$databasePrefix . $class::$databaseColumnId ] );
|
||||
if( $item->canView() )
|
||||
{
|
||||
return Theme::i()->getTemplate( 'global', 'core', 'global' )->basicUrl( $item->url(), TRUE, $val );
|
||||
}
|
||||
}
|
||||
catch( OutOfRangeException ){}
|
||||
return Member::loggedIn()->language()->addToStack( 'ipaddress_no_permission' );
|
||||
},
|
||||
);
|
||||
if( isset( $class::$databaseColumnMap['container'] ) )
|
||||
@@ -180,7 +190,11 @@ class Content extends ExtensionGenerator
|
||||
{
|
||||
$nodeClass = $class::$containerNodeClass;
|
||||
$node = $nodeClass::load( $val );
|
||||
return Theme::i()->getTemplate( 'global', 'core', 'global' )->basicUrl( $node->url(), TRUE, $node->_title );
|
||||
if( $node->canView() )
|
||||
{
|
||||
return Theme::i()->getTemplate( 'global', 'core', 'global' )->basicUrl( $node->url(), TRUE, $node->_title );
|
||||
}
|
||||
return Member::loggedIn()->language()->addToStack( 'ipaddress_no_permission' );
|
||||
};
|
||||
}
|
||||
|
||||
@@ -243,5 +257,36 @@ class Content extends ExtensionGenerator
|
||||
}
|
||||
|
||||
return Db::i()->select( "{$class::$databasePrefix}{$class::$databaseColumnMap['ip_address']} AS ip, count(*) AS count, MIN({$class::$databasePrefix}{$class::$databaseColumnMap['date']}) AS first, MAX({$class::$databasePrefix}{$class::$databaseColumnMap['date']}) AS last", $class::$databaseTable, array( "{$class::$databasePrefix}{$class::$databaseColumnMap['author']}=?", $member->member_id ), NULL, NULL, "{$class::$databasePrefix}{$class::$databaseColumnMap['ip_address']}" )->setKeyField( 'ip' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the logged IP address
|
||||
*
|
||||
* @param int $time
|
||||
* @return void
|
||||
*/
|
||||
public function pruneIpAddresses( int $time ) : void
|
||||
{
|
||||
/* @var ContentClass $class */
|
||||
$class = $this->class;
|
||||
$classes = [ $class ];
|
||||
if( isset( $class::$commentClass ) )
|
||||
{
|
||||
$classes[] = $class::$commentClass;
|
||||
}
|
||||
if( isset( $class::$reviewClass ) )
|
||||
{
|
||||
$classes[] = $class::$reviewClass;
|
||||
}
|
||||
|
||||
foreach( $classes as $class )
|
||||
{
|
||||
if( isset( $class::$databaseColumnMap['ip_address'] ) and isset( $class::$databaseColumnMap['date'] ) )
|
||||
{
|
||||
Db::i()->update( $class::$databaseTable, [ $class::$databasePrefix . $class::$databaseColumnMap['ip_address'] => '' ], [
|
||||
$class::$databasePrefix . $class::$databaseColumnMap['ip_address'] . ' != ? and ' . $class::$databasePrefix . $class::$databaseColumnMap['date'] . ' < ?', '', $time
|
||||
] );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,8 @@ namespace IPS\core\extensions\core\MemberACPProfileBlocks;
|
||||
|
||||
use IPS\Application;
|
||||
use IPS\core\MemberACPProfile\Block;
|
||||
use IPS\Helpers\Menu;
|
||||
use IPS\Helpers\Menu\Link;
|
||||
use IPS\Http\Url;
|
||||
use IPS\Login;
|
||||
use IPS\Login\Handler;
|
||||
@@ -77,44 +79,23 @@ class BasicInformation extends Block
|
||||
$canChangePassword = FALSE;
|
||||
}
|
||||
|
||||
$accountActions = array();
|
||||
$accountActions = new Menu( 'account_actions', css: 'ipsButton ipsButton--primary ipsButton--large' );
|
||||
if ( Member::loggedIn()->member_id != $this->member->member_id AND Member::loggedIn()->hasAcpRestriction( 'core', 'members', 'member_login' ) AND !$this->member->isBanned() )
|
||||
{
|
||||
$accountActions[] = array(
|
||||
'title' => Member::loggedIn()->language()->addToStack( 'login_as_x', FALSE, array( 'sprintf' => array( $this->member->name ) ) ),
|
||||
'icon' => 'key',
|
||||
'link' => Url::internal( "app=core&module=members&controller=members&do=login&id={$this->member->member_id}" )->csrf(),
|
||||
'class' => '',
|
||||
'target' => '_blank'
|
||||
);
|
||||
$accountActions->add( new Link( Url::internal( "app=core&module=members&controller=members&do=login&id={$this->member->member_id}" )->csrf(), Member::loggedIn()->language()->addToStack( 'login_as_x', false, [ 'sprintf' => [ $this->member->name ] ] ), dataAttributes: [ 'target' => '_blank' ], icon: 'fa-solid fa-key' ) );
|
||||
}
|
||||
if ( Member::loggedIn()->hasAcpRestriction( 'core', 'members', 'members_merge' ) )
|
||||
{
|
||||
$accountActions[] = array(
|
||||
'title' => 'merge_with_another_account',
|
||||
'icon' => 'level-up',
|
||||
'link' => Url::internal( "app=core&module=members&controller=members&do=merge&id={$this->member->member_id}" ),
|
||||
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => Member::loggedIn()->language()->addToStack('merge') )
|
||||
);
|
||||
$accountActions->add( new Link( Url::internal( "app=core&module=members&controller=members&do=merge&id={$this->member->member_id}" ), 'merge_with_another_account', dataAttributes: [ 'data-ipsDialog-title' => Member::loggedIn()->language()->addToStack( 'merge' ) ], opensDialog: true, icon: 'fa-solid fa-level-up' ) );
|
||||
}
|
||||
if ( Member::loggedIn()->hasAcpRestriction( 'core', 'members', 'member_delete' ) and ( Member::loggedIn()->hasAcpRestriction( 'core', 'members', 'member_delete_admin' ) or !$this->member->isAdmin() ) and $this->member->member_id != Member::loggedIn()->member_id )
|
||||
{
|
||||
$accountActions[] = array(
|
||||
'title' => 'delete',
|
||||
'icon' => 'times-circle',
|
||||
'link' => Url::internal( "app=core&module=members&controller=members&do=delete&id={$this->member->member_id}" ),
|
||||
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => Member::loggedIn()->language()->addToStack('delete') ),
|
||||
);
|
||||
$accountActions->add( new Link( Url::internal( "app=core&module=members&controller=members&do=delete&id={$this->member->member_id}" ), 'delete', dataAttributes: [ 'data-ipsDialog-title' => Member::loggedIn()->language()->addToStack( 'delete' ) ], opensDialog: true, icon: 'fa-solid fa-times-circle' ) );
|
||||
}
|
||||
|
||||
if ( Member::loggedIn()->hasAcpRestriction( 'core', 'members', 'member_export_pi' ) )
|
||||
{
|
||||
$accountActions[] = array(
|
||||
'title' => 'member_export_pi_title',
|
||||
'icon' => 'download',
|
||||
'link' => Url::internal( "app=core&module=members&controller=members&do=exportPersonalInfo&id={$this->member->member_id}" ),
|
||||
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => Member::loggedIn()->language()->addToStack('member_export_pi_title') )
|
||||
);
|
||||
$accountActions->add( new Link( Url::internal( "app=core&module=members&controller=members&do=exportPersonalInfo&id={$this->member->member_id}" ), 'member_export_pi_title', dataAttributes: [ 'data-ipsDialog-title' => Member::loggedIn()->language()->addToStack( 'member_export_pi_title' ) ], opensDialog: true, icon: 'fa-solid fa-download' ) );
|
||||
}
|
||||
|
||||
/* Data Layer PII Option */
|
||||
@@ -126,19 +107,34 @@ class BasicInformation extends Block
|
||||
)
|
||||
{
|
||||
$enabled = !$this->member->members_bitoptions['datalayer_pii_optout'];
|
||||
$accountActions[] = array(
|
||||
'title' => $enabled ? 'datalayer_omit_member_pii' : 'datalayer_collect_member_pii',
|
||||
'icon' => 'id-card',
|
||||
'link' => Url::internal( "app=core&module=members&controller=members&do=toggleDataLayerPii&id={$this->member->member_id}" ),
|
||||
);
|
||||
$accountActions->add( new Link( Url::internal( "app=core&module=members&controller=members&do=toggleDataLayerPii&id={$this->member->member_id}" ), ( $enabled ? 'datalayer_omit_member_pii' : 'datalayer_collect_member_pii' ), icon: 'fa-solid fa-id-card' ) );
|
||||
}
|
||||
|
||||
if( Member::loggedIn()->hasAcpRestriction( 'core', 'members', 'member_edit' ) )
|
||||
{
|
||||
$accountActions->add( new Link( $this->member->acpUrl()->setQueryString( 'do', 'edit' ), 'edit_member_account', dataAttributes: [ 'data-ipsDialog-title' => Member::loggedIn()->language()->addToStack( 'edit_member_account' ) ], opensDialog: true, icon: 'fa-solid fa-sliders' ) );
|
||||
}
|
||||
|
||||
if( $canChangePassword )
|
||||
{
|
||||
$accountActions->add( new Link( $this->member->acpUrl()->setQueryString( 'do', 'password' ), ( $hasPassword ? 'edit_password' : 'set_password' ), dataAttributes: [ 'data-ipsDialog-title' => Member::loggedIn()->language()->addToStack( 'edit_password' ) ], opensDialog: true, icon: 'fa-solid fa-lock' ) );
|
||||
}
|
||||
|
||||
/* Extensions */
|
||||
foreach( Application::allExtensions( 'core', 'UserMenu' ) as $ext )
|
||||
{
|
||||
foreach( $ext->acpAccountActionsMenu( $this->member ) as $element )
|
||||
{
|
||||
$accountActions->add( $element );
|
||||
}
|
||||
}
|
||||
|
||||
$activeSubscription = FALSE;
|
||||
if ( Application::appIsEnabled('nexus') and Settings::i()->nexus_subs_enabled ) // I know... this should really be a hook... I won't tell if you won't
|
||||
{
|
||||
$activeSubscription = Subscription::loadByMember( $this->member, true );
|
||||
}
|
||||
|
||||
return (string) Theme::i()->getTemplate('memberprofile')->basicInformation( $this->member, $canChangePassword, $hasPassword, $activeIntegrations, $accountActions, $activeSubscription );
|
||||
return (string) Theme::i()->getTemplate('memberprofile')->basicInformation( $this->member, $activeIntegrations, $accountActions, $activeSubscription );
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,7 @@ use IPS\Application;
|
||||
use IPS\core\MemberACPProfile\TabbedBlock;
|
||||
use IPS\Member;
|
||||
use IPS\Theme;
|
||||
use OutOfRangeException;
|
||||
use function defined;
|
||||
use function in_array;
|
||||
|
||||
@@ -196,14 +197,14 @@ class ContentStatistics extends TabbedBlock
|
||||
else
|
||||
{
|
||||
$exploded = explode( '_', $tab );
|
||||
$class = 'IPS\\' . $exploded[0] . '\\extensions\\core\\MemberACPProfileContentTab\\' . $exploded[1];
|
||||
|
||||
if ( class_exists( $class ) )
|
||||
try
|
||||
{
|
||||
$class = Application::getExtensionClass( $exploded[0], 'MemberACPProfileContentTab', $exploded[1] );
|
||||
$ext = new $class( $this->member );
|
||||
return $ext->output();
|
||||
}
|
||||
|
||||
catch( OutOfRangeException ){}
|
||||
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,6 +80,27 @@ class Reports extends Controller
|
||||
{
|
||||
return 'content';
|
||||
}
|
||||
|
||||
/**
|
||||
* Any counters that will be displayed in the ModCP Header.
|
||||
* This should return an array of counters, where each item contains
|
||||
* title (a language string)
|
||||
* total
|
||||
* id (optional element ID)
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getCounters() : array
|
||||
{
|
||||
if( $this->getTab() )
|
||||
{
|
||||
return [
|
||||
[ 'id' => 'elModCPReportCount', 'title' => 'active_reports', 'total' => Member::loggedIn()->reportCount( TRUE ) ]
|
||||
];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute
|
||||
@@ -382,8 +403,18 @@ class Reports extends Controller
|
||||
}
|
||||
$form->add( new Select( 'modal_author_notification', null, null, [ 'options' => $notifications ] ) );
|
||||
|
||||
try
|
||||
{
|
||||
$class = $report->class;
|
||||
$thing = $class::load( $report->content_id );
|
||||
}
|
||||
catch( \OutOfRangeException $e )
|
||||
{
|
||||
Output::i()->error( 'node_error', '2S319/2', 404 );
|
||||
}
|
||||
|
||||
/* Fix the language string */
|
||||
Member::loggedIn()->language()->words['modal_author_notification'] = Member::loggedIn()->language()->addToStack('modal_author__notification', null, [ 'sprintf' => [ $report->author()->name ] ] );
|
||||
Member::loggedIn()->language()->words['modal_author_notification'] = Member::loggedIn()->language()->addToStack('modal_author__notification', null, [ 'sprintf' => [ $thing->author()->name ] ] );
|
||||
if ( $values = $form->values() )
|
||||
{
|
||||
Session::i()->csrfCheck();
|
||||
|
||||
@@ -64,6 +64,22 @@ class Unapproved extends ModCpAbstract
|
||||
return 'content';
|
||||
}
|
||||
|
||||
/**
|
||||
* Any counters that will be displayed in the ModCP Header.
|
||||
* This should return an array of counters, where each item contains
|
||||
* title (a language string)
|
||||
* total
|
||||
* id (optional element ID)
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getCounters() : array
|
||||
{
|
||||
return [
|
||||
[ 'id' => 'elModCPApprovalCount', 'title' => 'modcp_approval', 'total' => $this->getApprovalQueueCount() ]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute
|
||||
*
|
||||
|
||||
@@ -100,6 +100,7 @@ class Content extends ModeratorPermissionsAbstract
|
||||
$return['can_manage_alerts'] = 'YesNo';
|
||||
|
||||
$return['can_pin_tagged'] = 'YesNo';
|
||||
$return['can_edit_tags'] = 'YesNo';
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
@@ -180,15 +180,15 @@ class ContentGenerator extends ExtensionGenerator
|
||||
/* Return */
|
||||
return $return;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* After change
|
||||
*
|
||||
* @param array $moderator The moderator
|
||||
* @param array $changed Values that were changed
|
||||
* @param array|string $changed Values that were changed
|
||||
* @return void
|
||||
*/
|
||||
public function onChange( array $moderator, array $changed ) : void
|
||||
public function onChange( array $moderator, array|string $changed ) : void
|
||||
{
|
||||
/* @var Item $class */
|
||||
$class = $this->class;
|
||||
|
||||
@@ -16,6 +16,7 @@ use IPS\Application\Module;
|
||||
use IPS\Content;
|
||||
use IPS\Content\Comment;
|
||||
use IPS\Content\Item;
|
||||
use IPS\Content\ReadMarkers;
|
||||
use IPS\core\Reports\Report;
|
||||
use IPS\core\Reports\Types;
|
||||
use IPS\core\Warnings\Warning;
|
||||
@@ -565,22 +566,26 @@ class Moderation extends NotificationsAbstract
|
||||
}
|
||||
|
||||
$item = $notification->item;
|
||||
|
||||
if ( $item instanceof Comment )
|
||||
{
|
||||
$title = $item->item()->mapped('title');
|
||||
$unread = false;
|
||||
|
||||
/* Unread? */
|
||||
$unread = false;
|
||||
if ( $item->item()->timeLastRead() instanceof DateTime )
|
||||
{
|
||||
$unread =( $item->item()->timeLastRead()->getTimestamp() < $notification->updated_time->getTimestamp() );
|
||||
}
|
||||
}
|
||||
else
|
||||
if( IPS::classUsesTrait( $item, ReadMarkers::class ) )
|
||||
{
|
||||
$title = $item->mapped('title');
|
||||
$unread = (bool) ( $item->unread() );
|
||||
if ( $item instanceof Comment )
|
||||
{
|
||||
$title = $item->item()->mapped('title');
|
||||
|
||||
/* Unread? */
|
||||
|
||||
if ( $item->item()->timeLastRead() instanceof DateTime )
|
||||
{
|
||||
$unread =( $item->item()->timeLastRead()->getTimestamp() < $notification->updated_time->getTimestamp() );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$title = $item->mapped('title');
|
||||
$unread = (bool) ( $item->unread() );
|
||||
}
|
||||
}
|
||||
|
||||
$name = ( IPS::classUsesTrait( $item, 'IPS\Content\Anonymous' ) AND $item->isAnonymous() ) ? Member::loggedIn()->language()->addToStack( 'post_anonymously_placename' ) : $item->author()->name;
|
||||
|
||||
@@ -283,6 +283,12 @@ class MyStuff extends NotificationsAbstract
|
||||
}
|
||||
|
||||
$item = ( $comment instanceof Item ) ? $comment : $comment->item();
|
||||
|
||||
if( !\IPS\IPS::classUsesTrait( $item, 'IPS\Content\Reactable' ) )
|
||||
{
|
||||
throw new OutOfRangeException;
|
||||
}
|
||||
|
||||
$idColumn = $comment::$databaseColumnId;
|
||||
|
||||
$between = time();
|
||||
@@ -358,6 +364,10 @@ class MyStuff extends NotificationsAbstract
|
||||
}
|
||||
|
||||
$item = ( $comment instanceof Item ) ? $comment : $comment->item();
|
||||
if( !\IPS\IPS::classUsesTrait( $item, 'IPS\Content\Reactable' ) )
|
||||
{
|
||||
throw new OutOfRangeException;
|
||||
}
|
||||
$idColumn = $comment::$databaseColumnId;
|
||||
|
||||
$between = time();
|
||||
@@ -417,6 +427,10 @@ class MyStuff extends NotificationsAbstract
|
||||
public static function parse_mobile_new_likes( Lang $language, Content $content, Member $liker ) : array
|
||||
{
|
||||
$item = ( $content instanceof Item ) ? $content : $content->item();
|
||||
if( !\IPS\IPS::classUsesTrait( $item, 'IPS\Content\Reactable' ) )
|
||||
{
|
||||
throw new OutOfRangeException;
|
||||
}
|
||||
$idField = $item::$databaseColumnId;
|
||||
$lang = Reaction::isLikeMode() ? 'notification__new_likes' : 'notification__new_react';
|
||||
|
||||
|
||||
@@ -53,14 +53,16 @@ class MoveFiles extends QueueAbstract
|
||||
public function run( array &$data, int $offset ): int
|
||||
{
|
||||
$exploded = explode( '_', $data['storageExtension'] );
|
||||
$classname = "IPS\\{$exploded[2]}\\extensions\\core\\FileStorage\\{$exploded[3]}";
|
||||
$offset = $offset ?: 0;
|
||||
|
||||
if ( !class_exists( $classname ) or !Application::appIsEnabled( $exploded[2] ) )
|
||||
try
|
||||
{
|
||||
$classname = Application::getExtensionClass( $exploded[2], 'FileStorage', $exploded[3] );
|
||||
}
|
||||
catch( OutOfRangeException )
|
||||
{
|
||||
throw new \IPS\Task\Queue\OutOfRangeException;
|
||||
}
|
||||
|
||||
|
||||
$offset = $offset ?: 0;
|
||||
$extension = new $classname;
|
||||
|
||||
for ( $i = 0; $i < $this->batch; $i++ )
|
||||
|
||||
@@ -51,6 +51,12 @@ class RebuildReputationLeaderboard extends QueueAbstract
|
||||
try
|
||||
{
|
||||
$date = Db::i()->select( 'MIN(rep_date)', 'core_reputation_index' )->first();
|
||||
|
||||
if( empty( $date ) )
|
||||
{
|
||||
throw new OutOfRangeException;
|
||||
}
|
||||
|
||||
$data = array();
|
||||
|
||||
/* We work a day in arrears */
|
||||
|
||||
@@ -15,6 +15,7 @@ use IPS\Content;
|
||||
use IPS\Content\Item;
|
||||
use IPS\Content\Search\Index;
|
||||
use IPS\Content\Search\SearchContent;
|
||||
use IPS\Content\Tag;
|
||||
use IPS\Db;
|
||||
use IPS\Extensions\QueueAbstract;
|
||||
use IPS\Member;
|
||||
@@ -152,8 +153,21 @@ class UpdateTaggedItems extends QueueAbstract
|
||||
*/
|
||||
public function getProgress( array $data, int $offset ): array
|
||||
{
|
||||
if( isset( $data['delete'] ) )
|
||||
{
|
||||
$title = 'queue_deleting_tag';
|
||||
}
|
||||
elseif( isset( $data['merge'] ) )
|
||||
{
|
||||
$title = 'queue_merging_tag';
|
||||
}
|
||||
else
|
||||
{
|
||||
$title = 'queue_renaming_tag';
|
||||
}
|
||||
|
||||
return [
|
||||
'text' => Member::loggedIn()->language()->addToStack( ( isset( $data['delete'] ) ? 'queue_deleting_tag' : 'queue_renaming_tag' ), true, [ 'sprintf' => [ $data['tag'] ] ] ),
|
||||
'text' => Member::loggedIn()->language()->addToStack( $title, true, [ 'sprintf' => [ $data['tag'] ] ] ),
|
||||
'complete' => ( $data['processed'] ? round( 100 / $data['count'] * $data['processed'], 2 ) : 0 )
|
||||
];
|
||||
}
|
||||
@@ -167,6 +181,11 @@ class UpdateTaggedItems extends QueueAbstract
|
||||
*/
|
||||
public function postComplete( array $data, bool $processed = TRUE ) : void
|
||||
{
|
||||
|
||||
/* If this was a merge, delete the tag when we're done */
|
||||
$queueData = json_decode( $data['data'], true );
|
||||
if( isset( $queueData['merge'] ) )
|
||||
{
|
||||
Tag::load( $queueData['tag'], 'tag_text' )->delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user