Version 5.0.0 beta 1

This commit is contained in:
Neo committed 2025-12-19 16:27:35 -08:00
1 parent 25ddeb65d6
commit 15c7beabc5
6736 files changed
+627902 -497943

No files matched your search

@@ -12,56 +12,85 @@
namespace IPS\downloads\File;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use Exception;
use InvalidArgumentException;
use IPS\Api\Webhook;
use IPS\Content\Filter;
use IPS\Content\Hideable;
use IPS\Content\Item;
use IPS\Db;
use IPS\Dispatcher;
use IPS\downloads\File;
use IPS\File as SystemFile;
use IPS\Http\Url;
use IPS\Member;
use IPS\Output;
use IPS\Request;
use IPS\Session;
use OutOfRangeException;
use RuntimeException;
use UnderflowException;
use function count;
use function defined;
use function floatval;
use function is_array;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* PendingVersion Model
*/
class _PendingVersion extends \IPS\Content\Item implements \IPS\Content\Hideable
class PendingVersion extends Item implements Filter
{
use Hideable
{
Hideable::unhide as public _unhide;
}
/**
* @brief Application
*/
public static $application = 'downloads';
public static string $application = 'downloads';
/**
* @brief Module
*/
public static $module = 'downloads';
public static string $module = 'downloads';
/**
* @brief Database Table
*/
public static $databaseTable = 'downloads_files_pending';
public static ?string $databaseTable = 'downloads_files_pending';
/**
* @brief Database Prefix
*/
public static $databasePrefix = 'pending_';
public static string $databasePrefix = 'pending_';
/**
* @brief [ActiveRecord] ID Database Column
*/
public static $databaseColumnId = 'id';
public static string $databaseColumnId = 'id';
/**
* @brief [ActiveRecord] Database ID Fields
*/
protected static $databaseIdFields = array('pending_file_id');
protected static array $databaseIdFields = array('pending_file_id');
/**
* @brief Multiton Store
*/
protected static $multitons;
protected static array $multitons;
/**
* @brief Database Column Map
*/
public static $databaseColumnMap = array(
public static array $databaseColumnMap = array(
'author' => 'member_id',
'title' => 'name',
'date' => 'date',
@@ -71,41 +100,41 @@ class _PendingVersion extends \IPS\Content\Item implements \IPS\Content\Hideable
/**
* @brief Title
*/
public static $title = 'downloads_file_pending';
public static string $title = 'downloads_file_pending';
/**
* @brief Icon
*/
public static $icon = 'download';
public static string $icon = 'download';
/**
* @brief [Content] Key for hide reasons
*/
public static $hideLogKey = 'downloads-file-pending';
public static ?string $hideLogKey = 'downloads-file-pending';
/**
* @brief Used by the dataLayer
*/
public static $contentType = 'file';
public static string $contentType = 'file';
/**
* Can unhide?
*
* @param \IPS\Member|NULL $member The member to check for (NULL for currently logged in member)
* @param Member|NULL $member The member to check for (NULL for currently logged in member)
* @return boolean
*/
public function canUnhide( $member=NULL )
public function canUnhide( ?Member $member=NULL ): bool
{
return \IPS\downloads\File::modPermission( 'unhide', $member, $this->file()->containerWrapper() );
return File::modPermission( 'unhide', $member, $this->file()->containerWrapper() );
}
/**
* Can hide?
*
* @param \IPS\Member|NULL $member The member to check for (NULL for currently logged in member)
* @param Member|NULL $member The member to check for (NULL for currently logged in member)
* @return bool
*/
public function canHide( $member=NULL )
public function canHide( ?Member $member=NULL ): bool
{
return FALSE;
}
@@ -113,13 +142,12 @@ class _PendingVersion extends \IPS\Content\Item implements \IPS\Content\Hideable
/**
* Can delete pending version?
*
* @param \IPS\Member|NULL $member The member to check for (NULL for currently logged in member)
* @param Member|NULL $member The member to check for (NULL for currently logged in member)
* @return bool
*/
public function canDelete( $member=NULL )
public function canDelete( ?Member $member=NULL ): bool
{
$member = $member ?: \IPS\Member::loggedIn();
$member = $member ?: Member::loggedIn();
if( !$member->member_id )
{
return FALSE;
@@ -136,9 +164,9 @@ class _PendingVersion extends \IPS\Content\Item implements \IPS\Content\Hideable
/**
* Returns the content
*
* @return string
* @return string|null
*/
public function content()
public function content(): ?string
{
return $this->form_values['file_changelog'];
}
@@ -146,17 +174,17 @@ class _PendingVersion extends \IPS\Content\Item implements \IPS\Content\Hideable
/**
* @brief Cached URLs
*/
protected $_url = array();
protected mixed $_url = array();
/**
* Pending URL
*
* @param null|string $action 'do' action
* @return \IPS\Http\Url
* @param string|null $action 'do' action
* @return Url
*/
public function url( $action=NULL ): \IPS\Http\Url
public function url( string $action=NULL ): Url
{
$url = \IPS\Http\Url::internal( "app=downloads&module=downloads&controller=pending&file_id={$this->file()->id}&id={$this->id}", 'front', 'downloads_file_pending', $this->file()->name_furl );
$url = Url::internal( "app=downloads&module=downloads&controller=pending&file_id={$this->file()->id}&id={$this->id}", 'front', 'downloads_file_pending', $this->file()->name_furl );
if( $action )
{
@@ -169,7 +197,7 @@ class _PendingVersion extends \IPS\Content\Item implements \IPS\Content\Hideable
/**
* @brief store decoded form values
*/
protected $_formValues = NULL;
protected ?array $_formValues = NULL;
/**
* Get form values decoded
@@ -211,7 +239,7 @@ class _PendingVersion extends \IPS\Content\Item implements \IPS\Content\Hideable
*
* @return void
*/
public function setDefaultValues()
public function setDefaultValues() : void
{
$this->approved = 0;
}
@@ -221,7 +249,7 @@ class _PendingVersion extends \IPS\Content\Item implements \IPS\Content\Hideable
*
* @return void
*/
public function saveVersion()
public function saveVersion() : void
{
$this->save_version = 1;
}
@@ -231,19 +259,19 @@ class _PendingVersion extends \IPS\Content\Item implements \IPS\Content\Hideable
*
* @param array $values
*/
public function set_form_values( array $values )
public function set_form_values( array $values ) : void
{
foreach( $values as $k => $v )
{
if( $v instanceof \IPS\File )
if( $v instanceof SystemFile )
{
$values[ $k ] = (string) $v;
}
elseif( \is_array( $v ) )
elseif( is_array( $v ) )
{
foreach( $v as $_key => $_value )
{
if( $_value instanceof \IPS\File )
if( $_value instanceof SystemFile )
{
$values[ $k ][ $_key ] = (string) $_value;
}
@@ -260,7 +288,7 @@ class _PendingVersion extends \IPS\Content\Item implements \IPS\Content\Hideable
*
* @param array $ids
*/
public function set_record_deletions( array $ids )
public function set_record_deletions( array $ids ) : void
{
$this->_data['record_deletions'] = json_encode( $ids );
}
@@ -268,9 +296,9 @@ class _PendingVersion extends \IPS\Content\Item implements \IPS\Content\Hideable
/**
* Setter for download updated date
*
* @param $value New date
* @param int $value New date
*/
public function set_updated( $value )
public function set_updated( int $value ) : void
{
$this->date = $value;
}
@@ -279,13 +307,13 @@ class _PendingVersion extends \IPS\Content\Item implements \IPS\Content\Hideable
* Do Moderator Action
*
* @param string $action The action
* @param \IPS\Member|NULL $member The member doing the action (NULL for currently logged in member)
* @param Member|NULL $member The member doing the action (NULL for currently logged in member)
* @param string|NULL $reason Reason (for hides)
* @param bool $immediately Delete immediately
* @return void
* @throws \OutOfRangeException|\InvalidArgumentException|\RuntimeException
* @throws OutOfRangeException|InvalidArgumentException|RuntimeException
*/
public function modAction( $action, \IPS\Member $member = NULL, $reason = NULL, $immediately = FALSE )
public function modAction( string $action, ?Member $member = NULL, mixed $reason = NULL, bool $immediately=FALSE ): void
{
/* We always want to immediately delete these records instead of leaving them soft deleted */
if( $action === 'delete' )
@@ -294,15 +322,15 @@ class _PendingVersion extends \IPS\Content\Item implements \IPS\Content\Hideable
$this->delete();
/* Moderator log */
\IPS\Session::i()->modLog( 'modlog__action_newversion_reject', array( (string) $file->url() => FALSE, $file->name => FALSE ), $file );
Session::i()->modLog( 'modlog__action_newversion_reject', array( (string) $file->url() => FALSE, $file->name => FALSE ), $file );
if( \IPS\Dispatcher::hasInstance() AND !\IPS\Request::i()->isAjax() )
if( Dispatcher::hasInstance() AND !Request::i()->isAjax() )
{
\IPS\Output::i()->redirect( $file->url() );
Output::i()->redirect( $file->url() );
}
elseif( \IPS\Request::i()->isAjax() )
elseif( Request::i()->isAjax() )
{
\IPS\Output::i()->json( 'OK' );
Output::i()->json( 'OK' );
}
return;
@@ -310,23 +338,22 @@ class _PendingVersion extends \IPS\Content\Item implements \IPS\Content\Hideable
elseif( $action == 'approve' OR $action == 'unhide' )
{
/* Moderator log */
\IPS\Session::i()->modLog( 'modlog__action_newversion_approved', array( (string) $this->file()->url() => FALSE, $this->file()->name => FALSE ), $this->file() );
\IPS\Api\Webhook::fire( 'downloads_new_version_approved', $this );
Session::i()->modLog( 'modlog__action_newversion_approved', array( (string) $this->file()->url() => FALSE, $this->file()->name => FALSE ), $this->file() );
Webhook::fire( 'downloads_new_version_approved', $this );
}
return parent::modAction( $action, $member, $reason, $immediately );
parent::modAction( $action, $member, $reason, $immediately );
}
/**
* Delete Record
*
* @return void
* @return void
*/
public function delete()
public function delete(): void
{
$ids = [];
/* @note SELECT_FROM_WRITE_SERVER added in pull #6913 "We update record_hidden=0 then delete record_hidden=1 pretty quickly afterwards before the change had propagated to the reader." */
foreach( \IPS\Db::i()->select( '*', 'downloads_files_records', [ 'record_file_id=? AND record_hidden=1', $this->file_id ], NULL, NULL, NULL, NULL, \IPS\Db::SELECT_FROM_WRITE_SERVER ) as $record )
foreach( Db::i()->select( '*', 'downloads_files_records', [ 'record_file_id=? AND record_hidden=1', $this->file_id ], NULL, NULL, NULL, NULL, Db::SELECT_FROM_WRITE_SERVER ) as $record )
{
switch( $record['record_type'] )
{
@@ -337,12 +364,12 @@ class _PendingVersion extends \IPS\Content\Item implements \IPS\Content\Hideable
try
{
if( $record['record_type'] == 'ssupload' AND !empty( $record['record_thumb'] )
AND !\IPS\Db::i()->select( 'COUNT(record_id)', 'downloads_files_records', [ 'record_id<>? AND record_thumb=?', $record['record_id'], $record['record_thumb'] ] )->first() )
AND !Db::i()->select( 'COUNT(record_id)', 'downloads_files_records', [ 'record_id<>? AND record_thumb=?', $record['record_id'], $record['record_thumb'] ] )->first() )
{
\IPS\File::get( 'downloads_Screenshots', $record['record_thumb'] )->delete();
SystemFile::get( 'downloads_Screenshots', $record['record_thumb'] )->delete();
}
}
catch( \Exception $e ){}
catch( Exception $e ){}
break;
case 'link':
case 'sslink':
@@ -351,7 +378,7 @@ class _PendingVersion extends \IPS\Content\Item implements \IPS\Content\Hideable
}
}
if( \count( $ids ) )
if( count( $ids ) )
{
$this->file()->deleteRecords( $ids );
}
@@ -362,22 +389,22 @@ class _PendingVersion extends \IPS\Content\Item implements \IPS\Content\Hideable
/**
* Get related file object
*
* @return \IPS\downloads\File
* @return File
*/
public function file()
public function file(): File
{
return \IPS\downloads\File::load( $this->file_id );
return File::load( $this->file_id );
}
/**
* Unhide
*
* @param \IPS\Member|NULL $member The member doing the action (NULL for currently logged in member)
* @param Member|NULL $member The member doing the action (NULL for currently logged in member)
* @return void
*/
public function unhide( $member )
public function unhide( ?Member $member=NULL ) : void
{
$member = $member ?: \IPS\Member::loggedIn();
$member = $member ?: Member::loggedIn();
if( $this->save_version )
{
@@ -385,7 +412,7 @@ class _PendingVersion extends \IPS\Content\Item implements \IPS\Content\Hideable
}
/* Remove hidden flag */
\IPS\Db::i()->update( 'downloads_files_records', array( 'record_hidden' => 0 ), array( 'record_file_id=?', $this->file_id ) );
Db::i()->update( 'downloads_files_records', array( 'record_hidden' => 0 ), array( 'record_file_id=?', $this->file_id ) );
$deletions = $this->record_deletions;
$file = $this->file();
@@ -398,21 +425,19 @@ class _PendingVersion extends \IPS\Content\Item implements \IPS\Content\Hideable
{
try
{
\IPS\File::get( 'downloads_Screenshots', $url )->delete();
SystemFile::get( 'downloads_Screenshots', $url )->delete();
}
catch( \Exception $e ){}
catch( Exception $e ){}
}
/* @note SELECT_FROM_WRITE_SERVER race condition */
$file->size = \floatval( \IPS\Db::i()->select( 'SUM(record_size)', 'downloads_files_records', array( 'record_file_id=? AND record_type=? AND record_backup=0', $file->id, 'upload' ), NULL, NULL, NULL, NULL, \IPS\Db::SELECT_FROM_WRITE_SERVER )->first() );
$file->size = floatval( Db::i()->select( 'SUM(record_size)', 'downloads_files_records', array( 'record_file_id=? AND record_type=? AND record_backup=0', $file->id, 'upload' ), NULL, NULL, NULL, NULL, Db::SELECT_FROM_WRITE_SERVER )->first() );
/* Work out the new primary screenshot */
try
{
/* @note SELECT_FROM_WRITE_SERVER race condition */
$file->primary_screenshot = \IPS\Db::i()->select( 'record_id', 'downloads_files_records', array( 'record_file_id=? AND ( record_type=? OR record_type=? ) AND record_backup=0 AND record_hidden=0', $file->id, 'ssupload', 'sslink' ), 'record_default DESC, record_id ASC', NULL, NULL, NULL, \IPS\Db::SELECT_FROM_WRITE_SERVER )->first();
$file->primary_screenshot = Db::i()->select( 'record_id', 'downloads_files_records', array( 'record_file_id=? AND ( record_type=? OR record_type=? ) AND record_backup=0 AND record_hidden=0', $file->id, 'ssupload', 'sslink' ), 'record_default DESC, record_id ASC', NULL, NULL, NULL, Db::SELECT_FROM_WRITE_SERVER )->first();
}
catch ( \UnderflowException $e ) { }
catch ( UnderflowException $e ) { }
/* The container may not have versions enabled */
if( !empty( $this->form_values['file_version'] ) )
@@ -445,12 +470,12 @@ class _PendingVersion extends \IPS\Content\Item implements \IPS\Content\Hideable
/**
* Save Changed Columns
*
* @return void
* @return void
*/
public function save()
public function save(): void
{
parent::save();
\IPS\File::claimAttachments( "downloads-{$this->file_id}-changelog", $this->file_id, $this->id, 'changelogpending' );
SystemFile::claimAttachments( "downloads-{$this->file_id}-changelog", $this->file_id, $this->id, 'changelogpending' );
}
}