Version 4.5.0

This commit is contained in:
Neo committed 2025-12-19 05:51:58 -08:00
1 parent 1a0c7fd3c2
commit f79dcf067a
3791 files changed
+248032 -76372

No files matched your search

+59 -32
View File
@@ -12,7 +12,7 @@
namespace IPS\gallery;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
@@ -94,6 +94,11 @@ class _Album extends \IPS\Node\Model implements \IPS\Node\Ratings, \IPS\Content\
'rating_hits' => 'rating_count',
);
/**
* @brief [Node] Maximum results to display at a time in any node helper form elements. Useful for user-submitted node types when there may be a lot. NULL for no limit.
*/
public static $maxFormHelperResults = 2000;
/**
* Return this album as a content item instead of a node
*
@@ -642,7 +647,7 @@ class _Album extends \IPS\Node\Model implements \IPS\Node\Ratings, \IPS\Content\
if( isset( $values['album_name'] ) )
{
\IPS\Lang::saveCustom( 'gallery', "gallery_album_{$this->id}", $values['album_name'] );
$values['name_seo'] = \IPS\Http\Url\Friendly::seoTitle( is_array( $values['album_name'] ) ? $values['album_name'][ \IPS\Lang::defaultLanguage() ] : $values['album_name'] );
$values['name_seo'] = \IPS\Http\Url\Friendly::seoTitle( \is_array( $values['album_name'] ) ? $values['album_name'][ \IPS\Lang::defaultLanguage() ] : $values['album_name'] );
}
if( isset( $values['album_description'] ) )
@@ -715,7 +720,7 @@ class _Album extends \IPS\Node\Model implements \IPS\Node\Ratings, \IPS\Content\
* @brief Remember previous album status when editing
*/
protected $postSaveType = NULL;
/**
* [Node] Perform actions after saving the form
*
@@ -725,6 +730,13 @@ class _Album extends \IPS\Node\Model implements \IPS\Node\Ratings, \IPS\Content\
public function postSaveForm( $values )
{
\IPS\File::claimAttachments( 'gallery-new-album', $this->id );
$sendFilterNotifications = $this->asItem()->checkProfanityFilters( FALSE, $this->postSaveIsEdit );
if ( $sendFilterNotifications )
{
/* Save it so it hides */
$this->asItem()->save();
}
/* Update counts in categories if we move the album */
if( $this->postSaveIsEdit and $this->postSaveCategory != $values['category_id'] )
@@ -925,14 +937,14 @@ class _Album extends \IPS\Node\Model implements \IPS\Node\Ratings, \IPS\Content\
/**
* 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', ... );
* @param int|null $limit Number of attachments to fetch, or NULL for all
* @param bool $ignorePermissions If set to TRUE, permission to view the images will not be checked
* @return array|NULL
* @throws \BadMethodCallException
*/
public function contentImages( $limit = NULL )
public function contentImages( $limit = NULL, $ignorePermissions = FALSE )
{
$this->asItem()->contentImages( $limit );
return $this->asItem()->contentImages( $limit, $ignorePermissions );
}
/**
@@ -942,9 +954,9 @@ class _Album extends \IPS\Node\Model implements \IPS\Node\Ratings, \IPS\Content\
*/
public function get__latestImages()
{
$_latestImages = json_decode( $this->last_x_images, TRUE );
$_latestImages = json_decode( $this->last_x_images, TRUE ) ?? array();
if( !count( $_latestImages ) )
if( !\count( $_latestImages ) )
{
return array();
}
@@ -975,7 +987,7 @@ class _Album extends \IPS\Node\Model implements \IPS\Node\Ratings, \IPS\Content\
{
$events = iterator_to_array( \IPS\calendar\Event::getItemsWithPermission( array( array( 'event_album=?', $this->id ) ) ) );
if( !count( $events ) )
if( !\count( $events ) )
{
$this->_events = array();
return $this->_events;
@@ -1039,12 +1051,21 @@ class _Album extends \IPS\Node\Model implements \IPS\Node\Ratings, \IPS\Content\
/**
* Retrieve the content item count
*
* @param null|array $data Data array for mass move/delete
* @return null|int
*/
public function getContentItemCount()
public function getContentItemCount( $data=NULL )
{
$contentItemClass = static::$contentItemClass;
return (int) \IPS\Db::i()->select( 'COUNT(*)', $contentItemClass::$databaseTable, array( $contentItemClass::$databasePrefix . 'album_id=?', $this->id ) )->first();
$where = array( array( $contentItemClass::$databasePrefix . 'album_id=?', $this->id ) );
if( $data )
{
$where = array_merge_recursive( $where, $this->massMoveorDeleteWhere( $data ) );
}
return (int) \IPS\Db::i()->select( 'COUNT(*)', $contentItemClass::$databaseTable, $where )->first();
}
/**
@@ -1069,7 +1090,7 @@ class _Album extends \IPS\Node\Model implements \IPS\Node\Ratings, \IPS\Content\
$where = array();
$where[] = array( $contentItemClass::$databasePrefix . 'album_id=?', $this->_id );
if ( count( $additionalWhere ) )
if ( \count( $additionalWhere ) )
{
foreach( $additionalWhere AS $clause )
{
@@ -1122,7 +1143,7 @@ class _Album extends \IPS\Node\Model implements \IPS\Node\Ratings, \IPS\Content\
}
/* Make sure it's a valid size */
if( !in_array( $size, array( 'masked', 'small' ) ) )
if( !\in_array( $size, array( 'masked', 'small' ) ) )
{
throw new \InvalidArgumentException;
}
@@ -1174,14 +1195,7 @@ class _Album extends \IPS\Node\Model implements \IPS\Node\Ratings, \IPS\Content\
if ( isset( $qs['album'] ) )
{
if ( method_exists( get_called_class(), 'loadAndCheckPerms' ) )
{
return static::loadAndCheckPerms( $qs['album'] );
}
else
{
return static::load( $qs['album'] );
}
return static::load( $qs['album'] );
}
throw new \InvalidArgumentException;
@@ -1206,12 +1220,13 @@ class _Album extends \IPS\Node\Model implements \IPS\Node\Ratings, \IPS\Content\
* Check permissions
*
* @param mixed $permission A key which has a value in static::$permissionMap['view'] matching a column ID in core_permission_index
* @param \IPS\Member|\IPS\Member\Group|NULL $member The member or group to check (NULL for currently logged in member)
* @param \IPS\Member|\IPS\Member\Group|NULL $member The member or group to check (NULL for currently logged in member)
* @param bool $considerPostBeforeRegistering If TRUE, and $member is a guest, will return TRUE if "Post Before Registering" feature is enabled
* @return bool
* @throws \OutOfBoundsException If $permission does not exist in static::$permissionMap
* @note Albums don't have permissions, but instead check against the category they are in
*/
public function can( $permission, $member=NULL )
public function can( $permission, $member=NULL, $considerPostBeforeRegistering = TRUE )
{
/* Load the item */
$asItem = $this->asItem();
@@ -1274,7 +1289,7 @@ class _Album extends \IPS\Node\Model implements \IPS\Node\Ratings, \IPS\Content\
/* Chosen members */
case static::AUTH_SUBMIT_MEMBERS:
if ( !in_array( $this->submit_access, $member->socialGroups() ) AND $this->owner_id != $member->member_id )
if ( !\in_array( $this->submit_access, $member->socialGroups() ) AND $this->owner_id != $member->member_id )
{
return FALSE;
}
@@ -1282,7 +1297,7 @@ class _Album extends \IPS\Node\Model implements \IPS\Node\Ratings, \IPS\Content\
/* Club */
case static::AUTH_SUBMIT_CLUB:
if ( $club = $this->category()->club() and !in_array( $club->id, $member->clubs() ) )
if ( $club = $this->category()->club() and !\in_array( $club->id, $member->clubs() ) )
{
return FALSE;
}
@@ -1312,7 +1327,7 @@ class _Album extends \IPS\Node\Model implements \IPS\Node\Ratings, \IPS\Content\
}
else
{
return $asItem->can( $permission, $member );
return $asItem->can( $permission, $member, $considerPostBeforeRegistering );
}
}
}
@@ -1337,19 +1352,19 @@ class _Album extends \IPS\Node\Model implements \IPS\Node\Ratings, \IPS\Content\
/* Albums can be hidden, so make sure to test permissions */
if( $asItem->hidden() )
{
if( !$asItem->can( 'view', $member ) )
if( !$asItem->can( 'view', $member, $considerPostBeforeRegistering ) )
{
return FALSE;
}
return $asItem->can( $permission, $member );
return $asItem->can( $permission, $member, $considerPostBeforeRegistering );
}
}
/* We'll just rely on category permissions if the album isn't hidden */
try
{
return $this->category()->can( $permission, $member );
return $this->category()->can( $permission, $member, $considerPostBeforeRegistering );
}
catch( \OutOfRangeException $e )
{
@@ -1444,7 +1459,7 @@ class _Album extends \IPS\Node\Model implements \IPS\Node\Ratings, \IPS\Content\
return array(
'id' => $this->id,
'name' => $this->name,
'description' => $this->description,
'description' => \IPS\Member::loggedIn()->language()->addToStack("gallery_album_{$this->id}_desc", NULL, array( 'removeLazyLoad' => true ) ),
'category' => $this->category()->apiOutput( $authorizedMember ),
'owner' => $this->owner()->apiOutput( $authorizedMember ),
'privacy' => ( $this->type == static::AUTH_TYPE_PUBLIC ) ? 'public' : ( $this->type == static::AUTH_TYPE_PRIVATE ? 'private' : ( $this->type == static::AUTH_TYPE_RESTRICTED ? 'restricted' : null ) ),
@@ -1455,6 +1470,18 @@ class _Album extends \IPS\Node\Model implements \IPS\Node\Ratings, \IPS\Content\
'url' => (string) $this->url()
);
}
/**
* Webhook filters
*
* @return array
*/
public function webhookFilters()
{
$filters = array();
$filters['privacy'] = ( $this->type == static::AUTH_TYPE_PUBLIC ) ? 'public' : ( $this->type == static::AUTH_TYPE_PRIVATE ? 'private' : ( $this->type == static::AUTH_TYPE_RESTRICTED ? 'restricted' : null ) );
return $filters;
}
/**
* Get template for managing this nodes follows
@@ -12,7 +12,7 @@
namespace IPS\gallery\Album;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
@@ -95,7 +95,9 @@ class _Comment extends \IPS\Content\Comment implements \IPS\Content\EditHistory,
* @param bool $joinContainer If true, will join container data (set to TRUE if your $where clause depends on this data)
* @param bool $joinComments If true, will join comment data (set to TRUE if your $where clause depends on this data)
* @param bool $joinReviews If true, will join review data (set to TRUE if your $where clause depends on this data)
* @return \IPS\Patterns\ActiveRecordIterator|int
* @param bool $countOnly If true will return the count
* @param array|null $joins Additional arbitrary joins for the query
* @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 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 )
{
@@ -142,7 +144,7 @@ class _Comment extends \IPS\Content\Comment implements \IPS\Content\EditHistory,
public static function searchResultSnippet( array $indexData, array $authorData, array $itemData, array $containerData = NULL, array $reputationData, $reviewRating, $view )
{
$url = \IPS\Http\Url::internal( \IPS\gallery\Album\Item::$urlBase . $indexData['index_item_id'], 'front', \IPS\gallery\Album\Item::$urlTemplate, \IPS\Http\Url\Friendly::seoTitle( $indexData['index_title'] ?: $itemData[ \IPS\gallery\Album\Item::$databasePrefix . \IPS\gallery\Album\Item::$databaseColumnMap['title'] ] ) );
$images = ( isset( $itemData['extra'] ) AND count( $itemData['extra'] ) ) ? $itemData['extra'] : array();
$images = ( isset( $itemData['extra'] ) AND \count( $itemData['extra'] ) ) ? $itemData['extra'] : array();
return \IPS\Theme::i()->getTemplate( 'global', 'gallery', 'front' )->searchResultAlbumCommentSnippet( $indexData, $itemData, $images, $url, $reviewRating, $view == 'condensed' );
}
@@ -159,7 +161,7 @@ class _Comment extends \IPS\Content\Comment implements \IPS\Content\EditHistory,
*/
public static function reactionType()
{
return 'comment_id';
return 'album_comment';
}
/**
+45 -38
View File
@@ -12,7 +12,7 @@
namespace IPS\gallery\Album;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
@@ -160,54 +160,38 @@ class _Item extends \IPS\Content\Item implements
*/
public static $seoTitleColumn = 'name_seo';
/**
* Get URL
*
* @param string|NULL $action Action
* @return \IPS\Http\Url
*/
public function url( $action=NULL )
{
$url = $this->asNode()->url();
if( $action !== NULL )
{
$url = $url->setQueryString( 'do', $action );
}
return $url;
}
/**
* Can review?
*
* @param \IPS\Member\NULL $member The member (NULL for currently logged in member)
* @param \IPS\Member\NULL $member The member (NULL for currently logged in member)
* @param bool $considerPostBeforeRegistering If TRUE, and $member is a guest, will return TRUE if "Post Before Registering" feature is enabled
* @return bool
*/
public function canReview( $member=NULL )
public function canReview( $member=NULL, $considerPostBeforeRegistering = TRUE )
{
if ( !$this->use_reviews )
{
return FALSE;
}
return parent::canReview( $member );
return parent::canReview( $member, $considerPostBeforeRegistering );
}
/**
* Can comment?
*
* @param \IPS\Member\NULL $member The member (NULL for currently logged in member)
* @param \IPS\Member\NULL $member The member (NULL for currently logged in member)
* @param bool $considerPostBeforeRegistering If TRUE, and $member is a guest, will return TRUE if "Post Before Registering" feature is enabled
* @return bool
*/
public function canComment( $member=NULL )
public function canComment( $member=NULL, $considerPostBeforeRegistering = TRUE )
{
if ( !$this->use_comments )
{
return FALSE;
}
return parent::canComment( $member );
return parent::canComment( $member, $considerPostBeforeRegistering );
}
/**
@@ -312,7 +296,7 @@ class _Item extends \IPS\Content\Item implements
$wheres[] = '(album_submit_type=' . \IPS\gallery\Album::AUTH_SUBMIT_MEMBERS . ' AND (' . \IPS\Db::i()->findInSet( 'album_submit_access', $member->socialGroups() ) . ' OR album_owner_id=' . $member->member_id . ' ) )';
/* And finally, if we're in a club and we allow anyone in the club to submit, handle that */
if( $category->club() AND in_array( $category->club()->id, $member->clubs() ) )
if( $category->club() AND \in_array( $category->club()->id, $member->clubs() ) )
{
$wheres[] = '(album_submit_type=' . \IPS\gallery\Album::AUTH_SUBMIT_CLUB . ')';
}
@@ -324,7 +308,12 @@ class _Item extends \IPS\Content\Item implements
* @brief Cached groups the member can access
*/
protected static $_availableGroups = array();
/**
* @brief Cached URLs
*/
protected $_url = array();
/**
* WHERE clause for getItemsWithPermission
*
@@ -446,7 +435,7 @@ class _Item extends \IPS\Content\Item implements
}
}
if ( count( $imageIds ) )
if ( \count( $imageIds ) )
{
\IPS\gallery\Application::outputCss();
@@ -454,7 +443,7 @@ class _Item extends \IPS\Content\Item implements
foreach ( \IPS\gallery\Image::getItemsWithPermission( array( array( 'image_id IN(' . implode( ',', $imageIds ) . ')' ) ), NULL, NULL ) as $image )
{
if( isset( $return[ $image->album_id] ) AND count( $return[ $image->album_id ] ) > 19 )
if( isset( $return[ $image->album_id] ) AND \count( $return[ $image->album_id ] ) > 19 )
{
continue;
}
@@ -483,7 +472,7 @@ class _Item extends \IPS\Content\Item implements
public static function searchResultSnippet( array $indexData, array $authorData, array $itemData, array $containerData = NULL, array $reputationData, $reviewRating, $view )
{
$url = \IPS\Http\Url::internal( static::$urlBase . $indexData['index_item_id'], 'front', static::$urlTemplate, \IPS\Http\Url\Friendly::seoTitle( $indexData['index_title'] ?: $itemData[ static::$databasePrefix . static::$databaseColumnMap['title'] ] ) );
$images = ( isset( $itemData['extra'] ) AND count( $itemData['extra'] ) ) ? $itemData['extra'] : array();
$images = ( isset( $itemData['extra'] ) AND \count( $itemData['extra'] ) ) ? $itemData['extra'] : array();
return \IPS\Theme::i()->getTemplate( 'global', 'gallery', 'front' )->searchResultAlbumSnippet( $indexData, $itemData, $images, $url, $view == 'condensed' );
}
@@ -501,9 +490,9 @@ class _Item extends \IPS\Content\Item implements
*/
public static function searchResultSummaryLanguage( $authorData, $articles, $indexData, $itemData )
{
if( !in_array( 'IPS\Content\Comment', class_parents( $indexData['index_class'] ) ) )
if( !\in_array( 'IPS\Content\Comment', class_parents( $indexData['index_class'] ) ) )
{
return \IPS\Member::loggedIn()->language()->addToStack( "album_user_own_activity_item", FALSE, array( 'sprintf' => array( $authorData['name'], $articles['indefinite'] ) ) );
return \IPS\Member::loggedIn()->language()->addToStack( "album_user_own_activity_item", FALSE, array( 'sprintf' => array( $articles['indefinite'] ), 'htmlsprintf' => array( \IPS\Theme::i()->getTemplate( 'global', 'core', 'front' )->userLinkFromData( $authorData['member_id'], $authorData['name'], $authorData['members_seo_name'], $authorData['member_group_id'] ?? \IPS\Settings::i()->guest_group ) ) ) );
}
else
{
@@ -644,21 +633,21 @@ class _Item extends \IPS\Content\Item implements
/**
* 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', ... );
* @param int|null $limit Number of attachments to fetch, or NULL for all
* @param bool $ignorePermissions If set to TRUE, permission to view the images will not be checked
* @return array|NULL
* @throws \BadMethodCallException
*/
public function contentImages( $limit = NULL )
public function contentImages( $limit = NULL, $ignorePermissions = FALSE )
{
$images = array();
foreach( \IPS\gallery\Image::getItemsWithPermission( array( array( 'image_album_id=?', $this->id ) ), NULL, $limit ? $limit : 10 ) as $image )
foreach( \IPS\gallery\Image::getItemsWithPermission( array( array( 'image_album_id=?', $this->id ) ), NULL, $limit ? $limit : 10, $ignorePermissions ? NULL : 'read' ) as $image )
{
$images[] = array( 'gallery_Images' => $image->masked_file_name );
}
return count( $images ) ? $images : NULL;
return \count( $images ) ? $images : NULL;
}
/**
@@ -674,4 +663,22 @@ class _Item extends \IPS\Content\Item implements
$this->container()->resetCommentCounts();
$this->container()->save();
}
/**
* Get the last modification date for the sitemap
*
* @return \IPS\DateTime|null Timestamp of the last modification time for the sitemap
*/
public function lastModificationDate()
{
/* Returns the last last comment date */
$lastMod = parent::lastModificationDate();
if( !$lastMod AND $this->last_img_date OR ( $lastMod AND $this->last_img_date AND $this->last_img_date > $lastMod->getTimestamp() ) )
{
$lastMod = \IPS\DateTime::ts( $this->last_img_date );
}
return $lastMod;
}
}
@@ -12,7 +12,7 @@
namespace IPS\gallery\Album;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
@@ -91,8 +91,10 @@ class _Review extends \IPS\Content\Review implements \IPS\Content\EditHistory, \
*
* @param string|NULL $action Action
* @return \IPS\Http\Url
* @throws \BadMethodCallException
* @throws \IPS\Http\Url\Exception
*/
public function url( $action=NULL )
public function url( $action='find' )
{
return parent::url( $action )->setQueryString( 'tab', 'reviews' );
}
@@ -139,7 +141,7 @@ class _Review extends \IPS\Content\Review implements \IPS\Content\EditHistory, \
*/
public static function reactionType()
{
return 'review_id';
return 'album_review';
}
/**
+2 -2
View File
@@ -12,7 +12,7 @@
namespace IPS\gallery\Album;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
@@ -85,7 +85,7 @@ class _Table extends \IPS\Helpers\Table\Content
/* If we can't moderate in this category, restrict results */
if( $container === NULL OR !\IPS\gallery\Image::modPermission( 'edit', NULL, $container ) )
{
if( count( \IPS\Member::loggedIn()->socialGroups() ) )
if( \count( \IPS\Member::loggedIn()->socialGroups() ) )
{
$this->where[] = array( '( album_type=1 OR ( album_type=2 AND album_owner_id=? ) OR ( album_type=3 AND ( album_owner_id=? OR ( album_allowed_access IS NOT NULL AND album_allowed_access IN(' . implode( ',', \IPS\Member::loggedIn()->socialGroups() ) . ') ) ) ) )', \IPS\Member::loggedIn()->member_id, \IPS\Member::loggedIn()->member_id );
}