Version 4.7.6

This commit is contained in:
Neo committed 2025-12-19 16:05:19 -08:00
1 parent 8ba7d43898
commit 7b7404e741
1085 files changed
+30590 -7837

No files matched your search

@@ -180,18 +180,23 @@ class _Recognize extends \IPS\Patterns\ActiveRecord
try
{
$author = \IPS\Member::load( $this->member_id );
if ( $this->points )
{
/* Wade does it this way so I guess there's a reason. And let the reason be love */
\IPS\Db::i()->update( 'core_members', "achievements_points = achievements_points - " . \intval( $this->points ), [ 'member_id=?', $this->member_id ] );
\IPS\Db::i()->delete( 'core_points_log', [ 'recognize=?', $this->id ] );
}
if ( $this->badge )
{
\IPS\Db::i()->delete( 'core_member_badges', [ 'member_id=? and recognize_id=?', $this->member_id, $this->id ] );
\IPS\Db::i()->delete( 'core_member_badges', [ 'member=? and recognize=?', $this->member_id, $this->id ] );
}
/* Remove notifications */
\IPS\Db::i()->delete( 'core_notifications', array( 'item_class=? and notification_key=? and item_id=? and extra=?', 'IPS\Member', 'new_recognize', $this->member_id, '[' . $this->id . ']' ) );
}
catch( \Exception $e ) { }
catch( \Exception $e ) {}
parent::delete();
}
+97 -8
View File
@@ -109,7 +109,7 @@ class _Alert extends \IPS\Content\Item
$form = new \IPS\Helpers\Form( NULL, 'save' );
$form->class = 'ipsForm_vertical';
if ( \IPS\Member::loggedIn()->members_disable_pm == 2 )
if ( ! \IPS\Member::loggedIn()->canUseMessenger() )
{
$form->addMessage( 'alert_you_cannot_receive_messages', 'ipsMessage ipsMessage_info' );
}
@@ -157,11 +157,38 @@ class _Alert extends \IPS\Content\Item
{
throw new \InvalidArgumentException( 'alert_no_recipient_selected' );
}
if ( ! $member->canUseMessenger() and \IPS\Request::i()->alert_reply == 2 )
{
throw new \InvalidArgumentException( \IPS\Member::loggedIn()->language()->addToStack( 'alert_member_pm_disabled', NULL, [ 'sprintf' => $member->name ] ) );
}
}
},
NULL, NULL, 'alert_recipient_user' ) );
$form->add( new \IPS\Helpers\Form\CheckboxSet( 'alert_recipient_group', ( $alert and $alert->recipient_group ) ? explode( ',', $alert->recipient_group ) : array(), FALSE, array( 'options' => $groups, 'multiple' => TRUE ), NULL, NULL, NULL, 'alert_recipient_group' ) );
$form->add( new \IPS\Helpers\Form\CheckboxSet( 'alert_recipient_group', ( $alert and $alert->recipient_group ) ? explode( ',', $alert->recipient_group ) : array(), FALSE, array( 'options' => $groups, 'multiple' => TRUE ), function( $groups )
{
if ( \IPS\Request::i()->alert_reply == 2 )
{
$module = \IPS\Application\Module::get( 'core', 'messaging' );
$names = [];
foreach( $groups as $group )
{
$group = \IPS\Member\Group::load( $group );
if ( ! ( \IPS\Application::load( $module->application )->canAccess( $group ) and ( $module->protected or $module->can( 'view', $group ) ) ) )
{
$names[] = $group->name;
}
}
if ( \count( $names ) )
{
throw new \InvalidArgumentException( \IPS\Member::loggedIn()->language()->addToStack( 'alert_member_group_pm_disabled', NULL, [ 'htmlsprintf' => \IPS\Member::loggedIn()->language()->formatList( $names ) ] ) );
}
}
},
NULL, NULL, 'alert_recipient_group' ) );
$form->add( new \IPS\Helpers\Form\Radio( 'alert_show_to', ( $alert and $alert->show_to ) ? $alert->show_to : 'all', FALSE, [
'options' => [
'all' => 'alert_show_to_all',
@@ -170,10 +197,11 @@ class _Alert extends \IPS\Content\Item
], NULL, NULL, NULL, 'alert_show_to' ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'alert_anonymous', ( $alert and $alert->anonymous ) ? TRUE : FALSE, TRUE, array( 'togglesOff' => array( 'alert_reply') ) ) );
$form->add( new \IPS\Helpers\Form\Radio( 'alert_reply', $alert ? $alert->reply : 0, TRUE, array( 'disabled' => (bool) \IPS\Member::loggedIn()->members_disable_pm, 'options' => array( '0' => 'alert_no_reply', '1' => 'alert_can_reply', '2' => 'alert_must_reply' ) ), NULL, NULL, NULL, 'alert_reply' ) );
if ( \IPS\Member::loggedIn()->members_disable_pm != 2 )
if ( \IPS\Member::loggedIn()->members_disable_pm )
{
$form->add( new \IPS\Helpers\Form\Radio( 'alert_reply', $alert ? $alert->reply : 0, TRUE, array( 'options' => array( '0' => 'alert_no_reply', '1' => 'alert_can_reply', '2' => 'alert_must_reply' ) ), NULL, NULL, NULL, 'alert_reply' ) );
\IPS\Member::loggedIn()->language()->words['alert_reply_desc'] = \IPS\Member::loggedIn()->language()->get('alert_reply__nopm_desc');
}
return $form;
@@ -191,7 +219,7 @@ class _Alert extends \IPS\Content\Item
\IPS\Data\Store::i()->alerts = iterator_to_array( \IPS\Db::i()->select( '*', static::$databaseTable, [
[ 'alert_enabled=?', 1 ],
[ 'alert_start < ?', time() ],
[ '( alert_end = 0 or alert_end < ? )', time() ]
[ '( alert_end = 0 or alert_end > ? )', time() ]
], "alert_start ASC" )->setKeyField( 'alert_id' ) );
}
@@ -220,8 +248,8 @@ class _Alert extends \IPS\Content\Item
$obj->title = $values['alert_title'];
$obj->seo_title = \IPS\Http\Url\Friendly::seoTitle( $values['alert_title'] );
$obj->content = $values['alert_content'];
$obj->start = $values['alert_start'] ? ( $values['alert_start']->getTimestamp() < time() ) ? time() : $values['alert_start']->getTimestamp() : time();
$obj->end = $values['alert_end'] ? $values['alert_end']->getTimestamp() : 0;
$obj->start = !empty( $values['alert_start'] ) ? ( $values['alert_start']->getTimestamp() < time() ) ? time() : $values['alert_start']->getTimestamp() : time();
$obj->end = !empty ($values['alert_end'] ) ? $values['alert_end']->getTimestamp() : 0;
$obj->recipient_type = $values['alert_recipient_type'];
@@ -242,7 +270,7 @@ class _Alert extends \IPS\Content\Item
}
$obj->anonymous = $values['alert_anonymous'];
$obj->reply = ( \IPS\Member::loggedIn()->members_disable_pm == 2 ) ? 0 : $values['alert_reply'];
$obj->reply = ( ! \IPS\Member::loggedIn()->canUseMessenger() ) ? 0 : $values['alert_reply'];
$obj->save();
@@ -486,4 +514,65 @@ class _Alert extends \IPS\Content\Item
\IPS\Db::i()->delete( 'core_alerts_seen', [ 'seen_alert_id=?', $this->id ] );
}
/**
* Get the count of how many replies have been sent in via this alert
*
* @return int
*/
public function membersRepliedCount(): int
{
return (int) \IPS\Db::i()->select( 'COUNT(*)', 'core_message_topics', [ 'mt_alert=?', $this->id ] )->first();
}
/**
* Returns the current alert that messenger is being filtered by
*
* @param \IPS\Member|null $member
* @return Alert|null
*/
public static function getAlertCurrentlyFilteringMessages( ?\IPS\Member $member = NULL ): ?\IPS\core\Alerts\Alert
{
$member = $member ?: \IPS\Member::loggedIn();
if ( isset( $_SESSION['mt_alert'] ) )
{
try
{
$alert = static::load( $_SESSION['mt_alert'] );
/* Only show details about this alert to the alert owner */
if ( $alert->author()->member_id != $member->member_id )
{
return NULL;
}
return $alert;
}
catch( \Exception $e ) { }
}
return NULL;
}
/**
* Set the alert to currently filter by
*
* @param Alert $alert
* @return void
*/
public static function setAlertCurrentlyFilteringMessages( \IPS\core\Alerts\Alert $alert )
{
$_SESSION['mt_alert'] = $alert->id;
}
/**
* Unset any messenger filters
*
* @return void
*/
public static function clearMessengerFilters()
{
unset( $_SESSION['mt_alert'] );
}
}
@@ -0,0 +1,224 @@
<?php
/**
* @brief Deletion Log Model
* @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 Nov 2016
*/
namespace IPS\core;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Deletion Log Model
*/
class _Approval extends \IPS\Patterns\ActiveRecord
{
/**
* @brief Database Table
*/
public static $databaseTable = 'core_approval_queue';
/**
* @brief Database Prefix
*/
public static $databasePrefix = 'approval_';
/**
* @brief Multiton Store
*/
protected static $multitons;
/**
* @brief [ActiveRecord] ID Database Column
*/
public static $databaseColumnId = 'id';
/**
* @brief [ActiveRecord] Multiton Map
*/
protected static $multitonMap = array();
/**
* Set Held Data
*
* @param NULL|array $data The data indicating why the content was held for approval
* @return void
*/
public function set_held_data( ?array $data )
{
if ( \is_array( $data ) )
{
$this->_data['held_data'] = json_encode( $data );
return;
}
$this->_data['held_data'] = NULL;
}
/**
* Get Held Data
*
* @return array
*/
public function get_held_data(): ?array
{
if ( $this->_data['held_data'] )
{
return json_decode( $this->_data['held_data'], true );
}
return NULL;
}
/**
* Set Held Reason
*
* @param NULL|string $reason The reason for requiring approval.
* @return void
*/
public function set_held_reason( ?string $reason )
{
if ( $reason AND \in_array( $reason, static::availableReasons() ) )
{
$this->_data['held_reason'] = $reason;
return;
}
$this->_data['held_reason'] = NULL;
}
/**
* Get Held Reason
*
* @param \IPS\Member|NULL $member The member, or NULL for currently logged in.
* #return NULL|string
*/
public function reason( ?\IPS\Member $member = NULL ): string
{
$member = $member ?: \IPS\Member::loggedIn();
if ( $this->held_reason )
{
if ( $extra = $this->parseReason() )
{
return $member->language()->addToStack( $extra['lang'], TRUE, ( isset( $extra['sprintf'] ) ) ? array( 'sprintf' => $extra['sprintf'] ) : array() );
}
else
{
return $member->language()->addToStack( "approval_reason_{$this->held_reason}" );
}
}
else
{
return $member->language()->addToStack( "approval_reason_unknown" );
}
}
/**
* Parse Reason
*
* @param \IPS\Member|NULL $member The member, or NULL for currently logged in.
* @return NULL|array
*/
public function parseReason( ?\IPS\Member $member = NULL ): ?array
{
$member = $member ?: \IPS\Member::loggedIn();
if ( $this->held_reason )
{
switch( $this->held_reason )
{
case 'profanity':
return array(
'lang' => 'approval_reason_profanity',
'sprintf' => array( $this->held_data['word'] )
);
break;
case 'url':
return array(
'lang' => 'approval_reason_url',
'sprintf' => array( $this->held_data['url'] )
);
break;
case 'email':
return array(
'lang' => 'approval_reason_email',
'sprintf' => array( $this->held_data['email'] )
);
break;
case 'node':
$contentClass = $this->content_class;
$content = $contentClass::load( $this->content_id );
return array(
'lang' => 'approval_reason_node',
'sprintf' => array( $content->indefiniteArticle(), $content->container()->url(), $content->container()->getTitleForLanguage( $member->language() ), $content->definiteArticle( $member->language(), 2 ) )
);
break;
case 'item':
$contentClass = $this->content_class;
$content = $contentClass::load( $this->content_id );
$title = ( $content instanceof \IPS\Content\Comment ) ? $content->item()->mapped('title') : $content->mapped('title');
return array(
'lang' => 'approval_reason_item',
'sprintf' => array( $content->url(), $title )
);
break;
default:
return NULL;
break;
}
}
return NULL;
}
/**
* Available Reasons
*
* @return array
*/
public static function availableReasons(): array
{
return array(
'profanity',
'url',
'email',
'user',
'group',
'node',
'item'
);
}
/**
* Load from Content
*
* @param string $class Content class
* @param int $id Content ID
* @return static
*/
public static function loadFromContent( string $class, int $id ): \IPS\core\Approval
{
try
{
return static::constructFromData( \IPS\Db::i()->select( '*', 'core_approval_queue', array( "approval_content_class=? AND approval_content_id=?", $class, $id ) )->first() );
}
catch( \UnderflowException $e )
{
throw new \OutOfRangeException;
}
}
}
Whitespace-only changes.
@@ -1,6 +1,6 @@
<?php
/**
* @brief Bulkmail central library
* @brief Datalayer Class
* @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/
@@ -18,7 +18,7 @@ if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
}
/**
* Bulk mail central library
* Datalayer Class
*/
class _DataLayer extends \IPS\Patterns\Singleton
{
@@ -98,6 +98,8 @@ class _SocialProfiles extends \IPS\Helpers\Form\KeyValue
'xing' => "siteprofilelink_xing",
'weibo' => "siteprofilelink_weibo",
'vk' => "siteprofilelink_vk",
'discord' => "siteprofilelink_discord",
'twitch' => "siteprofilelink_twitch",
);
return $options;
+1 -1
View File
@@ -85,7 +85,7 @@ class _Ignore extends \IPS\Patterns\ActiveRecord
}
}
$form = new \IPS\Helpers\Form( NULL, $ignore ? 'ignore_edit' : 'ignore_submit' );
$form = new \IPS\Helpers\Form( 'ignore_form', $ignore ? 'ignore_edit' : 'ignore_submit' );
$form->class = 'ipsForm_vertical';
$form->add( new \IPS\Helpers\Form\Member( 'member', $ignore ? \IPS\Member::load( $ignore->ignore_id ) : NULL, TRUE, array( 'placeholder' => \IPS\Member::loggedIn()->language()->addToStack('ignore_placeholder') ) ) );
+23 -20
View File
@@ -87,7 +87,7 @@ class _IndexNow extends \IPS\Patterns\Singleton
return;
}
$url = \IPS\Http\Url::internal('');
$url = \IPS\Http\Url::internal( '', 'front' );
$data = array(
'host' => \IPS\Http\Url::baseUrl(\IPS\Http\Url::PROTOCOL_WITHOUT ),
'key' => \IPS\Settings::i()->indexnow_key,
@@ -95,27 +95,30 @@ class _IndexNow extends \IPS\Patterns\Singleton
'urlList' => $urls,
);
$response = \IPS\Http\Url::external( static::$apiUrl )->request()
->setHeaders( array( 'Content-Type' => 'application/json' ) )->post( json_encode( $data ) );
if( !$response->isSuccessful() )
{
switch ( $response->httpResponseCode )
{
case 400:
$error = 'invalid_request';
break;
case 403:
$error = 'invalid_api_key';
breaK;
case 422:
$error = 'invalid_url';
break;
case 429:
default:
$error = 'unknown_error';
try {
$response = \IPS\Http\Url::external(static::$apiUrl)->request()
->setHeaders(array('Content-Type' => 'application/json'))->post(json_encode($data));
if (!$response->isSuccessful()) {
switch ($response->httpResponseCode) {
case 400:
$error = 'invalid_request';
break;
case 403:
$error = 'invalid_api_key';
break;
case 422:
$error = 'invalid_url';
break;
case 429:
default:
$error = 'unknown_error';
}
\IPS\Log::log($response->httpResponseCode . ' ' . $error . ' ' . print_r($data, TRUE), 'IndexNow');
}
\IPS\Log::log( $response->httpResponseCode . ' ' . $error . ' ' . print_r($data, TRUE ), 'IndexNow');
} catch (\IPS\Http\Request\CurlException $e)
{
\IPS\Log::log($e->getMessage(), 'IndexNow');
}
}
@@ -313,23 +313,49 @@ class _Profanity extends \IPS\Patterns\ActiveRecord implements \JsonSerializable
*
* @param string $content The content to check
* @param \IPS\Member|NULL $member The author of the content
* @param array|NULL $filtersMatched What matched, passed by reference
* @return bool
*/
public static function hiddenByFilters( $content, $member=NULL )
public static function hiddenByFilters( $content, $member=NULL, array &$filtersMatched = array() )
{
$return = static::_checkProfanityFilters( $content, $member );
if ( $return == FALSE )
if ( \is_string( $return ) )
{
$return = static::_checkUrlFilters( $content );
}
if ( $return == FALSE )
{
$return = static::_checkEmailFilters( $content );
$filtersMatched = array(
'type' => 'profanity',
'match' => $return
);
return TRUE;
}
return $return;
$return = static::_checkUrlFilters( $content );
if ( \is_string( $return ) )
{
$filtersMatched = array(
'type' => 'url',
'match' => $return
);
return TRUE;
}
$return = static::_checkEmailFilters( $content );
if ( \is_string( $return ) )
{
/* Add to approval queue table */
$filtersMatched = array(
'type' => 'email',
'match' => $return
);
return TRUE;
}
return FALSE;
}
/**
@@ -337,12 +363,19 @@ class _Profanity extends \IPS\Patterns\ActiveRecord implements \JsonSerializable
*
* @param string $content The content to check
* @param \IPS\Member|NULL $member The author of the content
* @return bool
* @return bool|string
*/
protected static function _checkProfanityFilters( $content, $member=NULL )
{
$looseProfanity = array();
$exactProfanity = array();
/* Clean up profanity a little to remove citation details and inline data attributes.
We don't want to remove <blockquotes> entirely as users can then hide profanity in a quote box to
bypass the system. */
$content = preg_replace( "#<blockquote\s+?class=\"ipsQuote\"[^>]+?>#", "<blockquote>", $content );
$content = preg_replace( "#<div\s+?class=\"ipsQuote_citation\"([^>]+?)?>(.+?)</div>#s", "", $content );
foreach( static::getProfanity() AS $profanity )
{
if ( $profanity->action == 'moderate' )
@@ -370,7 +403,7 @@ class _Profanity extends \IPS\Patterns\ActiveRecord implements \JsonSerializable
{
if ( mb_stristr( $content, $word ) )
{
return TRUE;
return $word;
break;
}
}
@@ -393,7 +426,7 @@ class _Profanity extends \IPS\Patterns\ActiveRecord implements \JsonSerializable
{
if ( \in_array( mb_strtolower( $section ), array_map( 'mb_strtolower', $exactProfanity ) ) )
{
return TRUE;
return $word;
break;
}
}
@@ -408,7 +441,7 @@ class _Profanity extends \IPS\Patterns\ActiveRecord implements \JsonSerializable
* Check URL Filters
*
* @param string $content The content to check
* @return bool
* @return bool|string
*/
protected static function _checkUrlFilters( $content )
{
@@ -455,7 +488,7 @@ class _Profanity extends \IPS\Patterns\ActiveRecord implements \JsonSerializable
{
if ( \IPS\Settings::i()->ipb_url_filter_option == 'none' )
{
return TRUE;
return $tag->hasAttribute( 'href' );
}
$urlToCheck = $tag->hasAttribute( 'href' ) ? $tag->getAttribute( 'href' ) : ( $tag->hasAttribute( 'src' ) ? $tag->getAttribute( 'src' ) : $tag->getAttribute( 'data-embed-src' ) );
@@ -481,7 +514,7 @@ class _Profanity extends \IPS\Patterns\ActiveRecord implements \JsonSerializable
/* IF we are moderating all URL's and it's not an attachment, return here. */
if ( $good !== TRUE AND \IPS\Settings::i()->ipb_url_filter_option == 'none' )
{
return TRUE;
return $good;
}
$url = preg_quote( $url, '/' );
@@ -492,7 +525,7 @@ class _Profanity extends \IPS\Patterns\ActiveRecord implements \JsonSerializable
{
if ( preg_match( '/' . $url . '/i', $urlToCheck ) )
{
return TRUE;
return $urlToCheck;
}
}
/* If it's a whitelist, check that */
@@ -501,7 +534,7 @@ class _Profanity extends \IPS\Patterns\ActiveRecord implements \JsonSerializable
/* @note http:// is hard-coded here as we're simply validating that the URL is on the same domain, so the protocol doesn't matter for the base_url replacement */
if ( !preg_match( '/' . $url . '/i', str_replace( '<___base_url___>', 'http://' . parse_url( \IPS\Settings::i()->base_url, PHP_URL_HOST ), $urlToCheck ), $matches ) )
{
$good = FALSE;
$good = $urlToCheck;
}
else
{
@@ -514,9 +547,9 @@ class _Profanity extends \IPS\Patterns\ActiveRecord implements \JsonSerializable
}
}
if ( $good === FALSE AND \IPS\Settings::i()->ipb_url_filter_option == 'white' )
if ( $good !== TRUE AND \IPS\Settings::i()->ipb_url_filter_option == 'white' )
{
return TRUE;
return $good;
}
}
catch( \Exception $e ) {}
@@ -530,7 +563,7 @@ class _Profanity extends \IPS\Patterns\ActiveRecord implements \JsonSerializable
* Check Email Filters
*
* @param string $content The content to check
* @return bool
* @return bool|string
*/
protected static function _checkEmailFilters( $content )
{
@@ -578,7 +611,7 @@ class _Profanity extends \IPS\Patterns\ActiveRecord implements \JsonSerializable
if( preg_match( '/' . \IPS\Text\Parser::EMAIL_REGEX . '/u', $content, $matches ) )
{
return TRUE;
return $matches[0];
}
}
+31 -7
View File
@@ -644,7 +644,8 @@ class _Promote extends \IPS\Patterns\ActiveRecord
$this->failed = ( $hasFailed ) ? $this->failed + 1 : 0;
$this->returned = $returned;
$this->save();
}
\IPS\Api\Webhook::fire( 'content_promoted', $this, $this->object()->webhookFilters() );
}
/**
* Save Changed Columns
@@ -737,7 +738,7 @@ class _Promote extends \IPS\Patterns\ActiveRecord
/**
* Shorten URL.
*
* @param string $service Service key, (such as facebook or twitter)
* @param string $service Service key, (such as twitter)
* @return boolean
*/
public function serviceFailed( $service )
@@ -755,7 +756,7 @@ class _Promote extends \IPS\Patterns\ActiveRecord
/**
* Returns text sent to a named service
*
* @param string $service Service key (twitter, facebook)
* @param string $service Service key (twitter)
* @param boolean $forDisplay Is this for display in output?
* @return string|NULL
*/
@@ -774,7 +775,7 @@ class _Promote extends \IPS\Patterns\ActiveRecord
/**
* Sets text for a named service
*
* @param string $service Service key (twitter, facebook)
* @param string $service Service key (twitter)
* @param boolean $text Text to save
* @return string|NULL
*/
@@ -788,7 +789,7 @@ class _Promote extends \IPS\Patterns\ActiveRecord
/**
* Return the published URL for this post
*
* @param string $service Service key, (such as facebook or twitter)
* @param string $service Service key, (such as twitter)
* @return string|NULL
*/
public function getPublishedUrl( $service )
@@ -806,7 +807,7 @@ class _Promote extends \IPS\Patterns\ActiveRecord
return $this->object()->url();
}
catch ( \InvalidArgumentException $e )
catch ( \InvalidArgumentException|\RuntimeException $e )
{
return NULL;
}
@@ -816,7 +817,7 @@ class _Promote extends \IPS\Patterns\ActiveRecord
/**
* Attempt to get all responses for this ID
*
* @param string $service Service to return (twitter, facebook, etc)
* @param string $service Service to return (facebook, etc)
* @return array|NULL array( response_id => data )
*/
public function responses( $service )
@@ -1399,4 +1400,27 @@ class _Promote extends \IPS\Patterns\ActiveRecord
}
}
}
/**
* Get output for API
*
* @param \IPS\Member|NULL $authorizedMember The member making the API request or NULL for API Key / client_credentials
*
* @apiresponse \IPS\Member promotedBy The member who promoted the content item
* @apiresponse string itemClass The FQN classname
* @apiresponse string itemTitle Title
* @apiresponse string itemDescription The content
* @apiresponse object item The promoted content item
*
*/
public function apiOutput( \IPS\Member $authorizedMember = NULL )
{
return [
'promotedBy' => $this->author()->apiOutput($authorizedMember),
'itemClass' => \get_class($this->object()),
'itemTitle' => $this->objectTitle,
'itemDescription' => $this->objectMetaDescription,
'item' => $this->object()->apiOutput($authorizedMember),
];
}
}
@@ -98,6 +98,11 @@ class _Report extends \IPS\Content\Item implements \IPS\Content\ReadMarkers
* @brief Title
*/
public static $title = 'report';
/**
* @brief [Content\Item] Include these items in trending content
*/
public static $includeInTrending = FALSE;
/**
* Should posting this increment the poster's post count?
@@ -602,4 +607,113 @@ class _Report extends \IPS\Content\Item implements \IPS\Content\ReadMarkers
'read', 'unread', 'report_status_1', 'report_status_2', 'report_status_3'
);
}
/**
* Build the where clause for finding reports
*
* @param \IPS\Member|null $member Member to base permissions on
* @return array
*/
public static function where( \IPS\Member $member=NULL ): array
{
$member = $member ?: \IPS\Member::loggedIn();
$classWhere = [];
$extensionWhere = [];
$viewPermIds = [];
$perms = $member->modPermissions();
foreach( \IPS\Db::i()->select( 'app, perm_id', 'core_permission_index', \IPS\Db::i()->findInSet( 'perm_view', $member->permissionArray() ) . " OR perm_view='*'" ) as $perm )
{
$viewPermIds[ $perm['app'] ][] = $perm['perm_id'];
}
foreach ( array_merge( ['IPS\core\Messenger\Conversation', 'IPS\core\Messenger\Message'], array_values( \IPS\Content::routedClasses( FALSE, TRUE ) ) ) as $class )
{
/* Got nodes? */
$item = NULL;
if ( is_subclass_of( $class, "IPS\Content\Item" ) )
{
$item = $class;
}
else if ( is_subclass_of( $class, "IPS\Content\Comment" ) or is_subclass_of( $class, "IPS\Content\Review" ) )
{
if ( isset( $class::$itemClass ) )
{
$item = $class::$itemClass;
}
}
if ( ! $item )
{
continue;
}
$extensionWhereClause = '';
if ( isset( $item::$containerNodeClass ) )
{
$container = $item::$containerNodeClass;
if ( isset( $container::$modPerm ) )
{
if ( isset( $perms[$container::$modPerm] ) and $perms[$container::$modPerm] != '*' and $perms[$container::$modPerm] != '-1')
{
$extensionWhereClause = ' AND ' . \IPS\Db::i()->in( 'node_id', $perms[$container::$modPerm] );
}
}
}
$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[ $class::$application ][ $workingClass::$permissionMap['read'] ] ) )
{
$permIds[ $class::$application ][ $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'] . "='*' ) AND app='{$class::$application}'" ) );
}
if( isset( $viewPermIds[ $class::$application ] ) AND !empty( $permIds[ $class::$application ][ $workingClass::$permissionMap['read'] ] ) )
{
$classWhere[] = "( ( class='" . str_replace( '\\', '\\\\', $class ) . "' AND ( perm_id IN(" . implode( ',', array_intersect( $viewPermIds[ $class::$application ], $permIds[ $class::$application ][ $workingClass::$permissionMap['read'] ] ) ) . ") ) OR perm_id IS NULL )" . $extensionWhereClause . ")";
}
}
else
{
if ( isset( $class::$application ) and isset( $viewPermIds[ $class::$application ] ) )
{
$classWhere[] = "( ( class='" . str_replace( '\\', '\\\\', $class ) . "' AND ( perm_id IN(" . implode( ',', $viewPermIds[ $class::$application ] ) . ") ) OR perm_id IS NULL )" . $extensionWhereClause . ")";
}
else
{
$classWhere[] = "( class='" . str_replace( '\\', '\\\\', $class ) . "' )";
}
}
}
return [ '(' . implode( ' OR ', array_values( $classWhere ) ) . ')' ];
}
/**
* Can view this entry
*
* @param \IPS\Member|NULL $member The member or NULL for currently logged in member.
* @return bool
*/
public function canView( $member = NULL )
{
$member = $member ?: \IPS\Member::loggedIn();
$return = parent::canView($member);
if ( $return AND $member->modPermission('can_view_reports') )
{
return TRUE;
}
return FALSE;
}
}
@@ -718,7 +718,6 @@ class _Upgrade
{
foreach( $_versionApps as $_versionApp )
{
\IPS\Application::installNewFeatures( $_versionApp, $_versionId );
\IPS\Log::debug( "Running finish step for: {$_versionApp} version {$_versionId}", 'upgrade' );
/* Get the object */
@@ -785,13 +784,6 @@ class _Upgrade
*/
protected function step3( $data )
{
/* Set administrator new features flags - if none were added, then it'll automatically reset back */
foreach( new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'core_members', array( \IPS\Db::i()->in('member_id', \array_keys( \IPS\Member::administrators()['m'] ) ) . " OR " . \IPS\Db::i()->in( 'member_group_id', \array_keys( \IPS\Member::administrators()['g'] ) ) . " OR " . \IPS\Db::i()->findInSet( 'mgroup_others', \array_keys( \IPS\Member::administrators()['g'] ) ) ) ), 'IPS\Member' ) AS $admin )
{
$admin->members_bitoptions['has_new_acp_features'] = TRUE;
$admin->save();
}
return $this->appLoop( $data, function( $app )
{
if ( !file_exists( \IPS\SITE_FILES_PATH . '/plugins/hooks.php' ) )
+14 -2
View File
@@ -296,7 +296,7 @@ class _Status extends \IPS\Content\Item implements \IPS\Content\Lockable, \IPS\C
$return = TRUE;
/* Can we access the module? */
if( !( $member->canAccessModule( \IPS\Application\Module::get( 'core', 'status' ) ) and \IPS\Settings::i()->profile_comments ) )
if( !( $member->canAccessModule( \IPS\Application\Module::get( 'core', 'status', 'front' ) ) and \IPS\Settings::i()->profile_comments ) )
{
return FALSE;
}
@@ -420,7 +420,9 @@ class _Status extends \IPS\Content\Item implements \IPS\Content\Lockable, \IPS\C
'key' => mb_ucfirst( static::$module ),
'maxLength' => 65535,
'autoSaveKey' => 'reply-' . static::$application . '/' . static::$module . '-' . $this->$idColumn,
'minimize' => isset( \IPS\Request::i()->$submitted ) ? NULL : static::$formLangPrefix . '_comment_placeholder'
'minimize' => isset( \IPS\Request::i()->$submitted ) ? NULL : static::$formLangPrefix . '_comment_placeholder',
'contentClass' => \get_called_class(),
'contentId' => $this->$idColumn
), function() use( $self ) {
if ( !$self->mergeConcurrentComment() )
{
@@ -875,4 +877,14 @@ class _Status extends \IPS\Content\Item implements \IPS\Content\Lockable, \IPS\C
return $return;
}
/**
* Whether or not to include in site search
*
* @return bool
*/
public static function includeInSiteSearch()
{
return \IPS\Member::loggedIn()->canAccessModule( \IPS\Application\Module::get( 'core', 'status', 'front' ) );
}
}
@@ -79,7 +79,7 @@ class _Subscription extends \IPS\Patterns\ActiveRecord
foreach ( $subscriptions as $row )
{
$member = \IPS\Member::load( $row['member_id'] );
if ( !$member->email )
if ( !$member->email or $member->isBanned() )
{
/* Update sent time, so the batch doesn't get stuck in a loop */
\IPS\Db::i()->update( 'core_stream_subscriptions', array( 'sent' => time() ), array( 'id=?', $row['id'] ) );
@@ -431,6 +431,8 @@ class _Warning extends \IPS\Content\Item
/* Moderator log */
\IPS\Session::i()->modLog( 'modlog__action_warn_user', array( $member->name => FALSE ) );
/* Webhook */
\IPS\Api\Webhook::fire( 'member_warned', $this );
parent::processAfterCreate( $comment, $values );
}
@@ -603,7 +605,7 @@ class _Warning extends \IPS\Content\Item
if ( $values[ 'warn_' . $f ] instanceof \IPS\DateTime )
{
$difference = \IPS\DateTime::create()->diff( $values[ 'warn_' . $f ] );
$difference = \IPS\DateTime::create()->setTimezone( $values[ 'warn_' . $f ]->getTimezone() )->diff( $values[ 'warn_' . $f ] );
$period = 'P';
foreach ( array( 'y' => 'Y', 'm' => 'M', 'd' => 'D' ) as $k => $v )
{