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

+222 -81
View File
@@ -12,7 +12,7 @@
namespace IPS\blog;
/* 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;
@@ -92,6 +92,10 @@ class _Entry extends \IPS\Content\Item implements
'future_date' => 'publish_date',
'status' => 'status',
'meta_data' => 'meta_data',
'edit_time' => 'edit_time',
'edit_member_name' => 'edit_name',
'edit_show' => 'append_edit',
'edit_reason' => 'edit_reason'
);
/**
@@ -152,7 +156,7 @@ class _Entry extends \IPS\Content\Item implements
/**
* Set the title
*
* @param string $title Title
* @param string $name Title
* @return void
*/
public function set_name( $name )
@@ -190,12 +194,8 @@ class _Entry extends \IPS\Content\Item implements
{
$album = \IPS\gallery\Album::loadAndCheckPerms( $this->gallery_album );
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'gallery.css', 'gallery', 'front' ) );
if ( \IPS\Theme::i()->settings['responsive'] )
{
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'gallery_responsive.css', 'gallery', 'front' ) );
}
$gallery = \IPS\Application::load( 'gallery' );
$gallery::outputCss();
return \IPS\Theme::i()->getTemplate( 'browse', 'gallery', 'front' )->miniAlbum( $album );
}
@@ -225,6 +225,11 @@ class _Entry extends \IPS\Content\Item implements
* @brief SEO Title Column
*/
public static $seoTitleColumn = 'name_seo';
/**
* @brief Category
*/
protected $category;
/**
* Can view this entry
@@ -238,13 +243,17 @@ class _Entry extends \IPS\Content\Item implements
$return = parent::canView( $member );
if ( $this->status == 'draft' AND !static::canViewHiddenItems( $member, $this->container() ) AND !in_array( $this->container()->id, array_keys( \IPS\blog\Blog::loadByOwner( $member ) ) ) )
if ( $this->status == 'draft' AND !static::canViewHiddenItems( $member, $this->container() ) AND !\in_array( $this->container()->id, array_keys( \IPS\blog\Blog::loadByOwner( $member ) ) ) )
{
$return = FALSE;
if ( ( $club = $this->container()->club() AND \in_array( $club->memberStatus( \IPS\Member::loggedIn() ), array( \IPS\Member\Club::STATUS_LEADER, \IPS\Member\Club::STATUS_MODERATOR ) ) ) )
{
$return = TRUE;
}
}
/* Is this a future publish entry and we are the owner of the blog? */
if ( $this->status == 'draft' AND $this->is_future_entry == 1 AND in_array( $this->container()->id, array_keys( \IPS\blog\Blog::loadByOwner( $member ) ) ) )
if ( $this->status == 'draft' AND $this->is_future_entry == 1 AND \in_array( $this->container()->id, array_keys( \IPS\blog\Blog::loadByOwner( $member ) ) ) )
{
$return = TRUE;
}
@@ -259,7 +268,7 @@ class _Entry extends \IPS\Content\Item implements
}
/* Private blog */
if( $this->container()->social_group != 0 AND $this->container()->owner() != $member )
if( $this->container()->social_group != 0 AND $this->container()->owner()->member_id != $member->member_id )
{
/* This will throw an exception of the row does not exist */
try
@@ -304,7 +313,7 @@ class _Entry extends \IPS\Content\Item implements
*/
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 )
{
if ( in_array( $permissionKey, array( 'view', 'read' ) ) )
if ( \in_array( $permissionKey, array( 'view', 'read' ) ) )
{
$joinContainer = TRUE;
@@ -322,13 +331,16 @@ class _Entry extends \IPS\Content\Item implements
{
$joins[] = array( 'from' => 'core_clubs', 'where' => 'core_clubs.id=blog_blogs.blog_club_id' );
if ( $member->member_id )
{
$where[] = array( '( blog_blogs.blog_club_id IS NULL OR ' . \IPS\Db::i()->in( 'blog_blogs.blog_club_id', $member->clubs() ) . ' OR core_clubs.type=? OR core_clubs.type=? OR core_clubs.type=?)', \IPS\Member\Club::TYPE_PUBLIC, \IPS\Member\Club::TYPE_READONLY, \IPS\Member\Club::TYPE_OPEN, );
}
else
{
$where[] = array( '( blog_blogs.blog_club_id IS NULL OR core_clubs.type=? OR core_clubs.type=? OR core_clubs.type=? )', \IPS\Member\Club::TYPE_PUBLIC, \IPS\Member\Club::TYPE_READONLY, \IPS\Member\Club::TYPE_OPEN, );
}
{
if ( !$member->modPermission( 'can_access_all_clubs' ) )
{
$where[] = array( '( blog_blogs.blog_club_id IS NULL OR ' . \IPS\Db::i()->in( 'blog_blogs.blog_club_id', $member->clubs() ) . ' OR core_clubs.type=? OR core_clubs.type=? OR core_clubs.type=?)', \IPS\Member\Club::TYPE_PUBLIC, \IPS\Member\Club::TYPE_READONLY, \IPS\Member\Club::TYPE_OPEN );
}
}
else
{
$where[] = array( '( blog_blogs.blog_club_id IS NULL OR core_clubs.type=? OR core_clubs.type=? OR core_clubs.type=? )', \IPS\Member\Club::TYPE_PUBLIC, \IPS\Member\Club::TYPE_READONLY, \IPS\Member\Club::TYPE_OPEN );
}
}
}
return parent::getItemsWithPermission( $where, $order, $limit, $permissionKey, $includeHiddenItems, $queryFlags, $member, $joinContainer, $joinComments, $joinReviews, $countOnly, $joins, $skipPermission, $joinTags, $joinAuthor, $joinLastCommenter, $showMovedLinks );
@@ -381,6 +393,23 @@ class _Entry extends \IPS\Content\Item implements
$return = parent::formElements( $item, $container );
$return['entry'] = new \IPS\Helpers\Form\Editor( 'blog_entry_content', $item ? $item->content : NULL, TRUE, array( 'app' => 'blog', 'key' => 'Entries', 'autoSaveKey' => ( $item === NULL ) ? 'blog-entry-' . $container->id : 'blog-edit-' . $item->id, 'attachIds' => ( $item === NULL ? NULL : array( $item->id ) ) ) );
/* Edit Log Fields need to be under the editor */
$editReason = NULL;
if( isset( $return['edit_reason']) )
{
$editReason = $return['edit_reason'];
unset( $return['edit_reason'] );
$return['edit_reason'] = $editReason;
}
$logEdit = NULL;
if( isset( $return['log_edit']) )
{
$logEdit = $return['log_edit'];
unset( $return['log_edit'] );
$return['log_edit'] = $logEdit;
}
/* Gallery album association */
if( \IPS\Application::appIsEnabled( 'gallery' ) )
{
@@ -391,7 +420,34 @@ class _Entry extends \IPS\Content\Item implements
) );
}
$return['image'] = new \IPS\Helpers\Form\Upload( 'blog_entry_cover_photo', ( ( $item AND $item->cover_photo ) ? \IPS\File::get( 'blog_Entries', $item->cover_photo ) : NULL ), FALSE, array( 'storageExtension' => 'blog_Entries', 'image' => array( 'maxWidth' => 4800, 'maxHeight' => 4800 ) ) );
$categories = \IPS\blog\Entry\Category::roots( NULL, NULL, array( 'entry_category_blog_id=?', $container->id ) );
$choiceOptions = array( 0 => 'entry_category_choice_new' );
$choiceToggles = array( 0 => array( 'blog_entry_new_category' ) );
if( \count( $categories ) )
{
$choiceOptions[1] = 'entry_category_choice_existing';
$choiceToggles[1] = array( 'entry_category_id' );
}
$return['entry_category_choice'] = new \IPS\Helpers\Form\Radio( 'entry_category_choice', ( ( $item AND $item->category_id ) or \IPS\Request::i()->cat ) ? 1 : 0, FALSE, array(
'options' => $choiceOptions,
'toggles' => $choiceToggles
) );
if( \count( $categories ) )
{
$options = array();
foreach ( $categories as $category )
{
$options[ $category->id ] = $category->name;
}
$return[ 'entry_category_id' ] = new \IPS\Helpers\Form\Select( 'entry_category_id', ( $item AND $item->category_id ) ? $item->category_id : ( \IPS\Request::i()->cat ? \IPS\Request::i()->cat : NULL ), FALSE, array( 'options' => $options ), NULL, NULL, NULL, "entry_category_id" );
}
$return['blog_entry_new_category'] = new \IPS\Helpers\Form\Text( 'blog_entry_new_category', NULL, TRUE, array(), NULL, NULL, NULL, "blog_entry_new_category" );
$return['image'] = new \IPS\Helpers\Form\Upload( 'blog_entry_cover_photo', ( ( $item AND $item->cover_photo ) ? \IPS\File::get( 'blog_Entries', $item->cover_photo ) : NULL ), FALSE, array( 'storageExtension' => 'blog_Entries', 'allowStockPhotos' => TRUE, 'image' => array( 'maxWidth' => 4800, 'maxHeight' => 4800 ) ) );
$return['publish'] = new \IPS\Helpers\Form\YesNo( 'blog_entry_publish', $item ? $item->status : TRUE, FALSE, array( 'togglesOn' => array( 'blog_entry_date' ) ) );
@@ -414,7 +470,7 @@ class _Entry extends \IPS\Content\Item implements
$return['poll'] = $poll;
}
return $return;
}
@@ -436,7 +492,10 @@ class _Entry extends \IPS\Content\Item implements
$oldContent = $this->content;
}
$this->content = $values['blog_entry_content'];
if ( !$new )
$sendFilterNotifications = $this->checkProfanityFilters( FALSE, $new );
if ( !$new AND $sendFilterNotifications === FALSE )
{
$this->sendAfterEditNotifications( $oldContent );
}
@@ -464,6 +523,22 @@ class _Entry extends \IPS\Content\Item implements
{
$this->status = 'draft';
}
if( $values['entry_category_choice'] == 1 and $values['entry_category_id'] )
{
$this->category_id = $values['entry_category_id'];
}
else
{
$newCategory = new \IPS\blog\Entry\Category;
$newCategory->name = $values['blog_entry_new_category'];
$newCategory->seo_name = \IPS\Http\Url\Friendly::seoTitle( $values['blog_entry_new_category'] );
$newCategory->blog_id = $this->blog_id;
$newCategory->save();
$this->category_id = $newCategory->id;
}
/* Ping */
$this->container()->ping();
@@ -481,6 +556,18 @@ class _Entry extends \IPS\Content\Item implements
{
parent::canCreate( $member, $container, $showError );
if ( $member->member_id AND $member->checkPostsPerDay() === FALSE )
{
if ( $showError )
{
\IPS\Output::i()->error( 'posts_per_day_error', '1B203/2', 403, '' );
}
else
{
return FALSE;
}
}
$return = TRUE;
$blogs = \IPS\blog\Blog::loadByOwner( $member );
@@ -492,7 +579,7 @@ class _Entry extends \IPS\Content\Item implements
$return = $club->isModerator( $member );
$error = 'no_module_permission';
}
elseif ( !in_array( $container->id, array_keys( $blogs ) ) )
elseif ( !\in_array( $container->id, array_keys( $blogs ) ) )
{
$return = FALSE;
$error = 'no_module_permission';
@@ -506,7 +593,7 @@ class _Entry extends \IPS\Content\Item implements
}
else
{
if( !count( $blogs ) )
if( !\count( $blogs ) )
{
$return = FALSE;
$error = 'no_module_permission';
@@ -585,13 +672,31 @@ class _Entry extends \IPS\Content\Item implements
/**
* 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 )
{
$member = $member ?: \IPS\Member::loggedIn();
return parent::canComment( $member ) and $member->group['g_blog_allowcomment'];
if ( parent::canComment( $member, $considerPostBeforeRegistering ) )
{
if ( $member->checkPostsPerDay() === FALSE )
{
return FALSE;
}
elseif ( $member->group['g_blog_allowcomment'] )
{
return TRUE;
}
elseif ( !$member->member_id and $considerPostBeforeRegistering and \IPS\Settings::i()->post_before_registering and \IPS\Login::registrationType() != 'disabled' )
{
return (bool) \IPS\Member\Group::load( \IPS\Settings::i()->member_group )->g_blog_allowcomment;
}
}
return FALSE;
}
/**
@@ -622,7 +727,7 @@ class _Entry extends \IPS\Content\Item implements
if ( $result !== TRUE )
{
if ( in_array( $type, array( 'edit', 'delete', 'lock', 'unlock' ) ) and $container and $container->member_id === $member->member_id )
if ( \in_array( $type, array( 'edit', 'delete', 'lock', 'unlock' ) ) and $container and $container->member_id === $member->member_id )
{
$result = $member->group['g_blog_allowownmod'];
}
@@ -641,6 +746,16 @@ class _Entry extends \IPS\Content\Item implements
return array( \IPS\Theme::i()->getTemplate( 'global', 'blog', 'front' ), 'rows' );
}
/**
* WHERE clause for getting items for digest (permissions are already accounted for)
*
* @return array
*/
public static function digestWhere(): array
{
return array( array( 'blog_entries.entry_is_future_entry=0 AND blog_entries.entry_status!=?', 'draft' ) );
}
/**
* Search Index Permissions
*
@@ -672,27 +787,28 @@ class _Entry extends \IPS\Content\Item implements
/**
* Get output for API
*
* @param \IPS\Member|NULL $authorizedMember The member making the API request or NULL for API Key / client_credentials
* @param \IPS\Member|NULL $authorizedMember The member making the API request or NULL for API Key / client_credentials
* @return array
* @apiresponse int id ID number
* @apiresponse string title Title
* @apiresponse \IPS\blog\Blog blog Blog
* @apiresponse \IPS\Member author The member that created the entry
* @apiresponse bool draft If this entry is a draft
* @apiresponse datetime date Date
* @apiresponse string entry Entry content
* @apiresponse int comments Number of comments
* @apiresponse int views Number of posts
* @apiresponse string prefix The prefix tag, if there is one
* @apiresponse [string] tags The tags
* @apiresponse bool locked Entry is locked
* @apiresponse bool hidden Entry is hidden
* @apiresponse bool future Will be published at a future date?
* @apiresponse bool pinned Entry is pinned
* @apiresponse bool featured Entry is featured
* @apiresponse \IPS\Poll poll Poll data, if there is one
* @apiresponse string url URL
* @apiresponse float rating Average Rating
* @apiresponse int id ID number
* @apiresponse string title Title
* @apiresponse \IPS\blog\Blog blog Blog
* @apiresponse \IPS\Member author The member that created the entry
* @apiresponse bool draft If this entry is a draft
* @apiresponse datetime date Date
* @apiresponse string entry Entry content
* @apiresponse int comments Number of comments
* @apiresponse int views Number of posts
* @apiresponse string prefix The prefix tag, if there is one
* @apiresponse [string] tags The tags
* @apiresponse bool locked Entry is locked
* @apiresponse bool hidden Entry is hidden
* @apiresponse bool future Will be published at a future date?
* @apiresponse bool pinned Entry is pinned
* @apiresponse bool featured Entry is featured
* @apiresponse \IPS\Poll poll Poll data, if there is one
* @apiresponse string url URL
* @apiresponse float rating Average Rating
* @apiresponse \IPS\blog\Entry\Category category Category
*/
public function apiOutput( \IPS\Member $authorizedMember = NULL )
{
@@ -703,7 +819,7 @@ class _Entry extends \IPS\Content\Item implements
'author' => $this->author()->apiOutput( $authorizedMember ),
'draft' => $this->status == 'draft',
'date' => \IPS\DateTime::ts( $this->date )->rfc3339(),
'entry' => $this->content(),
'entry' => \IPS\Text\Parser::removeLazyLoad( $this->content() ),
'comments' => $this->num_comments,
'views' => $this->views,
'prefix' => $this->prefix(),
@@ -716,6 +832,7 @@ class _Entry extends \IPS\Content\Item implements
'poll' => $this->poll_state ? \IPS\Poll::load( $this->poll_state )->apiOutput( $authorizedMember ) : null,
'url' => (string) $this->url(),
'rating' => $this->averageRating(),
'category' => $this->category_id ? $this->category()->apiOutput() : NULL,
);
}
@@ -739,34 +856,10 @@ class _Entry extends \IPS\Content\Item implements
return array( 'core_FeaturedComments', 'core_ContentMessages' );
}
/**
* Can perform an action on a message
*
* @param string The action
* @param \IPS\Member|NULL The member, or NULL for currently logged in
* @return bool
*/
public function canOnMessage( $action, \IPS\Member $member = NULL )
{
$return = parent::canOnMessage( $action, $member );
if ( $return === FALSE )
{
$member = $member ?: \IPS\Member::loggedIn();
if ( $member->member_id AND $member->member_id === $this->author()->member_id AND $member->group['g_blog_allowownmod'] )
{
$return = TRUE;
}
}
return $return;
}
/**
* Can Feature a Comment
*
* @param \IPS\Member|NULL The member, or NULL for currently logged in
* @param \IPS\Member|NULL $member The member, or NULL for currently logged in
* @return bool
*/
public function canFeatureComment( \IPS\Member $member = NULL )
@@ -789,7 +882,7 @@ class _Entry extends \IPS\Content\Item implements
/**
* Can Unfeature a Comment
*
* @param \IPS\Member|NULL The member, or NULL for currently logged in
* @param \IPS\Member|NULL $member The member, or NULL for currently logged in
* @return bool
*/
public function canUnfeatureComment( \IPS\Member $member = NULL )
@@ -808,17 +901,16 @@ class _Entry extends \IPS\Content\Item implements
return $return;
}
/**
* Returns the content images
*
* @param int|null $limit Number of attachments to fetch, or NULL for all
*
* @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 )
{
$idColumn = static::$databaseColumnId;
$internal = NULL;
@@ -836,8 +928,41 @@ class _Entry extends \IPS\Content\Item implements
$attachments[] = array( 'core_Attachment' => $row['attach_location'] );
}
}
/* Does the blog entry have a cover photo? */
if( $this->cover_photo )
{
$attachments[] = array( 'blog_Entries' => $this->cover_photo );
}
/* And what about the blog itself? */
if( $this->container()->cover_photo )
{
$attachments[] = array( 'blog_Blogs' => $this->container()->cover_photo );
}
/* IS there a club with a cover photo? */
if ( \IPS\IPS::classUsesTrait( $this->container(), 'IPS\Content\ClubContainer' ) and $club = $this->container()->club() )
{
$attachments[] = array( 'core_Clubs' => $club->cover_photo );
}
return count( $attachments ) ? $attachments : NULL;
return \count( $attachments ) ? $attachments : NULL;
}
/**
* Is this a future entry?
*
* @return bool
*/
public function isFutureDate()
{
if ( $this->date > time() )
{
return TRUE;
}
return FALSE;
}
/**
@@ -851,4 +976,20 @@ class _Entry extends \IPS\Content\Item implements
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'embed.css', 'blog', 'front' ) );
return \IPS\Theme::i()->getTemplate( 'global', 'blog' )->embedEntry( $this, $this->container(), $this->url()->setQueryString( $params ) );
}
/**
* Get category
*
* @return \IPS\blog\Entry\Category
* @throws \OutOfRangeException
*/
public function category()
{
if ( $this->category === NULL )
{
$this->category = \IPS\blog\Entry\Category::load( $this->category_id );
}
return $this->category;
}
}