Version 5.0.0 beta 4

This commit is contained in:
Neo committed 2025-12-19 16:57:00 -08:00
1 parent e86153356a
commit 2f24f9de48
276 files changed
+8614 -6044

No files matched your search

+223 -15
View File
@@ -14,6 +14,7 @@ namespace IPS\core\Reports;
use Exception;
use InvalidArgumentException;
use IPS\Application;
use IPS\Content;
use IPS\Content\Comment;
use IPS\Content\Item;
@@ -21,10 +22,13 @@ use IPS\Content\ReadMarkers;
use IPS\core\Reports\Comment as ReportComment;
use IPS\DateTime;
use IPS\Db;
use IPS\Email;
use IPS\Http\Url;
use IPS\IPS;
use IPS\Log;
use IPS\Member;
use IPS\Node\Model;
use IPS\Notification;
use IPS\Session;
use IPS\Settings;
use IPS\Theme;
@@ -53,7 +57,14 @@ class Report extends Item
* @brief Const No type selected
*/
const TYPE_MESSAGE = 0;
/**
* @brief Const Reported content statuses
*/
const STATUS_NEW = 1;
const STATUS_OPEN = 2;
const STATUS_CLOSED = 3;
const STATUS_REJECTED = 4;
/* !\IPS\Patterns\ActiveRecord */
@@ -137,7 +148,210 @@ class Report extends Item
* @var bool
*/
public static bool $skipIndexNow = TRUE;
/**
* Get all the report types for this report index
*
* @return array
*/
public function getReportedTypes(): array
{
$reportedTypes = [];
$reportTypes = [];
foreach ( Types::roots() as $type )
{
$reportTypes[ $type->id ] = $type->_title;
}
foreach ( Db::i()->select( '*', 'core_rc_reports', ['rid=? and report_type > 0', $this->id] ) as $report )
{
if ( isset( $reportTypes[ $report['report_type'] ] ) )
{
$reportedTypes[ $report['report_type'] ] = $reportTypes[ $report['report_type'] ];
}
}
return $reportedTypes;
}
/**
* Set the status of the report
*
* @param int $status
* @param int $authorNotification
* @param null $member
* @return void
*/
public function changeStatus( int $status, int $authorNotification=0, $member=null ): void
{
$member = $member ?: Member::loggedIn();
$this->status = $status;
$this->save();
/* We only need to notify if there is an outcome */
if ( $status == static::STATUS_CLOSED or static::STATUS_REJECTED )
{
$forNotifications = [];
$forEmails = [];
/* Now go through all the individual reports and see if we need to notify anyone */
foreach ( Db::i()->select( '*', 'core_rc_reports', ['rid=?', $this->id] ) as $report )
{
if ( !$report['report_type'] )
{
/* We have not selected a reason, no nothing to worry about */
continue;
}
/* Get the report type object */
try
{
$reportType = Types::load( $report['report_type'] );
$reportMember = Member::load( $report['report_by'] );
}
catch ( \Exception $e )
{
continue;
}
if ( $report['report_by'] )
{
/* We have a member */
$forNotifications[$report['report_type']][] = [$reportMember, $reportType, $report];
}
else
{
if ( $report['guest_email'] )
{
/* We have an email */
$forEmails[$report['report_type']][] = [$reportType, $report];
}
}
}
/* Members */
foreach ( $forNotifications as $typeId => $data )
{
foreach ( $data as $reportData )
{
$reportMember = $reportData[0];
$reportType = $reportData[1];
$userReport = $reportData[2];
if ( $this->getReportOutcomeBlurb( $userReport['id'] ) )
{
$notification = new Notification( Application::load( 'core' ), 'report_outcome', $this, [$this, $reportType, $userReport], ['reportType' => $reportType->id, 'userReport' => $userReport] );
$notification->recipients->attach( $reportMember );
$notification->send();
Log::debug( "Sent notification to {$reportMember->name}", 'reports_notification' );
}
}
}
/* Guests */
foreach ( $forEmails as $typeId => $data )
{
foreach ( $data as $reportData )
{
$reportType = $reportData[0];
$guestEmail = $reportData[1]['guest_email'];
$userReport = $reportData[1];
if ( $guestEmail and $this->getReportOutcomeBlurb( $userReport['id'] ) )
{
Email::buildFromTemplate( 'core', 'notification_report_outcome', [$this, $reportType, $userReport], Email::TYPE_LIST )->send( $guestEmail );
}
}
}
/* Content author? */
if ( $authorNotification )
{
try
{
$class = $this->_data['class'];
$thing = $class::load( $this->_data['content_id'] );
$content = ( $thing instanceof Comment ) ? $thing->truncated() : $thing->mapped( 'title' );
if ( $thing->author() and $thing->author()->email )
{
$authorContent = static::getAuthorNotifications();
if ( isset( $authorContent[ $authorNotification ] ) )
{
$notificationContent = $authorContent[$authorNotification]['text'];
/* Substitutions */
$subs = [
'name' => $thing->author()->name,
'content' => trim( $content ),
'link' => (string) $thing->url(),
'reason' => implode( ', ', $this->getReportedTypes() )
];
foreach( $subs as $key => $value )
{
$notificationContent = str_replace( '{' . $key . '}', $value, $notificationContent );
}
Email::buildFromTemplate( 'core', 'notification_report_content_author', [$this, $thing, $notificationContent], Email::TYPE_LIST )->send( $thing->author()->email );
}
}
}
catch ( \Exception $e ) { }
}
}
/* Post a comment on the report */
$content = $member->language()->addToStack( 'update_report_status_content', FALSE, array( 'sprintf' => array( $member->language()->addToStack( 'report_status_' . $this->status ) ) ) );
$member->language()->parseOutputForDisplay( $content );
$comment = ReportComment::create( $this, $content, TRUE, NULL, NULL, $member, new DateTime );
$comment->save();
/* And add to the moderator log */
Session::i()->modLog( 'modlog__action_update_report_status', array( $this->url()->__toString() => FALSE ) );
}
/**
* Get the author notifications
*
* @return array
*/
public static function getAuthorNotifications(): array
{
$return = [];
foreach( \IPS\Db::i()->select( '*', 'core_rc_author_notification_text', [], 'title ASC' ) as $row )
{
$return[ $row['id'] ] = $row;
}
return $return;
}
/**
* Get the report outcome blurb
*
* @param int $userReportId
* @return string
*/
public function getReportOutcomeBlurb( int $userReportId ): string
{
try
{
$userReport = Db::i()->select( '*', 'core_rc_reports', array( 'id=?', $userReportId ) )->first();
$reportType = Types::load( $userReport['report_type'] );
return $this->status === static::STATUS_REJECTED ? $reportType->getRejectedNotificationText( Member::load( $userReport['report_by'] ) ) : $reportType->getCompletedNotificationText( Member::load( $userReport['report_by'] ) );
}
catch( \Exception $e )
{
return '';
}
}
/**
* Should posting this increment the poster's post count?
*
@@ -389,18 +603,7 @@ class Report extends Item
{
if ( mb_substr( $action, 0, -1 ) === 'report_status_' )
{
$this->status = mb_substr( $action, -1 );
$this->save();
/* Post a comment on the report */
$content = Member::loggedIn()->language()->addToStack( 'update_report_status_content', FALSE, array( 'sprintf' => array( Member::loggedIn()->language()->addToStack( 'report_status_' . $this->status ) ) ) );
Member::loggedIn()->language()->parseOutputForDisplay( $content );
$comment = ReportComment::create( $this, $content, true, null, null, Member::loggedIn(), new DateTime );
$comment->save();
/* And add to the moderator log */
Session::i()->modLog( 'modlog__action_update_report_status', array( $this->url()->__toString() => FALSE ) );
$this->changeStatus( (int) mb_substr( $action, -1 ) );
}
else
{
@@ -415,7 +618,7 @@ class Report extends Item
*/
public function customMultimodActions(): array
{
return array_diff( array( 'report_status_1', 'report_status_2', 'report_status_3', ), array( 'report_status_' . $this->status ) );
return array_diff( array( 'report_status_1', 'report_status_2', 'report_status_3', 'report_status_4'), array( 'report_status_' . $this->status ) );
}
/**
@@ -446,6 +649,11 @@ class Report extends Item
'action' => 'report_status_3',
'icon' => 'check-circle',
'label' => 'report_status_3'
),
array(
'action' => 'report_status_4',
'icon' => 'archive',
'label' => 'report_status_4'
)
)
)
+31 -3
View File
@@ -80,7 +80,30 @@ class Types extends Model
* @brief [Node] Title prefix. If specified, will look for a language key with "{$key}_title" as the key
*/
public static ?string $titleLangPrefix = 'automaticmod_types_';
/**
* Get the completed notification text (hits the DB to get the real value, not the hash key)
* @param Member|null $member
* @return string
*/
public function getCompletedNotificationText( \IPS\Member|null $member=null ): string
{
$member = $member ?: \IPS\Member::loggedIn();
return $member->language()->get( 'automaticmod_types_notify_complete_' . $this->id, 'core' );
}
/**
* Get the rejected notification text (hits the DB to get the real value, not the hash key)
* @param Member|null $member
* @return string
*/
public function getRejectedNotificationText( \IPS\Member|null $member=null ): string
{
$member = $member ?: \IPS\Member::loggedIn();
return $member->language()->get( 'automaticmod_types_notify_reject_' . $this->id, 'core' );
}
/**
* Form
*
@@ -90,6 +113,8 @@ class Types extends Model
public function form( Form &$form ) : void
{
$form->add( new Translatable( 'automaticmod_types_title', NULL, TRUE, array( 'app' => 'core', 'key' => ( $this->id ? 'automaticmod_types_' . $this->id : NULL ) ) ) );
$form->add( new Translatable( 'automaticmod_types_notify_complete', NULL, FALSE, array( 'textArea' => true, 'app' => 'core', 'key' => ( $this->id ? 'automaticmod_types_notify_complete_' . $this->id : NULL ) ) ) );
$form->add( new Translatable( 'automaticmod_types_notify_reject', NULL, FALSE, array( 'textArea' => true, 'app' => 'core', 'key' => ( $this->id ? 'automaticmod_types_notify_reject_' . $this->id : NULL ) ) ) );
}
/**
@@ -107,8 +132,11 @@ class Types extends Model
/* Save the title */
Lang::saveCustom( 'core', 'automaticmod_types_' . $this->id, $values['automaticmod_types_title'] );
unset( $values['automaticmod_types_title'] );
/* Save the notification text */
Lang::saveCustom( 'core', 'automaticmod_types_notify_complete_' . $this->id, $values['automaticmod_types_notify_complete'] );
Lang::saveCustom( 'core', 'automaticmod_types_notify_reject_' . $this->id, $values['automaticmod_types_notify_reject'] );
unset( $values['automaticmod_types_title'], $values['automaticmod_types_notify_complete'], $values['automaticmod_types_notify_reject'] );
return parent::formatFormValues( $values );
}