Version 4.3.0

This commit is contained in:
Neo committed 2025-12-19 05:47:12 -08:00
1 parent 96997ddd8e
commit fe1acf984a
1349 files changed
+116159 -67711

No files matched your search

@@ -23,6 +23,30 @@ if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
*/
class _browse extends \IPS\Dispatcher\Controller
{
/**
* Mark Read
*
* @return void
*/
protected function markRead()
{
\IPS\Session::i()->csrfCheck();
try
{
$category = \IPS\downloads\Category::load( \IPS\Request::i()->id );
\IPS\downloads\File::markContainerRead( $category, NULL, FALSE );
\IPS\Output::i()->redirect( $category->url() );
}
catch ( \OutOfRangeException $e )
{
\IPS\Output::i()->error( 'no_module_permission', '2D175/3', 403, 'no_module_permission_guest' );
}
}
/**
* Route
*
@@ -37,13 +61,24 @@ class _browse extends \IPS\Dispatcher\Controller
if ( isset( \IPS\Request::i()->id ) )
{
try
if ( \IPS\Request::i()->id == 'clubs' and \IPS\Settings::i()->club_nodes_in_apps )
{
$this->_category( \IPS\downloads\Category::loadAndCheckPerms( \IPS\Request::i()->id, 'read' ) );
\IPS\Session::i()->setLocation( \IPS\Http\Url::internal( 'app=downloads&module=downloads&controller=browse&do=categories', 'front', 'downloads_categories' ), array(), 'loc_downloads_browsing_categories' );
\IPS\Output::i()->breadcrumb[] = array( \IPS\Http\Url::internal( 'app=downloads&module=downloads&controller=browse&do=categories', 'front', 'downloads_categories' ), \IPS\Member::loggedIn()->language()->addToStack('download_categories') );
\IPS\Output::i()->breadcrumb[] = array( \IPS\Http\Url::internal( 'app=downloads&module=downloads&controller=browse&id=clubs', 'front', 'downloads_clubs' ), \IPS\Member::loggedIn()->language()->addToStack('club_node_downloads') );
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('club_node_downloads');
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'browse' )->categories( TRUE );
}
catch ( \OutOfRangeException $e )
else
{
\IPS\Output::i()->error( 'node_error', '2D175/1', 404, '' );
try
{
$this->_category( \IPS\downloads\Category::loadAndCheckPerms( \IPS\Request::i()->id, 'read' ) );
}
catch ( \OutOfRangeException $e )
{
\IPS\Output::i()->error( 'node_error', '2D175/1', 404, '' );
}
}
}
else
@@ -66,7 +101,7 @@ class _browse extends \IPS\Dispatcher\Controller
}
/* Get stuff */
$featured = (\IPS\Settings::i()->idm_show_featured) ? iterator_to_array(\IPS\downloads\File::featured(\IPS\Settings::i()->idm_featured_count, '_rand')) : array();
$featured = \IPS\Settings::i()->idm_show_featured ? iterator_to_array( \IPS\downloads\File::featured( \IPS\Settings::i()->idm_featured_count, '_rand' ) ) : array();
if ( \IPS\Settings::i()->idm_newest_categories )
{
@@ -76,6 +111,10 @@ class _browse extends \IPS\Dispatcher\Controller
{
$newestWhere = array( array( 'downloads_categories.copen=1' ) );
}
if ( !\IPS\Settings::i()->club_nodes_in_apps )
{
$newestWhere[] = array( 'downloads_categories.cclub_id IS NULL' );
}
$new = ( \IPS\Settings::i()->idm_show_newest) ? \IPS\downloads\File::getItemsWithPermission( $newestWhere, NULL, 14, 'read', \IPS\Content\Hideable::FILTER_AUTOMATIC, 0, NULL, TRUE ) : array();
@@ -88,6 +127,10 @@ class _browse extends \IPS\Dispatcher\Controller
$highestWhere = array( array( 'downloads_categories.copen=1' ) );
}
$highestWhere[] = array( 'file_rating > ?', 0 );
if ( !\IPS\Settings::i()->club_nodes_in_apps )
{
$highestWhere[] = array( 'downloads_categories.cclub_id IS NULL' );
}
$highestRated = ( \IPS\Settings::i()->idm_show_highest_rated ) ? \IPS\downloads\File::getItemsWithPermission( $highestWhere, 'file_rating DESC, file_reviews DESC', 14, 'read', \IPS\Content\Hideable::FILTER_AUTOMATIC, 0, NULL, TRUE ) : array();
if (\IPS\Settings::i()->idm_show_most_downloaded_categories )
@@ -99,6 +142,10 @@ class _browse extends \IPS\Dispatcher\Controller
$mostDownloadedWhere = array( array( 'downloads_categories.copen=1' ) );
}
$mostDownloadedWhere[] = array( 'downloads_categories.copen=1 and file_downloads > ?', 0 );
if ( !\IPS\Settings::i()->club_nodes_in_apps )
{
$mostDownloadedWhere[] = array( 'downloads_categories.cclub_id IS NULL' );
}
$mostDownloaded = ( \IPS\Settings::i()->idm_show_most_downloaded ) ? \IPS\downloads\File::getItemsWithPermission( $mostDownloadedWhere, 'file_downloads DESC', 14, 'read', \IPS\Content\Hideable::FILTER_AUTOMATIC, 0, NULL, TRUE ) : array();
/* Online User Location */
@@ -168,7 +215,7 @@ class _browse extends \IPS\Dispatcher\Controller
unset( $table->sortOptions['num_comments'] );
}
if ( $table->sortBy === 'file_name' )
if ( $table->sortBy === 'downloads_files.file_title' )
{
$table->sortDirection = 'asc';
}
@@ -189,7 +236,6 @@ class _browse extends \IPS\Dispatcher\Controller
/* Output */
\IPS\Output::i()->title = $category->_title;
\IPS\Output::i()->contextualSearchOptions[ \IPS\Member::loggedIn()->language()->addToStack( 'search_contextual_item_downloads_categories' ) ] = array( 'type' => 'downloads_file', 'nodes' => $category->_id );
\IPS\Output::i()->sidebar['contextual'] .= \IPS\Theme::i()->getTemplate( 'browse' )->indexSidebar( \IPS\downloads\Category::canOnAny('add'), $category );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'browse' )->category( $category, (string) $table );
@@ -205,8 +251,9 @@ class _browse extends \IPS\Dispatcher\Controller
/* Online User Location */
\IPS\Session::i()->setLocation( \IPS\Http\Url::internal( 'app=downloads&module=downloads&controller=browse&do=categories', 'front', 'downloads_categories' ), array(), 'loc_downloads_browsing_categories' );
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('downloads_categories_pagetitle');
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'browse' )->categories();
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('downloads_categories_pagetitle');
\IPS\Output::i()->breadcrumb[] = array( \IPS\Http\Url::internal( 'app=downloads&module=downloads&controller=browse&do=categories', 'front', 'downloads_categories' ), \IPS\Member::loggedIn()->language()->addToStack('download_categories') );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'browse' )->categories();
}
/**
@@ -32,8 +32,6 @@ class _submit extends \IPS\Dispatcher\Controller
{
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'front_submit.js', 'downloads', 'front' ) );
\IPS\downloads\File::canCreate( \IPS\Member::loggedIn(), NULL, TRUE );
parent::execute();
}
@@ -50,6 +48,7 @@ class _submit extends \IPS\Dispatcher\Controller
'url' => \IPS\Http\Url::internal( 'app=downloads&module=downloads&controller=submit', 'front', 'downloads_submit' ),
'class' => 'IPS\downloads\Category',
'permissionCheck' => 'add',
'clubs' => \IPS\Settings::i()->club_nodes_in_apps
) ) );
if ( \IPS\Member::loggedIn()->group['idm_bulk_submit'] )
@@ -110,7 +109,7 @@ class _submit extends \IPS\Dispatcher\Controller
$form->class = 'ipsForm_vertical';
$form->hiddenValues['category'] = $category->_id;
$form->hiddenValues['postKey'] = ( \IPS\Request::i()->postKey ) ? \IPS\Request::i()->postKey : md5( uniqid() );
$form->hiddenValues['postKey'] = ( \IPS\Request::i()->postKey ) ? \IPS\Request::i()->postKey : md5( mt_rand() );
/* Populate any existing records */
$files = array();
@@ -236,6 +235,8 @@ class _submit extends \IPS\Dispatcher\Controller
}
if ( isset( $values['import_files'] ) )
{
\IPS\File::$copyFiles = TRUE;
foreach ( $values['import_files'] as $path )
{
$file = \IPS\File::create( 'downloads_Files', mb_substr( $path, mb_strrpos( $path, DIRECTORY_SEPARATOR ) + 1 ), NULL, NULL, FALSE, $path );
@@ -254,6 +255,8 @@ class _submit extends \IPS\Dispatcher\Controller
}
$k++;
}
\IPS\File::$copyFiles = FALSE;
}
if ( isset( $values['url_files'] ) )
{
@@ -371,7 +374,7 @@ class _submit extends \IPS\Dispatcher\Controller
if( $file->author()->member_id OR $file->canView() )
{
$url = $file->url();
$message = NULL;
$message = ( isset( $values['import_files'] ) AND count( $values['import_files'] ) ) ? \IPS\Member::loggedIn()->language()->addToStack('file_imported_removed') : NULL;
}
else
{
@@ -401,7 +404,7 @@ class _submit extends \IPS\Dispatcher\Controller
/**
* Step 2: File information (for bulk uploads only)
*/
$steps['file_information'] = function ($data)
$steps['file_information'] = function ( $data )
{
/* Get Category */
try
@@ -420,8 +423,18 @@ class _submit extends \IPS\Dispatcher\Controller
{
/* Header */
$file = \IPS\File::get( 'downloads_Files', $file );
$form->addTab( $file->originalFilename );
$form->addHeader( $file->originalFilename );
try
{
$displayName = \IPS\Db::i()->select( 'record_realname', 'downloads_files_records', array( 'record_location=?', (string) $file ) )->first();
}
catch( \UnderflowException $e )
{
$displayName = $file->originalFilename;
}
$form->addTab( $displayName );
$form->addHeader( $displayName );
/* Form Elements */
foreach ( \IPS\downloads\File::formElements( NULL, $category ) as $input )
@@ -430,7 +443,7 @@ class _submit extends \IPS\Dispatcher\Controller
if ( !$input->value and in_array( $input->name, array( 'file_title', 'file_desc' ) ) )
{
$input->value = $file->originalFilename;
$input->value = $displayName;
}
$input->name = "filedata_{$key}_{$input->name}";
@@ -121,19 +121,19 @@ class _view extends \IPS\Content\Controller
/* Add JSON-ld */
\IPS\Output::i()->jsonLd['download'] = array(
'@context' => "http://schema.org",
'@type' => "SoftwareApplication",
'@type' => "WebApplication",
"operatingSystem" => "N/A",
'url' => (string) $this->file->url(),
'name' => htmlspecialchars( $this->file->mapped('title'), ENT_QUOTES | \IPS\HTMLENTITIES, 'UTF-8', FALSE ),
'name' => $this->file->mapped('title'),
'description' => strip_tags( $this->file->truncated() ),
'applicationCategory' => $this->file->container()->_title,
'downloadUrl' => (string) $this->file->url( 'download' ),
'dateCreated' => \IPS\DateTime::ts( $this->file->submitted )->format( \IPS\DateTime::ISO8601 ),
'fileSize' => \IPS\Output\Plugin\Filesize::humanReadableFilesize( $this->file->filesize() ),
'softwareVersion' => htmlspecialchars( $this->file->version, ENT_QUOTES | \IPS\HTMLENTITIES, 'UTF-8', FALSE ),
'softwareVersion' => $this->file->version,
'author' => array(
'@type' => 'Person',
'name' => htmlspecialchars( \IPS\Member::load( $this->file->submitter )->name, ENT_QUOTES | \IPS\HTMLENTITIES, 'UTF-8', FALSE ),
'url' => (string) \IPS\Member::load( $this->file->submitter )->url(),
'name' => \IPS\Member::load( $this->file->submitter )->name,
'image' => \IPS\Member::load( $this->file->submitter )->get_photo()
),
'interactionStatistic' => array(
@@ -150,12 +150,18 @@ class _view extends \IPS\Content\Controller
)
);
/* Do we have a real author? */
if( $this->file->submitter )
{
\IPS\Output::i()->jsonLd['download']['author']['url'] = (string) \IPS\Member::load( $this->file->submitter )->url();
}
if( $this->file->updated != $this->file->submitted )
{
\IPS\Output::i()->jsonLd['download']['dateModified'] = \IPS\DateTime::ts( $this->file->updated )->format( \IPS\DateTime::ISO8601 );
}
if( $this->file->container()->bitoptions['reviews'] )
if( $this->file->container()->bitoptions['reviews'] AND $this->file->reviews )
{
\IPS\Output::i()->jsonLd['download']['aggregateRating'] = array(
'@type' => 'AggregateRating',
@@ -201,10 +207,18 @@ class _view extends \IPS\Content\Controller
'target' => (string) $this->file->url( 'buy' ),
);
/* Get the price */
$price = $this->file->price();
if( $price instanceof \IPS\nexus\Money )
{
$price = $price->amountAsString();
}
\IPS\Output::i()->jsonLd['download']['offers'] = array(
'@type' => 'Offer',
'url' => (string) $this->file->url( 'buy' ),
'price' => $this->file->price(),
'price' => $price,
'priceCurrency' => \IPS\nexus\Customer::loggedIn()->defaultCurrency(),
'availability' => "http://schema.org/InStock"
);
@@ -235,6 +249,34 @@ class _view extends \IPS\Content\Controller
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'view' )->view( $this->file, $commentsAndReviews, $versionData, $previousVersions, $this->file->nextItem(), $this->file->prevItem(), $cfields );
}
/**
* Purchase Status
*
* @return void
*/
public function purchaseStatus()
{
\IPS\Session::i()->csrfCheck();
if ( \IPS\Request::i()->value )
{
$method = 'canEnablePurchases';
}
else
{
$method = 'canDisablePurchases';
}
if ( !$this->file->$method() )
{
\IPS\Output::i()->error( 'no_module_permission', '2D161/L', 403, '' );
}
$this->file->purchasable = (bool) \IPS\Request::i()->value;
$this->file->save();
\IPS\Output::i()->redirect( $this->file->url(), 'saved' );
}
/**
* Buy file
*
@@ -250,6 +292,11 @@ class _view extends \IPS\Content\Controller
\IPS\Output::i()->error( 'no_module_permission', '2D161/E', 403, '' );
}
if ( !$this->file->isPurchasable() )
{
\IPS\Output::i()->error( 'no_module_permission', '2D161/K', 403, '' );
}
/* Is it associated with a Nexus product? */
if ( $this->file->nexus )
{
@@ -339,6 +386,7 @@ class _view extends \IPS\Content\Controller
\IPS\Output::i()->redirect( $this->file->url() );
}
\IPS\Output::i()->metaTags['robots'] = 'noindex';
\IPS\Session::i()->csrfCheck();
}
@@ -465,7 +513,7 @@ class _view extends \IPS\Content\Controller
'dmid' => (int) \IPS\Member::loggedIn()->member_id,
'dsize' => $data['record_size'],
'dua' => \IPS\Session::i()->userAgent->useragent,
'dbrowsers' => \IPS\Session::i()->userAgent->browser,
'dbrowsers' => \IPS\Session::i()->userAgent->browser ?: '',
'dos' => ''
) );
}
@@ -519,6 +567,10 @@ class _view extends \IPS\Content\Controller
'dsess_file' => $this->file->id,
'dsess_start' => time()
) );
/* If a user aborts the connection the shutdown function is not executed, and we need it to be */
ignore_user_abort( true );
register_shutdown_function( function() use( $downloadSessionId ) {
\IPS\Db::i()->delete( 'downloads_sessions', array( 'dsess_id=?', $downloadSessionId ) );
} );
@@ -530,7 +582,16 @@ class _view extends \IPS\Content\Controller
}
/* Print the file, honoring ranges */
$ranges = new \IPS\Http\Ranges( $file, (int) \IPS\Member::loggedIn()->group['idm_throttling'] );
try
{
$ranges = new \IPS\Http\Ranges( $file, (int) \IPS\Member::loggedIn()->group['idm_throttling'] );
}
catch( \RuntimeException $e )
{
\IPS\Log::log( $e, 'file_download' );
\IPS\Output::i()->error( 'downloads_no_file', '4D161/J', 403, '' );
}
/* If using PHP-FPM, close the request so that __destruct tasks are run after data is flushed to the browser
@see http://www.php.net/manual/en/function.fastcgi-finish-request.php */
@@ -992,7 +1053,7 @@ class _view extends \IPS\Content\Controller
{
try
{
$existing = \IPS\Db::i()->select( '*', 'downloads_files_records', array( "record_location=? AND record_file_id=?", (string) $file, $this->file->id ) )->first();
$existing = \IPS\Db::i()->select( '*', 'downloads_files_records', array( "record_location=? AND record_file_id=?", (string) $file, $this->file->id ), NULL, NULL, NULL, NULL, \IPS\Db::SELECT_FROM_WRITE_SERVER )->first();
}
catch( \UnderflowException $e ) {}
}
@@ -1072,12 +1133,12 @@ class _view extends \IPS\Content\Controller
/* Set the new details */
$this->file->version = $values['file_version'];
$this->file->changelog = $values['file_changelog'];
$this->file->size = floatval( \IPS\Db::i()->select( 'SUM(record_size)', 'downloads_files_records', array( 'record_file_id=? AND record_type=? AND record_backup=0', $this->file->id, 'upload' ) )->first() );
$this->file->size = floatval( \IPS\Db::i()->select( 'SUM(record_size)', 'downloads_files_records', array( 'record_file_id=? AND record_type=? AND record_backup=0', $this->file->id, 'upload' ), NULL, NULL, NULL, NULL, \IPS\Db::SELECT_FROM_WRITE_SERVER )->first() );
/* Work out the new primary screenshot */
try
{
$this->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', $this->file->id, 'ssupload', 'sslink' ), 'record_default DESC, record_id ASC' )->first();
$this->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', $this->file->id, 'ssupload', 'sslink' ), 'record_default DESC, record_id ASC', NULL, NULL, NULL, \IPS\Db::SELECT_FROM_WRITE_SERVER )->first();
}
catch ( \UnderflowException $e ) { }