Version 4.1.19

This commit is contained in:
Neo committed 2025-12-19 05:38:56 -08:00
1 parent 28bd025b35
commit 2bd5025018
2674 files changed
+233518 -77766

No files matched your search

+339 -76
View File
@@ -2,9 +2,9 @@
/**
* @brief Blog Node
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @subpackage Blog
* @since 3 Mar 2014
* @version SVN_VERSION_NUMBER
@@ -101,7 +101,20 @@ class _Blog extends \IPS\Node\Model implements \IPS\Node\Ratings, \IPS\Content\E
* @brief Cover Photo Storage Extension
*/
public static $coverPhotoStorageExtension = 'blog_Blogs';
/**
* Columns needed to query for search result / stream view
*
* @return array
*/
public static function basicDataColumns()
{
$return = parent::basicDataColumns();
$return[] = 'blog_name';
$return[] = 'blog_member_id';
return $return;
}
/**
* Get template for content tables
*
@@ -134,7 +147,20 @@ class _Blog extends \IPS\Node\Model implements \IPS\Node\Ratings, \IPS\Content\E
return FALSE;
}
/**
* Get title from index data
*
* @param array $indexData Data from the search index
* @param array $itemData Basic data about the item. Only includes columns returned by item::basicDataColumns()
* @param array|NULL $containerData Basic data about the author. Only includes columns returned by container::basicDataColumns()
* @return \IPS\Http\Url
*/
public static function titleFromIndexData( $indexData, $itemData, $containerData )
{
return ( $containerData['blog_member_id'] ) ? $containerData['blog_name'] : parent::titleFromIndexData( $indexData, $itemData, $containerData );
}
/**
* Check permissions
*
@@ -145,18 +171,24 @@ class _Blog extends \IPS\Node\Model implements \IPS\Node\Ratings, \IPS\Content\E
*/
public function can( $permission, $member=NULL )
{
/* Load member */
if ( $member === NULL )
{
$member = \IPS\Member::loggedIn();
}
if ( $this->social_group )
{
if ( !\IPS\Member::loggedIn()->member_id )
if ( !$member->member_id )
{
return FALSE;
}
if ( \IPS\Member::loggedIn()->member_id !== $this->member_id )
if ( $member->member_id !== $this->member_id )
{
try
{
\IPS\Db::i()->select( '*', 'core_sys_social_group_members', array( 'group_id=? AND member_id=?', $this->social_group, \IPS\Member::loggedIn()->member_id ) )->first();
\IPS\Db::i()->select( '*', 'core_sys_social_group_members', array( 'group_id=? AND member_id=?', $this->social_group, $member->member_id ) )->first();
}
catch ( \UnderflowException $e )
{
@@ -167,11 +199,11 @@ class _Blog extends \IPS\Node\Model implements \IPS\Node\Ratings, \IPS\Content\E
if ( $permission === 'add' )
{
if ( !\IPS\Member::loggedIn()->member_id )
if ( !$member->member_id )
{
return FALSE;
}
elseif ( \IPS\Member::loggedIn()->member_id === $this->member_id )
elseif ( $member->member_id === $this->member_id )
{
return TRUE;
}
@@ -179,7 +211,7 @@ class _Blog extends \IPS\Node\Model implements \IPS\Node\Ratings, \IPS\Content\E
{
if ( $this->groupblog_ids )
{
return \IPS\Member::loggedIn()->inGroup( explode( ',', $this->groupblog_ids ) );
return $member->inGroup( explode( ',', $this->groupblog_ids ) );
}
else
{
@@ -267,14 +299,30 @@ class _Blog extends \IPS\Node\Model implements \IPS\Node\Ratings, \IPS\Content\E
{
if( $public )
{
$form->add( new \IPS\Helpers\Form\Text( 'blog_name', $this->id ? $this->_title : NULL, TRUE ) );
$form->add( new \IPS\Helpers\Form\Editor( 'blog_desc', $this->id ? $this->description : NULL, FALSE, array( 'app' => 'blog', 'key' => 'Blogs', 'autoSaveKey' => ( $this->id ? "blogs-blog-{$this->id}" : "blogs-new-blog" ), 'attachIds' => $this->id ? array( $this->id, NULL, 'description' ) : NULL, 'minimize' => 'blog_desc_placeholder' ) ) );
$form->add( new \IPS\Helpers\Form\Text( 'blog_name', $this->id ? $this->_title : NULL, TRUE, array(), NULL, NULL, NULL, 'blog_name' ) );
$form->add( new \IPS\Helpers\Form\Editor( 'blog_desc', $this->id ? $this->description : NULL, FALSE, array( 'app' => 'blog', 'key' => 'Blogs', 'autoSaveKey' => ( $this->id ? "blogs-blog-{$this->id}" : "blogs-new-blog" ), 'attachIds' => $this->id ? array( $this->id, NULL, 'description' ) : NULL, 'minimize' => 'blog_desc_placeholder' ), NULL, NULL, NULL, 'blog_desc_wrap' ) );
}
else
{
$form->addHeader( 'blog_settings' );
$form->add( new \IPS\Helpers\Form\Translatable( 'blog_name', NULL, TRUE, array( 'app' => 'blog', 'key' => ( $this->id ? "blogs_blog_{$this->id}" : NULL ) ) ) );
$form->add( new \IPS\Helpers\Form\Translatable( 'blog_desc', NULL, FALSE, array( 'app' => 'blog', 'key' => ( $this->id ? "blogs_blog_{$this->id}_desc" : NULL ), 'editor' => array( 'app' => 'blog', 'key' => 'Blogs', 'autoSaveKey' => ( $this->id ? "blogs-blog-{$this->id}" : "blogs-new-blog" ), 'attachIds' => $this->id ? array( $this->id, NULL, 'description' ) : NULL, 'minimize' => 'blog_desc_placeholder' ) ) ) );
/* Owned blogs */
$form->add( new \IPS\Helpers\Form\Text( 'blog_name', $this->id ? $this->_title : NULL, FALSE, array(), function( $value ) {
if ( \IPS\Request::i()->blog_type === 'member' AND !$value )
{
throw new \InvalidArgumentException( 'form_required' );
}
}, NULL, NULL, 'blog_name' ) );
$form->add( new \IPS\Helpers\Form\Editor( 'blog_desc', $this->id ? $this->desc : NULL, FALSE, array( 'app' => 'blog', 'key' => 'Blogs', 'autoSaveKey' => ( $this->id ? "blogs-blog-{$this->id}m" : "blogs-new-blog" ), 'attachIds' => $this->id ? array( $this->id, NULL, 'description' ) : NULL, 'minimize' => 'blog_desc_placeholder' ), NULL, NULL, NULL, 'blog_desc_wrap' ) );
/* Group blogs - only one or the other will show at any given time */
$form->add( new \IPS\Helpers\Form\Translatable( 'blog_name_group', ( $this->id AND !$this->groupblog_ids ) ? $this->_title : NULL, FALSE, array( 'app' => 'blog', 'key' => ( $this->id ? "blogs_blog_{$this->id}" : NULL ) ), function( $value ) {
if ( \IPS\Request::i()->blog_type !== 'member' AND !$value )
{
throw new \InvalidArgumentException( 'form_required' );
}
}, NULL, NULL, 'blog_name_group' ) );
$form->add( new \IPS\Helpers\Form\Translatable( 'blog_desc_group', NULL, FALSE, array( 'app' => 'blog', 'key' => ( $this->id ? "blogs_blog_{$this->id}_desc" : NULL ), 'editor' => array( 'app' => 'blog', 'key' => 'Blogs', 'autoSaveKey' => ( $this->id ? "blogs-blog-{$this->id}-group" : "blogs-new-blog-group" ), 'attachIds' => $this->id ? array( $this->id, NULL, 'description' ) : NULL, 'minimize' => 'blog_desc_placeholder' ) ), NULL, NULL, NULL, 'blog_desc_group_wrap' ) );
$groups = array();
foreach ( \IPS\Member\Group::groups() as $k => $v )
@@ -299,8 +347,8 @@ class _Blog extends \IPS\Node\Model implements \IPS\Node\Ratings, \IPS\Content\E
'group' => 'blog_type_group'
),
'toggles' => array(
'member' => array( 'blog_member_id' ),
'group' => array( 'blog_groupblog_ids', 'blog_groupblog_name' )
'member' => array( 'blog_member_id', 'blog_name', 'blog_desc_wrap' ),
'group' => array( 'blog_groupblog_ids', 'blog_groupblog_name', 'blog_name_group', 'blog_desc_group_wrap' )
)
) ) );
@@ -348,21 +396,25 @@ class _Blog extends \IPS\Node\Model implements \IPS\Node\Ratings, \IPS\Content\E
*/
public function formatFormValues( $values )
{
$this->member_id = 0;
if( isset( $values['blog_type'] ) and $values['blog_type'] == 'member' and isset( $values['blog_member_id'] ) and is_object( $values['blog_member_id'] ) )
{
$values['blog_member_id']->create_menu = NULL;
$values['blog_member_id']->save();
$values['blog_member_id'] = $values['blog_member_id']->member_id;
$this->member_id = $values['blog_member_id'];
$values['blog_member_id'] = $values['blog_member_id']->member_id;
$values['blog_groupblog_ids'] = '';
$this->member_id = $values['blog_member_id'];
}
else if ( !isset( $values['blog_type'] ) )
else if ( !$this->id and !isset( $values['blog_type'] ) )
{
$values['blog_member_id'] = \IPS\Member::loggedIn()->member_id;
\IPS\Member::loggedIn()->create_menu = NULL;
\IPS\Member::loggedIn()->save();
$this->member_id = $values['blog_member_id'];
}
else if ( isset( $values['blog_type'] ) )
{
$this->member_id = 0;
}
if( isset( $values['blog_type'] ) )
{
@@ -398,39 +450,129 @@ class _Blog extends \IPS\Node\Model implements \IPS\Node\Ratings, \IPS\Content\E
if ( !$this->id )
{
$this->save();
\IPS\File::claimAttachments( 'blogs-new-blog', $this->id, NULL, 'description', TRUE );
}
foreach ( array( 'blog_name' => "blogs_blog_{$this->id}", 'blog_desc' => "blogs_blog_{$this->id}_desc", 'blog_groupblog_name' => "blogs_groupblog_name_{$this->id}" ) as $fieldKey => $langKey )
{
if ( isset( $values[ $fieldKey ] ) )
if( $values['blog_member_id'] )
{
\IPS\Lang::saveCustom( 'blog', $langKey, $values[ $fieldKey ] );
if ( $fieldKey === 'blog_name' )
{
$values['seo_name'] = \IPS\Http\Url::seoTitle( ( is_array( $values[ $fieldKey ] ) ) ? $values[ $fieldKey ][ \IPS\Lang::defaultLanguage() ] : $values[ $fieldKey ] );
}
unset( $values[ $fieldKey ] );
\IPS\File::claimAttachments( 'blogs-new-blog', $this->id, NULL, 'description', TRUE );
}
else
{
\IPS\File::claimAttachments( 'blogs-new-blog-group', $this->id, NULL, 'description', TRUE );
}
}
if( isset( $values['blog_enable_rss'] ) )
/* If this is not a member blog we store the languages in the language system */
if( !$this->member_id )
{
foreach ( array( 'blog_name_group' => "blogs_blog_{$this->id}", 'blog_desc_group' => "blogs_blog_{$this->id}_desc", 'blog_groupblog_name' => "blogs_groupblog_name_{$this->id}" ) as $fieldKey => $langKey )
{
if ( isset( $values[ $fieldKey ] ) )
{
\IPS\Lang::saveCustom( 'blog', $langKey, $values[ $fieldKey ] );
if ( $fieldKey === 'blog_name' )
{
$values['seo_name'] = \IPS\Http\Url\Friendly::seoTitle( ( is_array( $values[ $fieldKey ] ) ) ? $values[ $fieldKey ][ \IPS\Lang::defaultLanguage() ] : $values[ $fieldKey ] );
}
unset( $values[ $fieldKey ] );
}
}
if( array_key_exists( 'blog_name', $values ) )
{
unset( $values['blog_name'] );
}
if( array_key_exists( 'blog_desc', $values ) )
{
unset( $values['blog_desc'] );
}
}
else
{
/* If we're changing the author of the blog update the feed */
if( isset( $values['blog_member_id'] ) )
{
try
{
$feed = \IPS\blog\Blog\Feed::constructFromData( \IPS\Db::i()->select( '*', 'blog_rss_import', array( 'rss_blog_id=?', $this->id ) )->first() );
}
catch ( \UnderflowException $e )
{
$feed = NULL;
}
if( $feed )
{
$feed->member = $values['blog_member_id'];
$feed->save();
}
}
/* This is here in case an admin changes a group blog to a member blog */
\IPS\Lang::deleteCustom( 'blog', "blogs_blog_{$this->id}" );
\IPS\Lang::deleteCustom( 'blog', "blogs_blog_{$this->id}_desc" );
\IPS\Lang::deleteCustom( 'blog', "blogs_groupblog_name_{$this->id}" );
$values['seo_name'] = \IPS\Http\Url\Friendly::seoTitle( $values['blog_name'] );
}
if( array_key_exists( 'blog_name_group', $values ) )
{
unset( $values['blog_name_group'] );
}
if( array_key_exists( 'blog_desc_group', $values ) )
{
unset( $values['blog_desc_group'] );
}
if( array_key_exists( 'blog_groupblog_name', $values ) )
{
unset( $values['blog_groupblog_name'] );
}
if( array_key_exists( 'blog_enable_rss', $values ) )
{
$values['settings'] = array( 'allowrss' => $values['blog_enable_rss'] );
unset( $values['blog_enable_rss'] );
}
/* Send to parent */
if( isset( $values['blog_member_id'] ) )
if( array_key_exists( 'blog_member_id', $values ) )
{
unset( $values['blog_member_id'] );
}
return $values;
}
/**
* [Node] Get the title to store in the log
*
* @return string|null
*/
public function titleForLog()
{
if ( !$this->member_id )
{
try
{
return \IPS\Lang::load( \IPS\Lang::defaultLanguage() )->get( static::$titleLangPrefix . $this->_id );
}
catch( \UnderflowException $e )
{
/* If we're changing from a member blog to a group blog, the language string won't exist yet */
return $this->_title;
}
}
else
{
return $this->_title;
}
}
/**
* @brief Mass update search index after changes
*/
@@ -463,13 +605,20 @@ class _Blog extends \IPS\Node\Model implements \IPS\Node\Ratings, \IPS\Content\E
*/
public function get_seo_name()
{
if( !$this->_data['seo_name'] )
/* If we have the seo_name, just return it - don't query the language string */
if( $this->_data['seo_name'] )
{
$this->seo_name = \IPS\Http\Url::seoTitle( \IPS\Lang::load( \IPS\Lang::defaultLanguage() )->get( 'blogs_blog_' . $this->id ) );
$this->save();
return $this->_data['seo_name'];
}
return $this->_data['seo_name'] ?: \IPS\Http\Url::seoTitle( \IPS\Lang::load( \IPS\Lang::defaultLanguage() )->get( 'blogs_blog_' . $this->id ) );
/* The seo_name isn't set, so let's fix that real quick and return it */
$title = $this->member_id ? $this->name : \IPS\Lang::load( \IPS\Lang::defaultLanguage() )->get( 'blogs_blog_' . $this->id );
$seoTitle = \IPS\Http\Url::seoTitle( $title );
$this->seo_name = $seoTitle;
$this->save();
return $seoTitle;
}
/**
@@ -491,6 +640,29 @@ class _Blog extends \IPS\Node\Model implements \IPS\Node\Ratings, \IPS\Content\E
* @brief Cached latest entry
*/
protected $latestEntry = NULL;
/**
* Set last comment
*
* @param \IPS\Content\Comment|NULL $comment The latest comment or NULL to work it out
* @return void
* @note Like Gallery, we actually want to set this to the last entry rather than comment. As such $comment is ignored.
*/
public function setLastComment( \IPS\Content\Comment $comment=NULL )
{
$lastUpdateColumn = static::$databaseColumnMap['date'];
if ( $latestEntry = $this->latestEntry() )
{
$this->$lastUpdateColumn = $latestEntry->date;
}
else
{
$this->$lastUpdateColumn = 0;
}
$this->save();
}
/**
* Get latest entry
@@ -527,22 +699,37 @@ class _Blog extends \IPS\Node\Model implements \IPS\Node\Ratings, \IPS\Content\E
try
{
/* Get member IDs and contributions count */
$select = \IPS\Db::i()->select(
"core_members.*, count( blog_entries.entry_id ) as contributions",
"entry_author_id, count( entry_id ) as contributions",
'blog_entries',
array( "entry_blog_id=?", $this->id ),
array( "entry_blog_id=? AND entry_author_id !=?", $this->id, 0 ),
"contributions DESC",
NULL,
array( 'member_id' )
)->join(
'core_members',
"blog_entries.entry_author_id=core_members.member_id"
);
/* Get em! */
foreach( $select as $row )
array( 'entry_author_id' )
)->setKeyField( 'entry_author_id' )->setValueField( 'contributions' );
/* Get the member ids to load them in one query */
$memberIds = array();
$members = array();
foreach( $select as $member => $contributions )
{
$contributors[] = array ( 'member' => \IPS\Member::constructFromData( $row ), 'contributions' => $row['contributions'] );
$memberIds[] = $member;
}
if( count( $memberIds ) )
{
foreach( \IPS\Db::i()->select( '*', 'core_members', 'member_id IN(' . implode( ',', $memberIds ) . ')' ) as $member )
{
$members[ $member['member_id'] ] = \IPS\Member::constructFromData( $member );
}
}
/* Get em! */
foreach( $select as $member => $contributions )
{
$contributors[] = array( 'member' => $members[ $member ], 'contributions' => $contributions );
}
}
catch ( \UnderflowException $e ) {}
@@ -672,7 +859,34 @@ class _Blog extends \IPS\Node\Model implements \IPS\Node\Ratings, \IPS\Content\E
*/
protected function get__title()
{
return htmlspecialchars( \IPS\Member::loggedIn()->language()->get( static::$titleLangPrefix . $this->_id ), ENT_QUOTES | \IPS\HTMLENTITIES, 'UTF-8', FALSE );
return $this->member_id ? $this->name : \IPS\Member::loggedIn()->language()->addToStack( static::$titleLangPrefix . $this->_id );
}
/**
* Node titles can contain HTML. Apparently.
*
* @return string
*/
public function get__stripTagsTitle()
{
if ( $this->member_id )
{
return $this->name;
}
else
{
return \IPS\Member::loggedIn()->language()->addToStack( static::$titleLangPrefix . $this->_id, NULL, array( 'striptags' => true ) );
}
}
/**
* Returns the title
*
* @return string
*/
protected function get_description()
{
return $this->member_id ? $this->desc : \IPS\Member::loggedIn()->language()->addToStack( static::$titleLangPrefix . $this->_id . static::$descriptionLangSuffix );
}
/**
@@ -721,7 +935,7 @@ class _Blog extends \IPS\Node\Model implements \IPS\Node\Ratings, \IPS\Content\E
}
catch ( \IPS\Http\Request\Exception $e )
{
\IPS\Log::i( LOG_ERR )->write( $e->getMessage() );
\IPS\Log::log( $e, 'pingomatic' );
}
}
@@ -742,19 +956,30 @@ class _Blog extends \IPS\Node\Model implements \IPS\Node\Ratings, \IPS\Content\E
*/
public function delete()
{
/* Delete RSS Imports */
\IPS\Db::i()->delete( 'blog_rss_import', array( "rss_blog_id=?", $this->_id ) );
/* Delete Language Strings */
foreach ( array( 'blog_groupblog_name' => "blogs_groupblog_name_{$this->id}" ) as $fieldKey => $langKey )
{
\IPS\Lang::deleteCustom( 'blog', $langKey );
}
/* Reset create menu */
$member = \IPS\Member::load( $this->member_id );
$member->create_menu = NULL;
$member->save();
/* Unclaim Attachments */
\IPS\File::unclaimAttachments( 'blog_Blogs', $this->id );
/* Delete Cover Photo -specifically call parent otherwise deleteOrMoveContent process cannot run within the AdminCP */
$photo = parent::coverPhoto();
$photo->delete();
/* Delete Follows */
\IPS\Db::i()->delete( 'core_follow', array( "follow_app=? AND follow_area=? AND follow_rel_id=?", 'blog', 'blog', $this->_id ) );
return parent::delete();
}
@@ -782,31 +1007,69 @@ class _Blog extends \IPS\Node\Model implements \IPS\Node\Ratings, \IPS\Content\E
}
/**
* Set last comment
* [Node] Get content table meta description
*
* @param \IPS\Content\Comment $comment The latest comment or NULL to work it out
* @return void
* @return string
*/
public function setLastComment( \IPS\Content\Comment $comment=NULL )
public function metaDescription()
{
if ( $comment === NULL )
if( $this->member_id )
{
try
{
/* @note entry_hidden is flipped to map to "approved" */
$entry = \IPS\blog\Entry::constructFromData( \IPS\Db::i()->select( '*', 'blog_entries', array( 'entry_blog_id=? AND entry_status=? AND entry_hidden=1 and entry_is_future_entry=0', $this->id, 'published' ), 'entry_date DESC', 1 )->first() );
}
catch ( \UnderflowException $e )
{
$this->last_edate = 0;
return;
}
}
else
{
$entry = $comment->item();
return strip_tags( $this->desc );
}
$this->last_edate = $entry->mapped('date');
return parent::metaDescription();
}
/**
* Get output for API
*
* @return array
* @apiresponse int id ID number
* @apiresponse string name Name
* @apiresponse string description Description
* @apiresponse \IPS\Member owner If the blog is owned by a single member, the member
* @apiresponse [\IPS\Member\Group] groups If the blog is owned by groups, an array of the groups
* @apiresponse bool pinned If the blog is pinned
* @apiresponse int entries Number of entries
* @apiresponse int comments Number of comments
* @apiresponse string url URL
*/
public function apiOutput()
{
$groups = array();
if ( $this->groupblog_ids )
{
foreach ( array_filter( explode( ',', $this->groupblog_ids ) ) as $groupId )
{
try
{
$groups[] = \IPS\Member\Group::load( $groupId )->apiOutput();
}
catch ( \OutOfRangeException $e ) { }
}
}
return array(
'id' => $this->id,
'name' => $this->_title,
'description' => $this->member_id ? $this->desc : \IPS\Member::loggedIn()->language()->addToStack("blogs_blog_{$this->id}_desc"),
'owner' => $this->member_id ? $this->owner()->apiOutput() : null,
'groups' => $groups,
'pinned' => (bool) $this->pinned,
'entries' => $this->count_entries,
'comments' => $this->count_comments,
'url' => (string) $this->url()
);
}
/**
* Permission Types
*
* @return array
*/
public function permissionTypes()
{
return array( 'view' => 'view', 'add' => 'add' );
}
}