Version 4.2.0

This commit is contained in:
Neo committed 2025-12-19 05:44:59 -08:00
1 parent 0dc2aee5ed
commit 96997ddd8e
2074 files changed
+125454 -55780

No files matched your search

+266 -31
View File
@@ -1,13 +1,12 @@
<?php
/**
* @brief Records Model
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Community Suite
* @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
* @subpackage Content
* @since 8 April 2014
* @version SVN_VERSION_NUMBER
*/
namespace IPS\cms;
@@ -28,15 +27,17 @@ class _Records extends \IPS\Content\Item implements
\IPS\Content\Tags,
\IPS\Content\Followable,
\IPS\Content\Shareable,
\IPS\Content\Reputation,
\IPS\Content\ReportCenter,
\IPS\Content\ReadMarkers,
\IPS\Content\Views,
\IPS\Content\Ratings,
\IPS\Content\Searchable,
\IPS\Content\FuturePublishing,
\IPS\Content\Embeddable
\IPS\Content\Embeddable,
\IPS\Content\MetaData
{
use \IPS\Content\Reactable;
/**
* @brief Multiton Store
*/
@@ -131,11 +132,6 @@ class _Records extends \IPS\Content\Item implements
* @brief Icon
*/
public static $icon = 'file-text';
/**
* @brief Reputation Type
*/
public static $reputationType = NULL;
/**
* @brief Include In Sitemap (We do not want to include in Content sitemap, as we have a custom extension
@@ -758,7 +754,7 @@ class _Records extends \IPS\Content\Item implements
{
$this->record_approved = -1;
}
else
else if ( $this->record_approved !== 0 )
{
$this->record_approved = 1;
}
@@ -1034,6 +1030,71 @@ class _Records extends \IPS\Content\Item implements
\IPS\File::claimAttachments( 'RecordField_' . ( $isNew ? 'new' : $this->_id ) . '_' . $row->id, $this->primary_id_field, $id, static::$customDatabaseId );
}
if ( $row->can( ( $isNew ? 'add' : 'edit' ) ) and $row->type == 'Upload' )
{
if ( $row->extra['type'] == 'image' and isset( $row->extra['thumbsize'] ) )
{
$dims = $row->extra['thumbsize'];
$field = 'field_' . $row->id;
$extra = $row->extra;
$thumbs = iterator_to_array( \IPS\Db::i()->select( '*', 'cms_database_fields_thumbnails', array( array( 'thumb_field_id=?', $row->id ) ) )->setKeyField('thumb_original_location')->setValueField('thumb_location') );
if ( $this->$field )
{
foreach( explode( ',', $this->$field ) as $img )
{
try
{
$original = \IPS\File::get( 'cms_Records', $img );
try
{
$thumb = $original->thumbnail( 'cms_Records', $dims[0], $dims[1] );
if ( isset( $thumbs[ (string) $original ] ) )
{
\IPS\Db::i()->delete( 'cms_database_fields_thumbnails', array( array( 'thumb_original_location=? and thumb_field_id=?', (string) $original, $row->id ) ) );
try
{
\IPS\File::get( 'cms_Records', $thumbs[ (string) $original ] )->delete();
}
catch ( \Exception $e ) { }
}
\IPS\Db::i()->insert( 'cms_database_fields_thumbnails', array(
'thumb_original_location' => (string) $original,
'thumb_location' => (string) $thumb,
'thumb_field_id' => $row->id,
'thumb_database_id' => static::$customDatabaseId
) );
}
catch ( \Exception $e ) { }
}
catch ( \Exception $e ) { }
}
/* Remove any thumbnails if the original has been removed */
$orphans = iterator_to_array( \IPS\Db::i()->select( '*', 'cms_database_fields_thumbnails', array( array( 'thumb_field_id=?', $row->id ), array( \IPS\Db::i()->in( 'thumb_original_location', explode( ',', $this->$field ), TRUE ) ) ) ) );
if ( count( $orphans ) )
{
foreach( $orphans as $thumb )
{
try
{
\IPS\File::get( 'cms_Records', $thumb['thumb_location'] )->delete();
}
catch ( \Exception $e ) { }
}
\IPS\Db::i()->delete( 'cms_database_fields_thumbnails', array( array( 'thumb_field_id=?', $row->id ), array( \IPS\Db::i()->in( 'thumb_original_location', explode( ',', $this->$field ), TRUE ) ) ) );
}
}
}
}
if ( $row->can( ( $isNew ? 'add' : 'edit' ) ) and $row->type == 'Item' )
{
\IPS\Db::i()->delete( 'cms_database_fields_reciprocal_map', array( 'map_origin_database_id=? and map_field_id=? and map_origin_item_id=?', static::$customDatabaseId, $row->id, $this->_id ) );
@@ -1303,6 +1364,70 @@ class _Records extends \IPS\Content\Item implements
return $fields;
}
/**
* Returns the content images
*
* @param int|null $limit Number of attachments to fetch, or NULL for all
*
* @return array|NULL If array, then array( 'core_Attachment' => 'month_x/foo.gif', ... );
* @throws \BadMethodCallException
*/
public function contentImages( $limit = NULL )
{
$idColumn = static::$databaseColumnId;
$attachments = array();
$internal = \IPS\Db::i()->select( 'attachment_id', 'core_attachments_map', array( 'location_key=? and id1=? and id3=?', 'cms_Records', $this->$idColumn, static::$customDatabaseId ) );
/* Attachments */
foreach( \IPS\Db::i()->select( '*', 'core_attachments', array( array( 'attach_id IN(?)', $internal ), array( 'attach_is_image=1' ) ), 'attach_id ASC', $limit ) as $row )
{
$attachments[] = array( 'core_Attachment' => $row['attach_location'] );
}
/* Record image */
if ( $this->record_image )
{
$attachments[] = array( 'cms_Records' => $this->record_image );
}
/* Any upload fields */
$categoryClass = 'IPS\cms\Categories' . static::$customDatabaseId;
$container = $categoryClass::load( $this->category_id );
$fieldsClass = 'IPS\cms\Fields' . static::$customDatabaseId;
$fieldValues = $this->fieldValues();
$customFields = $fieldsClass::fields( $fieldValues, 'edit', $container, 0, $this );
foreach( $customFields as $key => $field )
{
$fieldName = mb_substr( $field->name, 8 );
if ( get_class( $field ) == 'IPS\Helpers\Form\Upload' )
{
if ( is_array( $fieldValues[ $fieldName ] ) )
{
foreach( $fieldValues[ $fieldName ] as $fileName )
{
$obj = \IPS\File::get( 'cms_Records', $filename );
if ( $obj->isImage() )
{
$attachments[] = array( 'cms_Records' => $fileName );
}
}
}
else
{
$obj = \IPS\File::get( 'cms_Records', $fieldValues[ $fieldName ] );
if ( $obj->isImage() )
{
$attachments[] = array( 'cms_Records' => $fieldValues[ $fieldName ] );
}
}
}
}
return count( $attachments ) ? $attachments : NULL;
}
/**
* Get the post key or create one if one doesn't exist
@@ -1741,10 +1866,11 @@ class _Records extends \IPS\Content\Item implements
/**
* Are comments supported by this class?
*
* @param \IPS\Member\NULL $member The member to check for or NULL fto not check permission
* @return int
* @param \IPS\Member|NULL $member The member to check for or NULL to not check permission
* @param \IPS\Node\Model|NULL $container The container to check in, or NULL for any container
* @return bool
*/
public static function supportsComments( \IPS\Member $member = NULL )
public static function supportsComments( \IPS\Member $member = NULL, \IPS\Node\Model $container = NULL )
{
return parent::supportsComments() and static::database()->options['comments'];
}
@@ -1752,10 +1878,11 @@ class _Records extends \IPS\Content\Item implements
/**
* Are reviews supported by this class?
*
* @param \IPS\Member\NULL $member The member to check for or NULL to not check permission
* @return int
* @param \IPS\Member|NULL $member The member to check for or NULL to not check permission
* @param \IPS\Node\Model|NULL $container The container to check in, or NULL for any container
* @return bool
*/
public static function supportsReviews( \IPS\Member $member = NULL )
public static function supportsReviews( \IPS\Member $member = NULL, \IPS\Node\Model $container = NULL )
{
return parent::supportsReviews() and static::database()->options['reviews'];
}
@@ -1816,12 +1943,13 @@ class _Records extends \IPS\Content\Item implements
* @param string $action The action
* @param \IPS\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
*/
public function modAction( $action, \IPS\Member $member = NULL, $reason = NULL )
public function modAction( $action, \IPS\Member $member = NULL, $reason = NULL, $immediately = FALSE )
{
parent::modAction( $action, $member, $reason );
parent::modAction( $action, $member, $reason, $immediately );
if ( $this->useForumComments() and ( $action === 'lock' or $action === 'unlock' ) )
{
@@ -1845,9 +1973,10 @@ class _Records extends \IPS\Content\Item implements
* @param \IPS\DateTime|NULL $cutoff If an \IPS\DateTime object is provided, only comments posted AFTER that date will be included
* @param mixed $extraWhereClause Additional where clause(s) (see \IPS\Db::build for details)
* @param bool|NULL $bypassCache Used in cases where comments may have already been loaded i.e. splitting comments on an item.
* @param bool $includeDeleted Include deleted content.
* @return array|NULL|\IPS\Content\Comment If $limit is 1, will return \IPS\Content\Comment or NULL for no results. For any other number, will return an array.
*/
public function comments( $limit=NULL, $offset=NULL, $order='date', $orderDirection='asc', $member=NULL, $includeHiddenComments=NULL, $cutoff=NULL, $extraWhereClause=NULL, $bypassCache=FALSE )
public function comments( $limit=NULL, $offset=NULL, $order='date', $orderDirection='asc', $member=NULL, $includeHiddenComments=NULL, $cutoff=NULL, $extraWhereClause=NULL, $bypassCache=FALSE, $includeDeleted=FALSE )
{
if ( $this->useForumComments() )
{
@@ -1866,7 +1995,7 @@ class _Records extends \IPS\Content\Item implements
$offset = ( ( $_pageValue - 1 ) * static::getCommentsPerPage() ) + 1;
}
return $recordClass::load( $this->record_topicid )->comments( $limit, $offset, $order, $orderDirection, $member, $includeHiddenComments, $cutoff );
return $recordClass::load( $this->record_topicid )->comments( $limit, $offset, $order, $orderDirection, $member, $includeHiddenComments, $cutoff, $extraWhereClause, $bypassCache, $includeDeleted );
}
else
{
@@ -1883,7 +2012,7 @@ class _Records extends \IPS\Content\Item implements
$where = array( array( 'comment_database_id=?', static::$customDatabaseId ) );
}
return parent::comments( $limit, $offset, $order, $orderDirection, $member, $includeHiddenComments, $cutoff, $where );
return parent::comments( $limit, $offset, $order, $orderDirection, $member, $includeHiddenComments, $cutoff, $where, $bypassCache, $includeDeleted );
}
/**
@@ -1921,13 +2050,14 @@ class _Records extends \IPS\Content\Item implements
* @param bool|NULL $includeHiddenReviews Include hidden comments or not? NULL to base of currently logged in member's permissions
* @param \IPS\DateTime|NULL $cutoff If an \IPS\DateTime object is provided, only comments posted AFTER that date will be included
* @param mixed $extraWhereClause Additional where clause(s) (see \IPS\Db::build for details)
* @param bool $includeDeleted Include deleted content
* @return array|NULL|\IPS\Content\Comment If $limit is 1, will return \IPS\Content\Comment or NULL for no results. For any other number, will return an array.
*/
public function reviews( $limit=NULL, $offset=NULL, $order=NULL, $orderDirection='desc', $member=NULL, $includeHiddenReviews=NULL, $cutoff=NULL, $extraWhereClause=NULL )
public function reviews( $limit=NULL, $offset=NULL, $order=NULL, $orderDirection='desc', $member=NULL, $includeHiddenReviews=NULL, $cutoff=NULL, $extraWhereClause=NULL, $includeDeleted=FALSE )
{
$where = array( array( 'review_database_id=?', static::$customDatabaseId ) );
return parent::reviews( $limit, $offset, $order, $orderDirection, $member, $includeHiddenReviews, $cutoff, $where );
return parent::reviews( $limit, $offset, $order, $orderDirection, $member, $includeHiddenReviews, $cutoff, $where, $includeDeleted );
}
/**
@@ -1940,11 +2070,11 @@ class _Records extends \IPS\Content\Item implements
$tabs = array();
if ( static::database()->options['reviews'] )
{
$tabs['reviews'] = \IPS\Member::loggedIn()->language()->pluralize( \IPS\Member::loggedIn()->language()->get( 'cms_review_count' ), array( $this->mapped('num_reviews') ) );
$tabs['reviews'] = \IPS\Member::loggedIn()->language()->addToStack( 'cms_review_count', TRUE, array( 'pluralize' => array( $this->mapped('num_reviews') ) ) );
}
if ( static::database()->options['comments'] )
{
$tabs['comments'] = \IPS\Member::loggedIn()->language()->pluralize( \IPS\Member::loggedIn()->language()->get( 'cms_comment_count' ), array( $this->mapped( 'num_comments' ) ) );
$tabs['comments'] = \IPS\Member::loggedIn()->language()->addToStack( 'cms_comment_count', TRUE, array( 'pluralize' => array( $this->mapped('num_comments') ) ) );
}
return $tabs;
@@ -2048,6 +2178,25 @@ class _Records extends \IPS\Content\Item implements
parent::processAfterEdit( $values );
}
/**
* Callback to execute when tags are edited
*
* @return void
*/
protected function processAfterTagUpdate()
{
parent::processAfterTagUpdate();
if ( \IPS\Application::appIsEnabled('forums') and $this->_forum_record and $this->_forum_forum and ! $this->hidden() and ! $this->record_future_date )
{
try
{
$this->syncTopic();
}
catch( \Exception $ex ) { }
}
}
/**
* Process the comment form
@@ -2128,7 +2277,7 @@ class _Records extends \IPS\Content\Item implements
$topic->unhide( $member );
}
}
else if ( $this->_forum_forum and $this->_forum_comments )
else if ( $this->_forum_forum )
{
$this->syncTopic();
}
@@ -2173,7 +2322,7 @@ class _Records extends \IPS\Content\Item implements
{
$topic->unhide( $member );
}
elseif ( $this->_forum_forum and $this->_forum_comments and ! $this->isFutureDate() )
elseif ( $this->_forum_forum and ! $this->isFutureDate() )
{
$this->syncTopic();
}
@@ -2405,6 +2554,22 @@ class _Records extends \IPS\Content\Item implements
return parent::commentPageCount();
}
/**
* Log for deletion later
*
* \IPS\Member|NULL $member The member or NULL for currently logged in
* @return void
*/
public function logDelete( $member = NULL )
{
parent::logDelete( $member );
if ( $topic = $this->topic() and $this->_forum_delete )
{
$topic->logDelete( $member );
}
}
/**
* Delete Record
@@ -2939,6 +3104,7 @@ class _Records extends \IPS\Content\Item implements
'featured' => (bool) $this->mapped('featured'),
'url' => (string) $this->url(),
'rating' => $this->averageRating(),
'image' => $this->record_image ? (string) \IPS\File::get( 'cms_Records', $this->record_image )->url : null
);
}
@@ -2965,6 +3131,23 @@ class _Records extends \IPS\Content\Item implements
* @return \IPS\Patterns\ActiveRecordIterator|int
*/
public static function getItemsWithPermission( $where=array(), $order=NULL, $limit=10, $permissionKey='read', $includeHiddenItems=\IPS\Content\Hideable::FILTER_AUTOMATIC, $queryFlags=0, \IPS\Member $member=NULL, $joinContainer=FALSE, $joinComments=FALSE, $joinReviews=FALSE, $countOnly=FALSE, $joins=NULL, $skipPermission=FALSE, $joinTags=TRUE, $joinAuthor=TRUE, $joinLastCommenter=TRUE, $showMovedLinks=FALSE )
{
$where = static::getItemsWithPermissionWhere( $where, $permissionKey, $member, $joinContainer, $skipPermission );
return parent::getItemsWithPermission( $where, $order, $limit, $permissionKey, $includeHiddenItems, $queryFlags, $member, $joinContainer, $joinComments, $joinReviews, $countOnly, $joins, $skipPermission, $joinTags, $joinAuthor, $joinLastCommenter, $showMovedLinks );
}
/**
* WHERE clause for getItemsWithPermission
*
* @param array $where Current WHERE clause
* @param string $permissionKey A key which has a value in the permission map (either of the container or of this class) matching a column ID in core_permission_index
* @param \IPS\Member $member The member (NULL to use currently logged in member)
* @param bool $joinContainer If true, will join container data (set to TRUE if your $where clause depends on this data)
* @param mixed $skipPermission If you are getting records from a specific container, pass the container to reduce the number of permission checks necessary or pass TRUE to skip container-based permission. You must still specify this in the $where clause
* @return array
*/
public static function getItemsWithPermissionWhere( $where, $permissionKey, $member, &$joinContainer, $skipPermission=FALSE )
{
/* Don't show records from categories in which records only show to the poster */
if ( $skipPermission !== TRUE and in_array( $permissionKey, array( 'view', 'read' ) ) )
@@ -2987,7 +3170,59 @@ class _Records extends \IPS\Content\Item implements
}
}
}
/* Return */
return $where;
}
/**
* Reaction Type
*
* @return string
*/
public static function reactionType()
{
$databaseId = static::database()->_id;
return "record_id_{$databaseId}";
}
/**
* Supported Meta Data Types
*
* @return array
*/
public static function supportedMetaDataTypes()
{
return array( 'core_FeaturedComments', 'core_ContentMessages' );
}
return parent::getItemsWithPermission( $where, $order, $limit, $permissionKey, $includeHiddenItems, $queryFlags, $member, $joinContainer, $joinComments, $joinReviews, $countOnly, $joins, $skipPermission, $joinTags, $joinAuthor, $joinLastCommenter, $showMovedLinks );
/**
* Get content for embed
*
* @param array $params Additional parameters to add to URL
* @return string
*/
public function embedContent( $params )
{
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'embed.css', 'cms', 'front' ) );
return \IPS\Theme::i()->getTemplate( 'global', 'cms' )->embedRecord( $this, $this->container(), $this->url()->setQueryString( $params ) );
}
/**
* Give a content item the opportunity to filter similar content
*
* @note Intentionally blank but can be overridden by child classes
* @return array|NULL
*/
public function similarContentFilter()
{
if( $this->record_topicid )
{
return array(
array( '!(tag_meta_app=? and tag_meta_area=? and tag_meta_id=?)', 'forums', 'forums', $this->record_topicid )
);
}
return NULL;
}
}