Version 5.0.0 beta 4
This commit is contained in:
1 parent
e86153356a
commit
2f24f9de48
276 files changed
+8614
-6044
No files matched your search
@@ -165,7 +165,7 @@ class ItemController extends Controller
|
||||
|
||||
/* Sort */
|
||||
$supportedSortBy = array( 'date', 'title' );
|
||||
if( $class::$databaseColumnMap['updated'] )
|
||||
if( isset($class::$databaseColumnMap['updated'] ) )
|
||||
{
|
||||
$supportedSortBy[] = 'updated';
|
||||
}
|
||||
|
||||
+84
-27
@@ -29,6 +29,7 @@ use IPS\DateTime;
|
||||
use IPS\Db;
|
||||
use IPS\Db\Exception;
|
||||
use IPS\Db\Select;
|
||||
use IPS\Dispatcher\Front;
|
||||
use IPS\Events\Event;
|
||||
use IPS\File;
|
||||
use IPS\Helpers\Form\Captcha;
|
||||
@@ -39,6 +40,7 @@ use IPS\IPS;
|
||||
use IPS\Member;
|
||||
use IPS\Node\Model;
|
||||
use IPS\Notification;
|
||||
use IPS\Output;
|
||||
use IPS\Patterns\ActiveRecordIterator;
|
||||
use IPS\Platform\Bridge;
|
||||
use IPS\Redis;
|
||||
@@ -57,6 +59,7 @@ use function in_array;
|
||||
use function intval;
|
||||
use function is_array;
|
||||
use function substr;
|
||||
use function ucfirst;
|
||||
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
@@ -151,27 +154,31 @@ abstract class Comment extends Content
|
||||
break;
|
||||
|
||||
case 'approved':
|
||||
if ( $first ) // If this is the first post within an item, don't mark it hidden, otherwise the count of unapproved comments/items will include both the comment and the item when really only the item is hidden
|
||||
if( IPS::classUsesTrait( $obj, Hideable::class ) )
|
||||
{
|
||||
$val = TRUE;
|
||||
}
|
||||
elseif ( $hiddenStatus === NULL )
|
||||
{
|
||||
$permissionCheckFunction = in_array( 'IPS\Content\Review', class_parents( get_called_class() ) ) ? 'canReview' : 'canComment';
|
||||
if ( !$member->member_id and !$item->$permissionCheckFunction( $member, FALSE ) )
|
||||
if ( $first ) // If this is the first post within an item, don't mark it hidden, otherwise the count of unapproved comments/items will include both the comment and the item when really only the item is hidden
|
||||
{
|
||||
$val = -3;
|
||||
$val = TRUE;
|
||||
}
|
||||
elseif ( in_array( 'IPS\Content\Review', class_parents( get_called_class() ) ) )
|
||||
elseif ( $hiddenStatus === NULL )
|
||||
{
|
||||
$val = $item->moderateNewReviews( $member ) ? 0 : 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
$val = $item->moderateNewComments( $member ) ? 0 : 1;
|
||||
$permissionCheckFunction = in_array( 'IPS\Content\Review', class_parents( get_called_class() ) ) ? 'canReview' : 'canComment';
|
||||
if ( !$member->member_id and !$item->$permissionCheckFunction( $member, FALSE ) )
|
||||
{
|
||||
$val = -3;
|
||||
}
|
||||
elseif ( in_array( 'IPS\Content\Review', class_parents( get_called_class() ) ) )
|
||||
{
|
||||
$val = $item->moderateNewReviews( $member ) ? 0 : 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
$val = $item->moderateNewComments( $member ) ? 0 : 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
if( $val === null or !IPS::classUsesTrait( $obj, Hideable::class ) )
|
||||
{
|
||||
switch ( $hiddenStatus )
|
||||
{
|
||||
@@ -189,11 +196,15 @@ abstract class Comment extends Content
|
||||
break;
|
||||
|
||||
case 'hidden':
|
||||
if( !IPS::classUsesTrait( $obj, Hideable::class ) )
|
||||
{
|
||||
$val = $hiddenStatus;
|
||||
}
|
||||
if ( $first )
|
||||
{
|
||||
$val = FALSE; // If this is the first post within an item, don't mark it hidden, otherwise the count of unapproved comments/items will include both the comment and the item when really only the item is hidden
|
||||
}
|
||||
elseif ( $item->approvedButHidden() )
|
||||
elseif ( IPS::classUsesTrait( $item, Hideable::class ) and $item->approvedButHidden() )
|
||||
{
|
||||
$val = 2;
|
||||
}
|
||||
@@ -602,6 +613,49 @@ abstract class Comment extends Content
|
||||
) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @var array Shareable URLs
|
||||
*/
|
||||
protected static $shareableUrls = array();
|
||||
/**
|
||||
* Get a shareable URL
|
||||
*
|
||||
* @return Url
|
||||
*/
|
||||
public function shareableUrl( string $type='comment' ): Url
|
||||
{
|
||||
$currentPage = Front::i()->currentPage ?? 1;
|
||||
$idColumn = static::$databaseColumnId;
|
||||
$item = $this->item();
|
||||
$itemIdColumn = $item::$databaseColumnId;
|
||||
|
||||
/* Avoid building a single item's URL multiple times, such as when viewing a topic */
|
||||
if ( isset( static::$shareableUrls[ $type ][ $item->$itemIdColumn ] ) )
|
||||
{
|
||||
$url = static::$shareableUrls[ $type ][ $item->$itemIdColumn ];
|
||||
}
|
||||
else
|
||||
{
|
||||
$url = $item->url()->setPage( 'page', $currentPage );
|
||||
|
||||
/* if we can do both comments and reviews, just return the findCommment url as we have tabs to navigate anyway */
|
||||
if ( isset( $item::$reviewClass ) and isset( $item::$commentClass ) )
|
||||
{
|
||||
if ( method_exists( $item, 'commentReviewTabs' ) )
|
||||
{
|
||||
if ( count( $item->commentReviewTabs() ) > 1 )
|
||||
{
|
||||
$url = $url->setQueryString( ['tab' => $type . 's'] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static::$shareableUrls[ $type ][ $item->$itemIdColumn ] = $url;
|
||||
}
|
||||
|
||||
return $url->setFragment( 'find' . ucfirst( $type ) . '-' . $this->$idColumn );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get containing item
|
||||
*
|
||||
@@ -1868,28 +1922,31 @@ abstract class Comment extends Content
|
||||
}
|
||||
}
|
||||
|
||||
if( $this->mapped('first') )
|
||||
if ( ! Output::i()->reduceLinks() )
|
||||
{
|
||||
$share = new ContentMenuLink( url: $this->item()->url('share' ), languageString: Member::loggedIn()->language()->addToStack( $contentType === 'Comment' ? 'share_this_post' : 'share_this_review' ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( $contentType === 'Comment' )
|
||||
if ( $this->mapped( 'first' ) )
|
||||
{
|
||||
$share = new ContentMenuLink( url: $this->item()->url( )->setQueryString( array( 'do' => 'findComment', 'comment' => $this->$idField )), languageString: Member::loggedIn()->language()->addToStack( 'share_this_post' ) );
|
||||
$share = new ContentMenuLink( url: $this->item()->url( 'share' ), languageString: Member::loggedIn()->language()->addToStack( $contentType === 'Comment' ? 'share_this_post' : 'share_this_review' ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
$share = new ContentMenuLink( url: $this->item()->url( )->setQueryString( array( 'do' => 'findReview', 'review' => $this->$idField )), languageString: Member::loggedIn()->language()->addToStack( 'share_this_review' ) );
|
||||
if ( $contentType === 'Comment' )
|
||||
{
|
||||
$share = new ContentMenuLink( url: $this->shareableUrl(), languageString: Member::loggedIn()->language()->addToStack( 'share_this_post' ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
$share = new ContentMenuLink( url: $this->shareableUrl('review'), languageString: Member::loggedIn()->language()->addToStack( 'share_this_review' ) );
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$share->opensDialog( title: Member::loggedIn()->language()->addToStack('share'), size: 'narrow', contentSelector: '#elShare' . ucfirst( static::$moderationMenuIdPrefix ) . $this->$idField . '_menu' )
|
||||
$share->opensDialog( title: Member::loggedIn()->language()->addToStack('share'), size: 'narrow', contentSelector: '#elShare' . ucfirst( static::$moderationMenuIdPrefix ) . $this->$idField . '_menu' )
|
||||
->addAttribute( 'data-role', 'share' . $contentType )
|
||||
->addAttribute( 'id', 'elShare' . ucfirst( static::$moderationMenuIdPrefix ) . $this->$idField )
|
||||
->addAttribute( 'rel', 'nofollow' );
|
||||
$menu->add( $share );
|
||||
$menu->add( $share );
|
||||
}
|
||||
|
||||
if( method_exists( $this, 'canRecognize') )
|
||||
{
|
||||
|
||||
@@ -879,11 +879,12 @@ abstract class Content extends ActiveRecord
|
||||
*
|
||||
* @param string $reportContent Report content message from member
|
||||
* @param int $reportType Report type (see constants in \IPS\core\Reports\Report)
|
||||
* @param Member|null $member Member making the report (or NULL for loggedIn())
|
||||
* @param Member|null $member Member making the report (or NULL for loggedIn())
|
||||
* @param array $guestDetails Details for a guest report
|
||||
* @return Report
|
||||
* @throws UnexpectedValueException If there is a permission error - you should only call this method after checking canReport
|
||||
*/
|
||||
public function report( string $reportContent, int $reportType=1, Member|null $member=null ): Report
|
||||
public function report( string $reportContent, int $reportType=1, Member|null $member=null, array $guestDetails=array() ): Report
|
||||
{
|
||||
$member = ( $member ) ?: Member::loggedIn();
|
||||
|
||||
@@ -936,9 +937,16 @@ abstract class Content extends ActiveRecord
|
||||
'report_by' => (int) $member->member_id,
|
||||
'date_reported' => time(),
|
||||
'ip_address' => Request::i()->ipAddress(),
|
||||
'report_type' => $member->member_id ? $reportType : 0
|
||||
'report_type' => ( ! $member->member_id and Settings::i()->automoderation_enabled ) ? 0 : $reportType
|
||||
);
|
||||
|
||||
|
||||
if ( count( $guestDetails ) and isset( $guestDetails['email'] ) )
|
||||
{
|
||||
/* Guest name can be optional */
|
||||
$reportInsert['guest_name'] = isset( $guestDetails['name'] ) ? $guestDetails['name'] : '';
|
||||
$reportInsert['guest_email'] = $guestDetails['email'];
|
||||
}
|
||||
|
||||
$insertID = Db::i()->insert( 'core_rc_reports', $reportInsert );
|
||||
$reportInsert['id'] = $insertID;
|
||||
|
||||
|
||||
@@ -19,8 +19,11 @@ use ErrorException;
|
||||
use Exception;
|
||||
use InvalidArgumentException;
|
||||
use IPS\Api\Webhook;
|
||||
use IPS\cloud\Application as CloudApplication;
|
||||
use IPS\Content\Search\SearchContent;
|
||||
use IPS\core\Feature;
|
||||
use IPS\Helpers\Form\Email;
|
||||
use IPS\Helpers\Form\Select;
|
||||
use IPS\Helpers\Form\TextArea;
|
||||
use IPS\Helpers\Form\Upload;
|
||||
use IPS\Helpers\Form\Url as FormUrl;
|
||||
@@ -398,7 +401,12 @@ class Controller extends CoverPhotoController
|
||||
}
|
||||
|
||||
Output::i()->sidebar['contextual'] .= $item->ui( 'sidebar' );
|
||||
|
||||
|
||||
if( Application::appIsEnabled( 'cloud' ) )
|
||||
{
|
||||
Output::setCacheTime( CloudApplication::getCacheDateForPage( $item->mapped('updated'), ( ( $item::$application === 'forums' and $item->isArchived() ) ? 'archived' : 'content' ) ) );
|
||||
}
|
||||
|
||||
/* Return */
|
||||
return $item;
|
||||
}
|
||||
@@ -1470,7 +1478,26 @@ class Controller extends CoverPhotoController
|
||||
}
|
||||
if ( $values = $form->values() )
|
||||
{
|
||||
$report = $item->report( $values['report_message'], ( isset( $values['report_type'] ) ) ? $values['report_type'] : 0 );
|
||||
$guestDetails = [];
|
||||
if ( ! Member::loggedIn()->member_id and Settings::i()->report_capture_guest_details )
|
||||
{
|
||||
$guestDetails = [ 'name' => $values['report_guest_name'], 'email' => $values['report_guest_email'] ];
|
||||
|
||||
/* Has this guest already reported this? */
|
||||
try
|
||||
{
|
||||
$index = Db::i()->select( '*', 'core_rc_index', [ 'class=? and content_id=?', \get_class( $item ), $item->$idColumn ] )->first();
|
||||
$report = Db::i()->select( '*', 'core_rc_reports', [ 'rid=? and guest_email=?', $index['id'], $values['report_guest_email'] ] )->first();
|
||||
|
||||
Output::i()->error( 'report_err_already_reported', '2S136/11', 403, '' );
|
||||
}
|
||||
catch( \UnderflowException )
|
||||
{
|
||||
/* The query failed, so this is a new report */
|
||||
}
|
||||
}
|
||||
|
||||
$report = $item->report( $values['report_message'], ( isset( $values['report_type'] ) ) ? $values['report_type'] : 0, null, $guestDetails );
|
||||
File::claimAttachments( "report-{$class::$application}-{$class::$module}-{$item->$idColumn}", $report->id );
|
||||
if ( Request::i()->isAjax() )
|
||||
{
|
||||
@@ -3337,7 +3364,7 @@ class Controller extends CoverPhotoController
|
||||
}
|
||||
|
||||
/* Show form */
|
||||
$form = new Form( NULL, 'report_submit' );
|
||||
$form = new Form( 'report_submit', 'report_submit' );
|
||||
$form->class = 'ipsForm--vertical ipsForm--report';
|
||||
$itemIdColumn = $class::$databaseColumnId;
|
||||
$idColumn = $comment::$databaseColumnId;
|
||||
@@ -3355,17 +3382,28 @@ class Controller extends CoverPhotoController
|
||||
return;
|
||||
}
|
||||
catch( Exception $e ) { }
|
||||
|
||||
$options = array( Report::TYPE_MESSAGE => Member::loggedIn()->language()->addToStack('report_message_comment') );
|
||||
foreach( Types::roots() as $type )
|
||||
{
|
||||
$options[ $type->id ] = $type->_title;
|
||||
}
|
||||
|
||||
$form->add( new Radio( 'report_type', NULL, FALSE, array( 'options' => $options ) ) );
|
||||
}
|
||||
|
||||
$form->add( new Editor( 'report_message', NULL, FALSE, array( 'app' => 'core', 'key' => 'Reports', 'autoSaveKey' => "report-{$class::$application}-{$class::$module}-{$item->$itemIdColumn}-{$comment->$idColumn}", 'minimize' => 'report_message_placeholder' ) ) );
|
||||
|
||||
$options = array( Report::TYPE_MESSAGE => Member::loggedIn()->language()->addToStack('report_message_comment') );
|
||||
foreach( Types::roots() as $type )
|
||||
{
|
||||
$options[ $type->id ] = $type->_title;
|
||||
}
|
||||
|
||||
if ( count( $options ) > 1 )
|
||||
{
|
||||
$form->add( new Select( 'report_type', null, false, ['options' => $options] ) );
|
||||
}
|
||||
|
||||
if ( ! Member::loggedIn()->member_id and Settings::i()->report_capture_guest_details )
|
||||
{
|
||||
/* Guest details */
|
||||
$form->add( new Text( 'report_guest_name', null, Settings::i()->report_guest_details_name_mandatory ) );
|
||||
$form->add( new Email( 'report_guest_email', null, true ) );
|
||||
}
|
||||
|
||||
$form->add( new Editor( 'report_message', null, (bool) Settings::i()->report_content_mandatory, array( 'app' => 'core', 'key' => 'Reports', 'autoSaveKey' => "report-{$class::$application}-{$class::$module}-{$item->$itemIdColumn}-{$comment->$idColumn}", 'minimize' => Settings::i()->report_content_mandatory ? 'report_message_placeholder_mandatory' : 'report_message_placeholder' ) ) );
|
||||
|
||||
if ( !Request::i()->isAjax() )
|
||||
{
|
||||
Member::loggedIn()->language()->words['report_message'] = Member::loggedIn()->language()->addToStack('report_message_fallback');
|
||||
@@ -3378,7 +3416,26 @@ class Controller extends CoverPhotoController
|
||||
|
||||
if ( $values = $form->values() )
|
||||
{
|
||||
$report = $comment->report( $values['report_message'], ( isset( $values['report_type'] ) ) ? $values['report_type'] : 0 );
|
||||
$guestDetails = [];
|
||||
if ( ! Member::loggedIn()->member_id and Settings::i()->report_capture_guest_details )
|
||||
{
|
||||
$guestDetails = [ 'name' => $values['report_guest_name'], 'email' => $values['report_guest_email'] ];
|
||||
|
||||
/* Has this guest already reported this? */
|
||||
try
|
||||
{
|
||||
$index = Db::i()->select( '*', 'core_rc_index', [ 'class=? and content_id=?', \get_class( $comment ), $comment->$idColumn ] )->first();
|
||||
$report = Db::i()->select( '*', 'core_rc_reports', [ 'rid=? and guest_email=?', $index['id'], $values['report_guest_email'] ] )->first();
|
||||
|
||||
Output::i()->error( 'report_err_already_reported', '2S136/11', 403, '' );
|
||||
}
|
||||
catch( \UnderflowException )
|
||||
{
|
||||
/* The query failed, so this is a new report */
|
||||
}
|
||||
}
|
||||
|
||||
$report = $comment->report( $values['report_message'], ( isset( $values['report_type'] ) ) ? $values['report_type'] : 0, null, $guestDetails );
|
||||
File::claimAttachments( "report-{$class::$application}-{$class::$module}-{$item->$itemIdColumn}-{$comment->$idColumn}", $report->id );
|
||||
if ( Request::i()->isAjax() )
|
||||
{
|
||||
|
||||
+21
-2
@@ -1401,7 +1401,26 @@ abstract class Item extends Content
|
||||
}
|
||||
throw new BadMethodCallException;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get a shareable URL
|
||||
*
|
||||
* @param int|null $commentId
|
||||
* @return Url
|
||||
*/
|
||||
public function shareableUrl( int $commentId = NULL ): Url
|
||||
{
|
||||
$idColumn = static::$databaseColumnId;
|
||||
$url = $this->url();
|
||||
|
||||
if ( $commentId )
|
||||
{
|
||||
$url = $url->setFragment( 'findComment-' . $commentId );
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get mapped value
|
||||
*
|
||||
@@ -7165,7 +7184,7 @@ abstract class Item extends Content
|
||||
{
|
||||
$lock->addAttribute( 'data-ipsDialog')
|
||||
->addAttribute( 'data-ipsDialog-size', 'medium')
|
||||
->addAttribute( 'data-ipsDialog-title', 'lock')
|
||||
->addAttribute( 'data-ipsDialog-title', Member::loggedIn()->language()->addToStack( 'lock'))
|
||||
->addAttribute( 'data-ipsDialog-destructOnClose', 'true');
|
||||
}
|
||||
$menu->add( $lock );
|
||||
|
||||
@@ -619,6 +619,7 @@ class Tag extends Model
|
||||
|
||||
$this->text = sprintf( Member::loggedIn()->language()->get( 'copy_tag_text' ), $this->text );
|
||||
$this->text_seo = Friendly::seoTitle( $this->text );
|
||||
$this->totals = null;
|
||||
|
||||
parent::__clone();
|
||||
|
||||
|
||||
Reference in new issue
Block a user