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

+89 -62
View File
@@ -102,6 +102,11 @@ class _Blog extends \IPS\Node\Model implements \IPS\Node\Ratings, \IPS\Content\E
* @brief Cover Photo Storage Extension
*/
public static $coverPhotoStorageExtension = 'blog_Blogs';
/**
* @brief Use a default cover photo
*/
public static $coverPhotoDefault = true;
/**
* Columns needed to query for search result / stream view
@@ -111,7 +116,6 @@ class _Blog extends \IPS\Node\Model implements \IPS\Node\Ratings, \IPS\Content\E
public static function basicDataColumns()
{
$return = parent::basicDataColumns();
$return[] = 'blog_name';
$return[] = 'blog_member_id';
return $return;
}
@@ -123,7 +127,7 @@ class _Blog extends \IPS\Node\Model implements \IPS\Node\Ratings, \IPS\Content\E
*/
public static function contentTableTemplate()
{
return array( \IPS\Theme::i()->getTemplate( 'browse', 'blog' ), 'rows' );
return array( \IPS\Theme::i()->getTemplate( 'browse', 'blog', 'front' ), 'rows' );
}
/**
@@ -149,19 +153,6 @@ 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
*
@@ -258,7 +249,7 @@ class _Blog extends \IPS\Node\Model implements \IPS\Node\Ratings, \IPS\Content\E
if ( $club = $this->club() )
{
if ( $club->type == $club::TYPE_PUBLIC )
if ( $club->type == $club::TYPE_PUBLIC or $club->type == $club::TYPE_READONLY )
{
return 'ca';
}
@@ -286,21 +277,33 @@ class _Blog extends \IPS\Node\Model implements \IPS\Node\Ratings, \IPS\Content\E
/**
* Additional WHERE clauses for Follow view
*
* @param array $joins Joins
* @return array
*/
public static function followWhere()
public static function followWhere( &$joins )
{
$where = array();
if ( \IPS\Member::loggedIn()->member_id )
{
$where[] = array( '( blog_blogs.blog_social_group IS NULL OR blog_blogs.blog_member_id=' . \IPS\Member::loggedIn()->member_id . ' OR ( ' . \IPS\Content::socialGroupGetItemsWithPermissionWhere( 'blog_blogs.blog_social_group', \IPS\Member::loggedIn() ) . ' ) )' );
$where[] = array( '( blog_blogs.blog_club_id IS NULL OR ' . \IPS\Db::i()->in( 'blog_blogs.blog_club_id', \IPS\Member::loggedIn()->clubs() ) . ' )' );
}
else
{
$where[] = \IPS\Content::socialGroupGetItemsWithPermissionWhere( 'blog_blogs.blog_social_group', \IPS\Member::loggedIn() );
$where[] = array( 'blog_blogs.blog_club_id IS NULL' );
}
if ( \IPS\Settings::i()->clubs )
{
$joins[] = array( 'from' => 'core_clubs', 'where' => 'core_clubs.id=blog_blogs.blog_club_id' );
if ( \IPS\Member::loggedIn()->member_id )
{
$where[] = array( '( blog_blogs.blog_club_id IS NULL OR ' . \IPS\Db::i()->in( 'blog_blogs.blog_club_id', \IPS\Member::loggedIn()->clubs() ) . ' OR core_clubs.type=? OR core_clubs.type=? )', \IPS\Member\Club::TYPE_PUBLIC, \IPS\Member\Club::TYPE_READONLY );
}
else
{
$where[] = array( '( blog_blogs.blog_club_id IS NULL OR core_clubs.type=? OR core_clubs.type=? )', \IPS\Member\Club::TYPE_PUBLIC, \IPS\Member\Club::TYPE_READONLY );
}
}
return $where;
@@ -409,7 +412,7 @@ class _Blog extends \IPS\Node\Model implements \IPS\Node\Ratings, \IPS\Content\E
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' ) );
$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}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 ) {
@@ -552,12 +555,7 @@ class _Blog extends \IPS\Node\Model implements \IPS\Node\Ratings, \IPS\Content\E
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'] );
@@ -584,13 +582,18 @@ class _Blog extends \IPS\Node\Model implements \IPS\Node\Ratings, \IPS\Content\E
}
}
\IPS\Lang::saveCustom( 'blog', "blogs_blog_{$this->id}", $values['blog_name'] );
/* 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', $values ) )
{
unset( $values['blog_name'] );
}
if( array_key_exists( 'blog_name_group', $values ) )
{
@@ -758,7 +761,7 @@ class _Blog extends \IPS\Node\Model implements \IPS\Node\Ratings, \IPS\Content\E
try
{
/* @note entry_hidden is flipped to map to "approved" */
/* @note entry_hidden is flipped to map to "approved" and that this method will always only return the latest, visible, entry. */
$this->latestEntry = \IPS\blog\Entry::constructFromData( \IPS\Db::i()->select( '*', 'blog_entries', array( 'entry_blog_id=? AND entry_is_future_entry=0 AND entry_hidden=1 AND entry_status!=?', $this->_id, 'draft' ), 'entry_date DESC', 1 )->first() );
return $this->latestEntry;
}
@@ -783,7 +786,7 @@ class _Blog extends \IPS\Node\Model implements \IPS\Node\Ratings, \IPS\Content\E
$select = \IPS\Db::i()->select(
"entry_author_id, count( entry_id ) as contributions",
'blog_entries',
array( "entry_blog_id=? AND entry_author_id !=?", $this->id, 0 ),
array( "entry_blog_id=? AND entry_author_id !=? AND entry_hidden!=?", $this->id, 0, -2 ),
"contributions DESC",
NULL,
array( 'entry_author_id' )
@@ -932,33 +935,6 @@ class _Blog extends \IPS\Node\Model implements \IPS\Node\Ratings, \IPS\Content\E
$this->count_entries_future = $val;
}
/**
* Returns the title
*
* @return string
*/
protected function get__title()
{
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
*
@@ -968,7 +944,7 @@ class _Blog extends \IPS\Node\Model implements \IPS\Node\Ratings, \IPS\Content\E
{
return $this->member_id ? $this->desc : \IPS\Member::loggedIn()->language()->addToStack( static::$titleLangPrefix . $this->_id . static::$descriptionLangSuffix );
}
/**
* Get settings
*
@@ -1074,6 +1050,16 @@ class _Blog extends \IPS\Node\Model implements \IPS\Node\Ratings, \IPS\Content\E
$photo->overlay = \IPS\Theme::i()->getTemplate( 'view', 'blog' )->coverPhotoOverlay( $this );
return $photo;
}
/**
* Produce a random hex color for a background
*
* @return string
*/
public function coverPhotoBackgroundColor()
{
return $this->staticCoverPhotoBackgroundColor( $this->titleForLog() );
}
/**
* Get content for embed
@@ -1105,6 +1091,7 @@ class _Blog extends \IPS\Node\Model implements \IPS\Node\Ratings, \IPS\Content\E
/**
* Get output for API
*
* @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 name Name
@@ -1116,7 +1103,7 @@ class _Blog extends \IPS\Node\Model implements \IPS\Node\Ratings, \IPS\Content\E
* @apiresponse int comments Number of comments
* @apiresponse string url URL
*/
public function apiOutput()
public function apiOutput( \IPS\Member $authorizedMember = NULL )
{
$groups = array();
if ( $this->groupblog_ids )
@@ -1125,7 +1112,7 @@ class _Blog extends \IPS\Node\Model implements \IPS\Node\Ratings, \IPS\Content\E
{
try
{
$groups[] = \IPS\Member\Group::load( $groupId )->apiOutput();
$groups[] = \IPS\Member\Group::load( $groupId )->apiOutput( $authorizedMember );
}
catch ( \OutOfRangeException $e ) { }
}
@@ -1134,8 +1121,8 @@ class _Blog extends \IPS\Node\Model implements \IPS\Node\Ratings, \IPS\Content\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,
'description' => \IPS\Member::loggedIn()->language()->addToStack("blogs_blog_{$this->id}_desc"),
'owner' => $this->member_id ? $this->owner()->apiOutput( $authorizedMember ) : null,
'groups' => $groups,
'pinned' => (bool) $this->pinned,
'entries' => $this->count_entries,
@@ -1203,6 +1190,12 @@ class _Blog extends \IPS\Node\Model implements \IPS\Node\Ratings, \IPS\Content\E
{
$this->seo_name = \IPS\Http\Url\Friendly::seoTitle( $values['club_node_name'] );
}
if ( !$this->_id )
{
$this->save();
\IPS\File::claimAttachments( 'blogs-new-blog', $this->id, NULL, 'description' );
}
}
/**
@@ -1215,4 +1208,38 @@ class _Blog extends \IPS\Node\Model implements \IPS\Node\Ratings, \IPS\Content\E
{
// Deliberately do nothing, Blog handles permissions differently
}
/**
* Fetch All Nodes in Clubs
*
* @param string|NULL $permissionCheck The permission key to check for or NULl to not check permissions
* @param \IPS\Member|NULL $member The member to check permissions for or NULL for the currently logged in member
* @param mixed $where Additional WHERE clause
* @return array
*/
public static function clubNodes( $permissionCheck='view', $member=NULL, $where=array() )
{
$member = $member ?: \IPS\Member::loggedIn();
if ( $member->modPermission('can_access_all_clubs') )
{
return static::nodesWithPermission( NULL, $member, $where );
}
else
{
$where[] = array( 'blog_club_id IS NOT NULL' );
if ( $permissionCheck === 'add' )
{
$statuses = array( \IPS\Member\Club::STATUS_LEADER, \IPS\Member\Club::STATUS_MODERATOR );
}
else
{
$statuses = array( \IPS\Member\Club::STATUS_LEADER, \IPS\Member\Club::STATUS_MODERATOR, \IPS\Member\Club::STATUS_MEMBER );
}
$where[] = array( \IPS\Db::i()->in( 'status', $statuses ) );
return new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'blog_blogs', $where )->join( 'core_clubs_memberships', array( 'club_id=blog_club_id AND member_id=?', \IPS\Member::loggedIn()->member_id ) ), get_called_class() );
}
}
}