Version 5.0.0 beta 1

This commit is contained in:
Neo committed 2025-12-19 16:27:35 -08:00
1 parent 25ddeb65d6
commit 15c7beabc5
6736 files changed
+627902 -497943

No files matched your search

+60 -29
View File
@@ -11,36 +11,52 @@
namespace IPS\blog;
use IPS\Application as SystemApplication;
use IPS\Content\Filter;
use IPS\DateTime;
use IPS\Dispatcher;
use IPS\Lang;
use IPS\Login;
use IPS\Member;
use IPS\Member\Group;
use IPS\Output;
use IPS\Request;
use IPS\Settings;
use IPS\Theme;
use IPS\Xml\Rss;
use OutOfRangeException;
use function array_merge;
/**
* Blog Application Class
*/
class _Application extends \IPS\Application
class Application extends SystemApplication
{
/**
* Init
*
* @return void
*/
public function init()
public function init() : void
{
/* Handle RSS requests */
if ( \IPS\Request::i()->module == 'blogs' and \IPS\Request::i()->controller == 'view' and \IPS\Request::i()->do == 'rss' )
if ( Request::i()->module == 'blogs' and Request::i()->controller == 'view' and Request::i()->do == 'rss' )
{
$member = NULL;
if( \IPS\Request::i()->member AND \IPS\Request::i()->key )
if( Request::i()->member AND Request::i()->key )
{
$member = \IPS\Member::load( \IPS\Request::i()->member );
if( !\IPS\Login::compareHashes( $member->getUniqueMemberHash(), (string) \IPS\Request::i()->key ) )
$member = Member::load( Request::i()->member );
if( !Login::compareHashes( $member->getUniqueMemberHash(), (string) Request::i()->key ) )
{
$member = NULL;
}
}
$this->sendBlogRss( $member ?? new \IPS\Member );
$this->sendBlogRss( $member ?? new Member );
if( !\IPS\Member::loggedIn()->group['g_view_board'] )
if( !Member::loggedIn()->group['g_view_board'] )
{
\IPS\Output::i()->error( 'node_error', '2B221/1', 404, '' );
Output::i()->error( 'node_error', '2B221/1', 404, '' );
}
}
}
@@ -48,45 +64,47 @@ class _Application extends \IPS\Application
/**
* Send the blog's RSS feed for the indicated member
*
* @param \IPS\Member $member Member
* @param Member $member Member
* @return void
*/
protected function sendBlogRss( $member )
protected function sendBlogRss( Member $member ) : void
{
try
{
$blog = \IPS\blog\Blog::load( \IPS\Request::i()->id );
$blog = Blog::load( Request::i()->id );
if( !$blog->can( 'view', $member ) )
{
throw new \OutOfRangeException;
throw new OutOfRangeException;
}
}
catch ( \OutOfRangeException $e )
catch ( OutOfRangeException )
{
/* We'll let the regular controller handle the error */
return;
}
if( !\IPS\Settings::i()->blog_allow_rss or !$blog->settings['allowrss'] )
if( !Settings::i()->blog_allow_rss or !$blog->settings['allowrss'] )
{
\IPS\Output::i()->error( 'blog_rss_offline', '2B201/5', 403, 'blog_rss_offline_admin' );
Output::i()->error( 'blog_rss_offline', '2B201/5', 403, 'blog_rss_offline_admin' );
}
/* We have to use get() to ensure CDATA tags wrap the blog title properly */
$title = $blog->member_id ? $blog->name : $member->language()->get( "blogs_blog_{$blog->id}" );
$document = \IPS\Xml\Rss::newDocument( $blog->url(), $title, $blog->description );
$document = Rss::newDocument( $blog->url(), $title, $blog->description );
foreach ( \IPS\blog\Entry::getItemsWithPermission( array( array( 'entry_blog_id=?', $blog->id ), array( 'entry_status!=?', 'draft' ) ), 'entry_date DESC', 25, 'read', \IPS\Content\Hideable::FILTER_PUBLIC_ONLY, 0, $member, FALSE, FALSE, FALSE, FALSE, NULL, $blog ) as $entry )
foreach (Entry::getItemsWithPermission( array( array( 'entry_blog_id=?', $blog->id ), array( 'entry_status!=?', 'draft' ) ), 'entry_date DESC', 25, 'read', Filter::FILTER_PUBLIC_ONLY, 0, $member, FALSE, FALSE, FALSE, FALSE, NULL, $blog ) as $entry )
{
/* @var Entry $entry */
$content = $entry->content;
\IPS\Output::i()->parseFileObjectUrls( $content );
$document->addItem( $entry->name, $entry->url(), $content, \IPS\DateTime::ts( $entry->date ), $entry->id );
Output::i()->parseFileObjectUrls( $content );
$document->addItem( $entry->name, $entry->url(), $entry->content, DateTime::ts( $entry->date ), $entry->id );
}
/* @note application/rss+xml is not a registered IANA mime-type so we need to stick with text/xml for RSS */
\IPS\Output::i()->sendOutput( $document->asXML(), 200, 'text/xml', array(), TRUE, parseFileObjects: FALSE );
Output::i()->sendOutput( $document->asXML(), 200, 'text/xml', array(), TRUE, parseFileObjects: FALSE );
}
/**
@@ -94,10 +112,10 @@ class _Application extends \IPS\Application
*
* @return void
*/
public function installOther()
public function installOther() : void
{
/* Allow non guests to create and comment on Blogs */
foreach( \IPS\Member\Group::groups( TRUE, FALSE ) as $group )
foreach( Group::groups( TRUE, FALSE ) as $group )
{
$group->g_blog_allowlocal = TRUE;
$group->g_blog_allowcomment = TRUE;
@@ -105,20 +123,20 @@ class _Application extends \IPS\Application
}
/* Create new default category */
$category = new \IPS\blog\Category;
$category = new Category;
$category->seo_name = 'general';
$category->save();
\IPS\Lang::saveCustom( 'blog', "blog_category_{$category->id}", "General" );
Lang::saveCustom( 'blog', "blog_category_{$category->id}", "General" );
}
/**
* [Node] Get Icon for tree
*
* @note Return the class for the icon (e.g. 'globe')
* @return string|null
* @return string
*/
protected function get__icon()
protected function get__icon(): string
{
return 'file-text';
}
@@ -146,7 +164,7 @@ class _Application extends \IPS\Application
* @endcode
* @return array
*/
public function defaultFrontNavigation()
public function defaultFrontNavigation(): array
{
return array(
'rootTabs' => array(),
@@ -164,7 +182,20 @@ class _Application extends \IPS\Application
public function getWebhooks() : array
{
return array_merge( [
'blogBlog_create' => \IPS\blog\Blog::class
'blogBlog_create' => Blog::class
], parent::getWebhooks());
}
/**
* Output CSS files
*
* @return void
*/
public static function outputCss() : void
{
if ( Dispatcher::hasInstance() and Dispatcher::i()->controllerLocation === 'front' )
{
Output::i()->cssFiles = array_merge( Output::i()->cssFiles, Theme::i()->css( 'blog.css', 'blog', 'front' ) );
}
}
}
+9 -9
View File
@@ -10,20 +10,21 @@
*/
namespace IPS\blog\api\GraphQL;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\Types;
use IPS\blog\api\GraphQL\Mutations\CreateEntry;
use IPS\blog\api\GraphQL\Mutations\ReplyEntry;
use function defined;
/* 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' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Blog mutationss GraphQL API
*/
abstract class _Mutation
abstract class Mutation
{
/**
* Get the supported query types in this app
@@ -32,10 +33,9 @@ abstract class _Mutation
*/
public static function mutations(): array
{
$return = [
'createEntry' => new \IPS\blog\api\GraphQL\Mutations\CreateEntry(),
'replyEntry' => new \IPS\blog\api\GraphQL\Mutations\ReplyEntry(),
return [
'createEntry' => new CreateEntry(),
'replyEntry' => new ReplyEntry(),
];
return $return;
}
}
@@ -10,30 +10,37 @@
*/
namespace IPS\blog\api\GraphQL\Mutations;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\SafeException;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\blog\api\GraphQL\Types\EntryType;
use IPS\blog\Blog;
use IPS\blog\Entry;
use IPS\Content\Api\GraphQL\ItemMutator;
use IPS\Member;
use OutOfRangeException;
use function defined;
/* 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' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Create blog entry mutation for GraphQL API
*/
class _CreateEntry extends \IPS\Content\Api\GraphQL\ItemMutator
class CreateEntry extends ItemMutator
{
/**
* Class
*/
protected $class = \IPS\blog\Entry::class;
protected string $class = Entry::class;
/*
* @brief Query description
*/
public static $description = "Create a new blog entry";
public static string $description = "Create a new blog entry";
/*
* Mutation arguments
@@ -48,7 +55,7 @@ class _CreateEntry extends \IPS\Content\Api\GraphQL\ItemMutator
/**
* Return the mutation return type
*/
public function type()
public function type(): EntryType
{
return \IPS\blog\api\GraphQL\TypeRegistry::entry();
}
@@ -56,37 +63,38 @@ class _CreateEntry extends \IPS\Content\Api\GraphQL\ItemMutator
/**
* Resolves this mutation
*
* @param mixed Value passed into this resolver
* @param array Arguments
* @param array Context values
* @return \IPS\blog\Blog
* @param mixed $val Value passed into this resolver
* @param array $args Arguments
* @param array $context Context values
* @param mixed $info
* @return Entry
*/
public function resolve($val, $args, $context, $info)
public function resolve( mixed $val, array $args, array $context, mixed $info): Entry
{
/* Get blog */
try
{
$blog = \IPS\blog\Blog::loadAndCheckPerms( $args['blogID'] );
$blog = Blog::loadAndCheckPerms( $args['blogID'] );
}
catch ( \OutOfRangeException $e )
catch ( OutOfRangeException )
{
throw new \IPS\Api\GraphQL\SafeException( 'NO_BLOG', '1B300/1_graphql', 400 );
throw new SafeException( 'NO_BLOG', '1B300/1_graphql', 400 );
}
/* Check permission */
if ( !$blog->can( 'add', \IPS\Member::loggedIn() ) )
if ( !$blog->can( 'add', Member::loggedIn() ) )
{
throw new \IPS\Api\GraphQL\SafeException( 'NO_PERMISSION', '1B300/A_graphql', 403 );
throw new SafeException( 'NO_PERMISSION', '1B300/A_graphql', 403 );
}
/* Check we have a title and a post */
if ( !$args['title'] )
{
throw new \IPS\Api\GraphQL\SafeException( 'NO_TITLE', '1B300/4_graphql', 400 );
throw new SafeException( 'NO_TITLE', '1B300/4_graphql', 400 );
}
if ( !$args['content'] )
{
throw new \IPS\Api\GraphQL\SafeException( 'NO_POST', '1B300/5_grapqhl', 400 );
throw new SafeException( 'NO_POST', '1B300/5_grapqhl', 400 );
}
@@ -10,30 +10,37 @@
*/
namespace IPS\blog\api\GraphQL\Mutations;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\SafeException;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\blog\api\GraphQL\Types\CommentType;
use IPS\blog\Entry;
use IPS\blog\Entry\Comment;
use IPS\Content\Api\GraphQL\CommentMutator;
use IPS\Member;
use OutOfRangeException;
use function defined;
/* 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' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Reply to entry mutation for GraphQL API
*/
class _ReplyEntry extends \IPS\Content\Api\GraphQL\CommentMutator
class ReplyEntry extends CommentMutator
{
/**
* Class
*/
protected $class = \IPS\blog\Entry\Comment::class;
protected string $class = Comment::class;
/*
* @brief Query description
*/
public static $description = "Create a new comment";
public static string $description = "Create a new comment";
/*
* Mutation arguments
@@ -51,7 +58,7 @@ class _ReplyEntry extends \IPS\Content\Api\GraphQL\CommentMutator
/**
* Return the mutation return type
*/
public function type()
public function type(): CommentType
{
return \IPS\blog\api\GraphQL\TypeRegistry::comment();
}
@@ -59,33 +66,34 @@ class _ReplyEntry extends \IPS\Content\Api\GraphQL\CommentMutator
/**
* Resolves this mutation
*
* @param mixed Value passed into this resolver
* @param array Arguments
* @param array Context values
* @return \IPS\blog\Entry
* @param mixed $val Value passed into this resolver
* @param array $args Arguments
* @param array $context Context values
* @param array $info
* @return Comment
*/
public function resolve($val, $args, $context, $info)
public function resolve( mixed $val, array $args, array $context, array $info): Comment
{
/* Get topic */
try
{
$entry = \IPS\blog\Entry::loadAndCheckPerms( $args['entryID'] );
$entry = Entry::loadAndCheckPerms( $args['entryID'] );
}
catch ( \OutOfRangeException $e )
catch ( OutOfRangeException )
{
throw new \IPS\Api\GraphQL\SafeException( 'NO_TOPIC', '1F295/1_graphql', 403 );
throw new SafeException( 'NO_TOPIC', '1F295/1_graphql', 403 );
}
/* Get author */
if ( !$entry->canComment( \IPS\Member::loggedIn() ) )
if ( !$entry->canComment( Member::loggedIn() ) )
{
throw new \IPS\Api\GraphQL\SafeException( 'NO_PERMISSION', '2F294/A_graphql', 403 );
throw new SafeException( 'NO_PERMISSION', '2F294/A_graphql', 403 );
}
/* Check we have a post */
if ( !$args['content'] )
{
throw new \IPS\Api\GraphQL\SafeException( 'NO_POST', '1F295/3_graphql', 403 );
throw new SafeException( 'NO_POST', '1F295/3_graphql', 403 );
}
$originalPost = NULL;
@@ -94,9 +102,9 @@ class _ReplyEntry extends \IPS\Content\Api\GraphQL\CommentMutator
{
try
{
$originalPost = \IPS\blog\Entry\Comment::loadAndCheckPerms( $args['replyingTo'] );
$originalPost = Comment::loadAndCheckPerms( $args['replyingTo'] );
}
catch ( \OutOfRangeException $e )
catch ( OutOfRangeException )
{
// Just ignore it
}
+18 -13
View File
@@ -10,25 +10,29 @@
*/
namespace IPS\blog\api\GraphQL\Queries;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\blog\api\GraphQL\Types\BlogType;
use IPS\blog\Blog as BlogObject;
use OutOfRangeException;
use function defined;
/* 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' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Blog query for GraphQL API
*/
class _Blog
class Blog
{
/*
* @brief Query description
*/
public static $description = "Returns a Blog";
public static string $description = "Returns a Blog";
/*
* Query arguments
@@ -43,7 +47,7 @@ class _Blog
/**
* Return the query return type
*/
public function type()
public function type(): BlogType
{
return \IPS\blog\api\GraphQL\TypeRegistry::blog();
}
@@ -51,18 +55,19 @@ class _Blog
/**
* Resolves this query
*
* @param mixed Value passed into this resolver
* @param array Arguments
* @param array Context values
* @return \IPS\blog\Blog
* @param mixed $val Value passed into this resolver
* @param array $args Arguments
* @param array $context Context values
* @param array $info
* @return BlogObject
*/
public function resolve($val, $args, $context, $info)
public function resolve( mixed $val, array $args, array $context, array $info): BlogObject
{
$blog = \IPS\blog\Blog::load( $args['id'] );
$blog = BlogObject::load( $args[ 'id'] );
if( !$blog->can( 'view', $context['member'] ) )
{
throw new \OutOfRangeException;
throw new OutOfRangeException;
}
return $blog;
}
+15 -12
View File
@@ -10,25 +10,27 @@
*/
namespace IPS\blog\api\GraphQL\Queries;
use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\ListOfType;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\blog\Blog;
use function defined;
/* 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' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Blogs query for GraphQL API
*/
class _Blogs
class Blogs
{
/*
* @brief Query description
*/
public static $description = "Returns a list of blogs";
public static string $description = "Returns a list of blogs";
/*
* Query arguments
@@ -43,7 +45,7 @@ class _Blogs
/**
* Return the query return type
*/
public function type()
public function type(): ListOfType
{
return TypeRegistry::listOf( \IPS\blog\api\GraphQL\TypeRegistry::blog() );
}
@@ -51,14 +53,15 @@ class _Blogs
/**
* Resolves this query
*
* @param mixed Value passed into this resolver
* @param array Arguments
* @param array Context values
* @param mixed $val Value passed into this resolver
* @param array $args Arguments
* @param array $context Context values
* @param array $info
* @return array
*/
public function resolve($val, $args, $context, $info)
public function resolve( mixed $val, array $args, array $context, array $info): array
{
\IPS\blog\Blog::loadIntoMemory('view', $context['member']);
return \IPS\blog\Blog::roots();
Blog::loadIntoMemory('view', $context['member']);
return Blog::roots();
}
}
@@ -10,25 +10,35 @@
*/
namespace IPS\blog\api\GraphQL\Queries;
use GraphQL\Type\Definition\ObjectType;
use Exception;
use GraphQL\Type\Definition\ListOfType;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\blog\api\GraphQL\Types\EntryType;
use IPS\blog\Blog;
use IPS\blog\Entry;
use IPS\Db;
use IPS\Member;
use IPS\Patterns\ActiveRecordIterator;
use function count;
use function defined;
use function is_array;
/* 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' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Topics query for GraphQL API
*/
class _Entries
class Entries
{
/*
* @brief Query description
*/
public static $description = "Returns a list of blog entries";
public static string $description = "Returns a list of blog entries";
/*
* Query arguments
@@ -49,7 +59,7 @@ class _Entries
'type' => TypeRegistry::eNum([
'name' => 'blog_order_by',
'description' => 'Fields on which event can be sorted',
'values' => \IPS\blog\api\GraphQL\Types\EntryType::getOrderByOptions()
'values' => EntryType::getOrderByOptions()
]),
'defaultValue' => NULL // will use default sort option
],
@@ -71,7 +81,7 @@ class _Entries
/**
* Return the query return type
*/
public function type()
public function type(): ListOfType
{
return TypeRegistry::listOf( \IPS\blog\api\GraphQL\TypeRegistry::entry() );
}
@@ -79,29 +89,30 @@ class _Entries
/**
* Resolves this query
*
* @param mixed Value passed into this resolver
* @param array Arguments
* @param array Context values
* @return \IPS\blog\Entry
* @param mixed $val Value passed into this resolver
* @param array $args Arguments
* @param array $context Context values
* @param array $info
* @return ActiveRecordIterator
*/
public function resolve($val, $args, $context, $info)
public function resolve( mixed $val, array $args, array $context, array $info): ActiveRecordIterator
{
\IPS\blog\Blog::loadIntoMemory('view', \IPS\Member::loggedIn() );
Blog::loadIntoMemory('view', Member::loggedIn() );
$blogIds = [];
/* Are we filtering by blogs? */
if( isset( $args['blogs'] ) && \count( $args['blogs'] ) )
if( isset( $args['blogs'] ) && count( $args['blogs'] ) )
{
foreach( $args['blogs'] as $id )
{
$blog = \IPS\blog\Blog::loadAndCheckPerms( $id );
$blog = Blog::loadAndCheckPerms( $id );
$blogIds[] = $blog->id;
}
if( \count( $blogIds ) )
if( count( $blogIds ) )
{
$where['container'][] = array( \IPS\Db::i()->in( 'blog_blogs.blog_id', array_filter( $blogIds ) ) );
$where['container'][] = array( Db::i()->in( 'blog_blogs.blog_id', array_filter( $blogIds ) ) );
}
}
@@ -114,30 +125,30 @@ class _Entries
}
else
{
$orderBy = \IPS\blog\Entry::$databaseColumnMap[ $args['orderBy'] ];
$orderBy = Entry::$databaseColumnMap[ $args['orderBy'] ];
}
if( $args['orderBy'] === 'last_comment' )
{
$orderBy = \is_array( $orderBy ) ? array_pop( $orderBy ) : $orderBy;
$orderBy = is_array( $orderBy ) ? array_pop( $orderBy ) : $orderBy;
}
}
catch (\Exception $e)
catch (Exception)
{
$orderBy = 'last_post';
}
$sortBy = \IPS\blog\Entry::$databaseTable . '.' . \IPS\blog\Entry::$databasePrefix . "{$orderBy} {$args['orderDir']}";
$sortBy = Entry::$databaseTable . '.' . Entry::$databasePrefix . "{$orderBy} {$args['orderDir']}";
$offset = max( $args['offset'], 0 );
$limit = min( $args['limit'], 50 );
/* Figure out pinned status */
if ( $args['honorPinned'] )
{
$column = \IPS\blog\Entry::$databaseTable . '.' . \IPS\blog\Entry::$databasePrefix . \IPS\blog\Entry::$databaseColumnMap['pinned'];
$column = Entry::$databaseTable . '.' . Entry::$databasePrefix . Entry::$databaseColumnMap['pinned'];
$sortBy = "{$column} DESC, {$sortBy}";
}
return \IPS\blog\Entry::getItemsWithPermission( $where, $sortBy, array( $offset, $limit ), 'read' );
return Entry::getItemsWithPermission( $where, $sortBy, array( $offset, $limit ) );
}
}
+22 -17
View File
@@ -10,25 +10,29 @@
*/
namespace IPS\blog\api\GraphQL\Queries;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\SafeException;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\blog\api\GraphQL\Types\EntryType;
use IPS\blog\Entry as EntryClass;
use OutOfRangeException;
use function defined;
/* 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' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Entry query for GraphQL API
*/
class _Entry
class Entry
{
/*
* @brief Query description
*/
public static $description = "Returns a Blog Entry";
public static string $description = "Returns a Blog Entry";
/*
* Query arguments
@@ -43,7 +47,7 @@ class _Entry
/**
* Return the query return type
*/
public function type()
public function type(): EntryType
{
return \IPS\blog\api\GraphQL\TypeRegistry::entry();
}
@@ -51,25 +55,26 @@ class _Entry
/**
* Resolves this query
*
* @param mixed Value passed into this resolver
* @param array Arguments
* @param array Context values
* @return \IPS\blog\Entry
*/
public function resolve($val, $args, $context, $info)
{
* @param mixed $val Value passed into this resolver
* @param array $args Arguments
* @param array $context Context values
* @param array $info
* @return EntryClass
*/
public function resolve( mixed $val, array $args, array $context, array $info): EntryClass
{
try
{
$entry = \IPS\blog\Entry::loadAndCheckPerms( $args['id'] );
$entry = EntryClass::loadAndCheckPerms( $args['id'] );
}
catch ( \OutOfRangeException $e )
catch ( OutOfRangeException )
{
throw new \IPS\Api\GraphQL\SafeException( 'NO_TOPIC', '2B300/A_graphql', 400 );
throw new SafeException( 'NO_TOPIC', '2B300/A_graphql', 400 );
}
if( !$entry->can('read') )
{
throw new \IPS\Api\GraphQL\SafeException( 'NO_PERMISSION', '2B300/9_graphql', 403 );
throw new SafeException( 'NO_PERMISSION', '2B300/9_graphql', 403 );
}
return $entry;
+12 -9
View File
@@ -10,20 +10,23 @@
*/
namespace IPS\blog\api\GraphQL;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\Types;
use IPS\blog\api\GraphQL\Queries\Blog;
use IPS\blog\api\GraphQL\Queries\Blogs;
use IPS\blog\api\GraphQL\Queries\Entries;
use IPS\blog\api\GraphQL\Queries\Entry;
use function defined;
/* 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' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Blog queries for GraphQL API
*/
abstract class _Query
abstract class Query
{
/**
* Get the supported query types in this app
@@ -33,10 +36,10 @@ abstract class _Query
public static function queries(): array
{
return [
'blogs' => new \IPS\blog\api\GraphQL\Queries\Blogs(),
'blog' => new \IPS\blog\api\GraphQL\Queries\Blog(),
'entries' => new \IPS\blog\api\GraphQL\Queries\Entries(),
'entry' => new \IPS\blog\api\GraphQL\Queries\Entry(),
'blogs' => new Blogs(),
'blog' => new Blog(),
'entries' => new Entries(),
'entry' => new Entry(),
];
}
}
+19 -18
View File
@@ -10,37 +10,38 @@
*/
namespace IPS\blog\api\GraphQL;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\Types;
use IPS\blog\api\GraphQL\Types\_BlogType;
use IPS\blog\api\GraphQL\Types\BlogType;
use IPS\blog\api\GraphQL\Types\CommentType;
use IPS\blog\api\GraphQL\Types\EntryType;
use function defined;
/* 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' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
class _TypeRegistry
class TypeRegistry
{
/**
* The blog type instance
* @var \IPS\blog\api\GraphQL\Types\BlogType
* @var BlogType
*/
protected static $blog;
protected static BlogType $blog;
/**
* The blog entry type instance
* @var \IPS\blog\api\GraphQL\Types\EntryType
* @var EntryType
*/
protected static $entry;
protected static EntryType $entry;
/**
* The entry comment instance
* @var \IPS\blog\api\GraphQL\Types\CommentType
* @var CommentType
*/
protected static $comment;
protected static CommentType $comment;
/**
* Constructor
@@ -53,24 +54,24 @@ class _TypeRegistry
/**
* @return BlogType
*/
public static function blog(): \IPS\blog\api\GraphQL\Types\BlogType
public static function blog(): BlogType
{
return self::$blog ?: (self::$blog = new \IPS\blog\api\GraphQL\Types\BlogType());
return self::$blog ?? (self::$blog = new BlogType());
}
/**
* @return EntryType
*/
public static function entry(): \IPS\blog\api\GraphQL\Types\EntryType
public static function entry(): EntryType
{
return self::$entry ?: (self::$entry = new \IPS\blog\api\GraphQL\Types\EntryType());
return self::$entry ?? (self::$entry = new EntryType());
}
/**
* @return CommentType
*/
public static function comment(): \IPS\blog\api\GraphQL\Types\CommentType
public static function comment(): CommentType
{
return self::$comment ?: (self::$comment = new \IPS\blog\api\GraphQL\Types\CommentType());
return self::$comment??( self::$comment = new CommentType() );
}
}
@@ -11,39 +11,42 @@
namespace IPS\blog\api\GraphQL\Types;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\blog\api\GraphQL\TypeRegistry;
use IPS\blog\Blog;
use IPS\Node\Api\GraphQL\NodeType;
use function defined;
/* 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' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* BlogType for GraphQL API
*/
class _BlogType extends \IPS\Node\Api\GraphQL\NodeType
class BlogType extends NodeType
{
/*
* @brief The item classname we use for this type
*/
protected static $nodeClass = \IPS\blog\Blog::class;
protected static string $nodeClass = Blog::class;
/*
* @brief GraphQL type name
*/
protected static $typeName = 'blog_Blog';
protected static string $typeName = 'blog_Blog';
/*
* @brief GraphQL type description
*/
protected static $typeDescription = 'A blog';
protected static string $typeDescription = 'A blog';
/*
* @brief Follow data passed in to FollowType resolver
*/
protected static $followData = array('app' => 'blog', 'area' => 'blog');
protected static array $followData = array('app' => 'blog', 'area' => 'blog');
/**
@@ -51,8 +54,8 @@ class _BlogType extends \IPS\Node\Api\GraphQL\NodeType
*
* @return ObjectType
*/
public static function getItemType()
{
return \IPS\blog\api\GraphQL\TypeRegistry::entry();
public static function getItemType(): ObjectType
{
return TypeRegistry::entry();
}
}
@@ -11,43 +11,46 @@
namespace IPS\blog\api\GraphQL\Types;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\blog\api\GraphQL\TypeRegistry;
use IPS\blog\Entry\Comment;
use IPS\Content\Api\GraphQL\CommentType as ApiCommentType;
use function defined;
/* 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' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* PostType for GraphQL API
*/
class _CommentType extends \IPS\Content\Api\GraphQL\CommentType
class CommentType extends ApiCommentType
{
/*
* @brief The item classname we use for this type
*/
protected static $commentClass = \IPS\blog\Entry\Comment::class;
protected static string $commentClass = Comment::class;
/*
* @brief GraphQL type name
*/
protected static $typeName = 'blog_Comment';
protected static string $typeName = 'blog_Comment';
/*
* @brief GraphQL type description
*/
protected static $typeDescription = 'A blog comment';
protected static string $typeDescription = 'A blog comment';
/**
* Get the item type that goes with this item type
*
* @return ObjectType
*/
public static function getItemType()
{
return \IPS\blog\api\GraphQL\TypeRegistry::comment();
public static function getItemType(): ObjectType
{
return TypeRegistry::comment();
}
/**
@@ -55,12 +58,12 @@ class _CommentType extends \IPS\Content\Api\GraphQL\CommentType
*
* @return array
*/
public function fields()
{
public function fields(): array
{
$defaultFields = parent::fields();
$postFields = array(
'entry' => [
'type' => \IPS\blog\api\GraphQL\TypeRegistry::entry(),
'type' => TypeRegistry::entry(),
'resolve' => function ($comment) {
return $comment->item();
}
@@ -11,48 +11,50 @@
namespace IPS\blog\api\GraphQL\Types;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\_TypeRegistry;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\blog\api\GraphQL\TypeRegistry;
use IPS\blog\Entry;
use IPS\Content\Api\GraphQL\ItemType;
use function defined;
/* 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' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Entry for GraphQL API
*/
class _EntryType extends \IPS\Content\Api\GraphQL\ItemType
class EntryType extends ItemType
{
/*
* @brief The item classname we use for this type
*/
protected static $itemClass = \IPS\blog\Entry::class;
protected static string $itemClass = Entry::class;
/*
* @brief GraphQL type name
*/
protected static $typeName = 'blog_Entry';
protected static string $typeName = 'blog_Entry';
/*
* @brief GraphQL type description
*/
protected static $typeDescription = 'A blog entry';
protected static string $typeDescription = 'A blog entry';
/*
* @brief Follow data passed in to FollowType resolver
*/
protected static $followData = array('app' => 'blogs', 'area' => 'entry');
protected static array $followData = array('app' => 'blogs', 'area' => 'entry');
/**
* Get the comment type that goes with this item type
*
* @return ObjectType
*/
protected static function getCommentType()
{
return \IPS\blog\api\GraphQL\TypeRegistry::comment();
protected static function getCommentType(): ObjectType
{
return TypeRegistry::comment();
}
}
+49 -31
View File
@@ -1,4 +1,5 @@
<?php
/**
* @brief Blog Blogs API
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
@@ -12,22 +13,35 @@
namespace IPS\blog\api;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use IPS\Api\Exception;
use IPS\Api\PaginatedResponse;
use IPS\Api\Response;
use IPS\blog\Blog;
use IPS\Db;
use IPS\Node\Api\NodeController;
use IPS\Request;
use OutOfRangeException;
use function defined;
use function in_array;
use function intval;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* @brief Blog Blogs API
*/
class _blogs extends \IPS\Node\Api\NodeController
class blogs extends NodeController
{
/**
* Class
*/
protected $class = 'IPS\blog\Blog';
protected string $class = 'IPS\blog\Blog';
/**
* GET /blog/blogs
@@ -42,31 +56,32 @@ class _blogs extends \IPS\Node\Api\NodeController
* @apiparam string sortDir Sort direction. Can be 'asc' or 'desc' - defaults to 'asc'
* @apiparam int page Page number
* @apiparam int perPage Number of results per page - defaults to 25
* @return \IPS\Api\PaginatedResponse<IPS\blog\Entry>
* @apireturn PaginatedResponse<\IPS\blog\Blog>
* @return PaginatedResponse<Blog>
*/
public function GETindex()
public function GETindex(): PaginatedResponse
{
/* Where clause */
$where = $this->_globalWhere();
/* Owners */
if ( isset( \IPS\Request::i()->owners ) and isset( \IPS\Request::i()->groups ) )
if ( isset( Request::i()->owners ) and isset( Request::i()->groups ) )
{
$where[] = array( '( ' . \IPS\Db::i()->in( 'blog_member_id', array_filter( explode( ',', \IPS\Request::i()->owners ) ) ) . ' OR ' . \IPS\Db::i()->findInSet( 'blog_groupblog_ids', array_filter( explode( ',', \IPS\Request::i()->groups ) ) ) . ' )' );
$where[] = array( '( ' . Db::i()->in( 'blog_member_id', array_filter( explode( ',', Request::i()->owners ) ) ) . ' OR ' . Db::i()->findInSet( 'blog_groupblog_ids', array_filter( explode( ',', Request::i()->groups ) ) ) . ' )' );
}
elseif ( isset( \IPS\Request::i()->owners ) )
elseif ( isset( Request::i()->owners ) )
{
$where[] = array( '( ' . \IPS\Db::i()->in( 'blog_member_id', array_filter( explode( ',', \IPS\Request::i()->owners ) ) ) . ' OR blog_groupblog_ids<>? )', '' );
$where[] = array( '( ' . Db::i()->in( 'blog_member_id', array_filter( explode( ',', Request::i()->owners ) ) ) . ' OR blog_groupblog_ids<>? )', '' );
}
elseif ( isset( \IPS\Request::i()->groups ) )
elseif ( isset( Request::i()->groups ) )
{
$where[] = array( '( blog_member_id>0 OR ' . \IPS\Db::i()->findInSet( 'blog_groupblog_ids', array_filter( explode( ',', \IPS\Request::i()->groups ) ) ) . ' )' );
$where[] = array( '( blog_member_id>0 OR ' . Db::i()->findInSet( 'blog_groupblog_ids', array_filter( explode( ',', Request::i()->groups ) ) ) . ' )' );
}
/* Pinned */
if ( isset( \IPS\Request::i()->pinned ) )
if ( isset( Request::i()->pinned ) )
{
$where[] = array( 'blog_pinned=?', \intval( \IPS\Request::i()->pinned ) );
$where[] = array( 'blog_pinned=?', intval( Request::i()->pinned ) );
}
/* Permission */
@@ -76,25 +91,25 @@ class _blogs extends \IPS\Node\Api\NodeController
}
/* Sort */
if ( isset( \IPS\Request::i()->sortBy ) and \in_array( \IPS\Request::i()->sortBy, array( 'count_entries', 'last_edate' ) ) )
if ( isset( Request::i()->sortBy ) and in_array( Request::i()->sortBy, array( 'count_entries', 'last_edate' ) ) )
{
$sortBy = 'blog_' . \IPS\Request::i()->sortBy;
$sortBy = 'blog_' . Request::i()->sortBy;
}
else
{
$sortBy = 'blog_id';
}
$sortDir = ( isset( \IPS\Request::i()->sortDir ) and \in_array( mb_strtolower( \IPS\Request::i()->sortDir ), array( 'asc', 'desc' ) ) ) ? \IPS\Request::i()->sortDir : 'asc';
$sortDir = ( isset( Request::i()->sortDir ) and in_array( mb_strtolower( Request::i()->sortDir ), array( 'asc', 'desc' ) ) ) ? Request::i()->sortDir : 'asc';
/* Return */
return new \IPS\Api\PaginatedResponse(
return new PaginatedResponse(
200,
\IPS\Db::i()->select( '*', 'blog_blogs', $where, "{$sortBy} {$sortDir}" ),
isset( \IPS\Request::i()->page ) ? \IPS\Request::i()->page : 1,
Db::i()->select( '*', 'blog_blogs', $where, "{$sortBy} {$sortDir}" ),
isset( Request::i()->page ) ? Request::i()->page : 1,
'IPS\blog\Blog',
\IPS\Db::i()->select( 'COUNT(*)', 'blog_blogs', $where )->first(),
Db::i()->select( 'COUNT(*)', 'blog_blogs', $where )->first(),
$this->member,
isset( \IPS\Request::i()->perPage ) ? \IPS\Request::i()->perPage : NULL
isset( Request::i()->perPage ) ? Request::i()->perPage : NULL
);
}
@@ -104,9 +119,10 @@ class _blogs extends \IPS\Node\Api\NodeController
*
* @param int $id ID Number
* @throws 2B302/1 INVALID_ID The blog ID does not exist or the authorized user does not have permission to view it
* @return \IPS\blog\Blog
* @apireturn \IPS\blog\Blog
* @return Response
*/
public function GETitem( $id )
public function GETitem( int $id ): Response
{
return $this->_view( $id );
}
@@ -116,28 +132,30 @@ class _blogs extends \IPS\Node\Api\NodeController
* Delete a blog
*
* @param int $id ID Number
* @return void
* @apireturn void
* @return Response
* @throws 2B302/2 INVALID_ID The blog ID does not exist or the authorized user does not have permission to view it
* @throws 2B302/3 NO_PERMISSION The authorized user does not have permission to delete the blog
*/
public function DELETEitem( $id )
public function DELETEitem( int $id ): Response
{
/* @var Blog $class */
$class = $this->class;
try
{
$blog = $this->member ? $class::loadAndCheckPerms( $id ) : $class::load( $id );
if ( !$blog->canDelete( $this->member ) )
if ( !$blog->canDelete() )
{
throw new \IPS\Api\Exception( 'INVALID_ID', '2B302/3', 404 );
throw new Exception( 'INVALID_ID', '2B302/3', 404 );
}
$blog->delete();
return new \IPS\Api\Response( 200, NULL );
return new Response( 200, NULL );
}
catch ( \OutOfRangeException $e )
catch ( OutOfRangeException $e )
{
throw new \IPS\Api\Exception( 'INVALID_ID', '2B302/2', 404 );
throw new Exception( 'INVALID_ID', '2B302/2', 404 );
}
}
}
+59 -37
View File
@@ -12,22 +12,37 @@
namespace IPS\blog\api;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use IPS\Api\Exception;
use IPS\Api\PaginatedResponse;
use IPS\Api\Response;
use IPS\blog\Category;
use IPS\Db;
use IPS\Http\Url\Friendly;
use IPS\Lang;
use IPS\Node\Api\NodeController;
use IPS\Node\Model;
use IPS\Request;
use OutOfRangeException;
use function defined;
use function in_array;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* @brief Blog Blogs API
*/
class _categories extends \IPS\Node\Api\NodeController
class categories extends NodeController
{
/**
* Class
*/
protected $class = 'IPS\blog\Category';
protected string $class = 'IPS\blog\Category';
/**
* GET /blog/categories
@@ -38,33 +53,34 @@ class _categories extends \IPS\Node\Api\NodeController
* @apiparam string sortDir Sort direction. Can be 'asc' or 'desc' - defaults to 'asc'
* @apiparam int page Page number
* @apiparam int perPage Number of results per page - defaults to 25
* @return \IPS\Api\PaginatedResponse<IPS\blog\Entry>
* @apireturn PaginatedResponse<IPS\blog\Category>
* @return PaginatedResponse<Category>
*/
public function GETindex()
public function GETindex(): PaginatedResponse
{
/* Where clause */
$where = $this->_globalWhere();
/* Sort */
if ( isset( \IPS\Request::i()->sortBy ) and \in_array( \IPS\Request::i()->sortBy, array( 'position' ) ) )
if ( isset( Request::i()->sortBy ) and Request::i()->sortBy == 'position' )
{
$sortBy = 'category_' . \IPS\Request::i()->sortBy;
$sortBy = 'category_' . Request::i()->sortBy;
}
else
{
$sortBy = 'category_id';
}
$sortDir = ( isset( \IPS\Request::i()->sortDir ) and \in_array( mb_strtolower( \IPS\Request::i()->sortDir ), array( 'asc', 'desc' ) ) ) ? \IPS\Request::i()->sortDir : 'asc';
$sortDir = ( isset( Request::i()->sortDir ) and in_array( mb_strtolower( Request::i()->sortDir ), array( 'asc', 'desc' ) ) ) ? Request::i()->sortDir : 'asc';
/* Return */
return new \IPS\Api\PaginatedResponse(
return new PaginatedResponse(
200,
\IPS\Db::i()->select( '*', 'blog_categories', $where, "{$sortBy} {$sortDir}" ),
isset( \IPS\Request::i()->page ) ? \IPS\Request::i()->page : 1,
Db::i()->select( '*', 'blog_categories', $where, "{$sortBy} {$sortDir}" ),
isset( Request::i()->page ) ? Request::i()->page : 1,
'IPS\blog\Category',
\IPS\Db::i()->select( 'COUNT(*)', 'blog_categories', $where )->first(),
Db::i()->select( 'COUNT(*)', 'blog_categories', $where )->first(),
$this->member,
isset( \IPS\Request::i()->perPage ) ? \IPS\Request::i()->perPage : NULL
isset( Request::i()->perPage ) ? Request::i()->perPage : NULL
);
}
@@ -73,9 +89,10 @@ class _categories extends \IPS\Node\Api\NodeController
* Get information about a specific blog category
*
* @param int $id ID Number
* @return \IPS\blog\Blog
* @apireturn \IPS\blog\Category
* @return Response
*/
public function GETitem( $id )
public function GETitem( int $id ): Response
{
return $this->_view( $id );
}
@@ -88,17 +105,18 @@ class _categories extends \IPS\Node\Api\NodeController
* @reqapiparam string name The category name
* @apiparam int|null parent The ID number of the parent the category should be created in. NULL for root.
* @apiparam int position The category position
* @return \IPS\blog\Category
* @apireturn \IPS\blog\Category
* @throws 1B408/1 NO_TITLE A name for the category must be supplied
* @return Response
*/
public function POSTindex()
public function POSTindex(): Response
{
if ( !\IPS\Request::i()->name )
if ( !Request::i()->name )
{
throw new \IPS\Api\Exception( 'NO_TITLE', '1B408/1', 400 );
throw new Exception( 'NO_TITLE', '1B408/1', 400 );
}
return new \IPS\Api\Response( 201, $this->_create()->apiOutput( $this->member ) );
return new Response( 201, $this->_create()->apiOutput( $this->member ) );
}
/**
@@ -110,14 +128,16 @@ class _categories extends \IPS\Node\Api\NodeController
* @apiparam int|null parent The ID number of the parent the category should be created in. NULL for root.
* @apiparam int position The category position
* @param int $id ID Number
* @return \IPS\blog\Category
* @apireturn \IPS\blog\Category
* @return Response
*/
public function POSTitem( $id )
public function POSTitem( int $id ): Response
{
/* @var Category $class */
$class = $this->class;
$category = $class::load( $id );
return new \IPS\Api\Response( 200, $this->_createOrUpdate( $category )->apiOutput( $this->member ) );
return new Response( 200, $this->_createOrUpdate( $category )->apiOutput( $this->member ) );
}
/**
@@ -126,11 +146,13 @@ class _categories extends \IPS\Node\Api\NodeController
*
* @apiclientonly
* @param int $id ID Number
* @return void
* @apireturn void
* @return Response
* @throws 2B408/3 INVALID_ID The blog category ID does not exist or the authorized user does not have permission to delete it
*/
public function DELETEitem( $id )
public function DELETEitem( int $id ): Response
{
/* @var Category $class */
$class = $this->class;
try
@@ -138,31 +160,31 @@ class _categories extends \IPS\Node\Api\NodeController
$category = $class::load( $id );
$category->delete();
return new \IPS\Api\Response( 200, NULL );
return new Response( 200, NULL );
}
catch ( \OutOfRangeException $e )
catch ( OutOfRangeException $e )
{
throw new \IPS\Api\Exception( 'INVALID_ID', '2B408/3', 404 );
throw new Exception( 'INVALID_ID', '2B408/3', 404 );
}
}
/**
* Create or update node
*
* @param \IPS\Node\Model $category The node
* @return \IPS\Node\Model
* @param Model $node The node
* @return Model
*/
protected function _createOrUpdate( \IPS\Node\Model $category )
protected function _createOrUpdate( Model $node ): Model
{
if ( isset( \IPS\Request::i()->name ) )
if ( isset( Request::i()->name ) )
{
\IPS\Lang::saveCustom( 'blog', "blog_category_{$category->id}", \IPS\Request::i()->name );
Lang::saveCustom( 'blog', "blog_category_{$node->id}", Request::i()->name );
$category->seo_name = \IPS\Http\Url\Friendly::seoTitle( \IPS\Request::i()->name );
$node->seo_name = Friendly::seoTitle( Request::i()->name );
}
$category->parent = (int) \IPS\Request::i()->parent?: \IPS\blog\Category::$databaseColumnParentRootValue;
$node->parent = (int) Request::i()->parent?: Category::$databaseColumnParentRootValue;
return parent::_createOrUpdate( $category );
return parent::_createOrUpdate( $node );
}
}
+73 -50
View File
@@ -12,21 +12,34 @@
namespace IPS\blog\api;
/* To prentry PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use InvalidArgumentException;
use IPS\Api\Exception;
use IPS\Api\PaginatedResponse;
use IPS\Api\Response;
use IPS\blog\Entry;
use IPS\blog\Entry\Comment;
use IPS\Content\Api\CommentController;
use IPS\Member;
use IPS\Request;
use OutOfRangeException;
use function defined;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* @brief Blog Entry Comments API
*/
class _comments extends \IPS\Content\Api\CommentController
class comments extends CommentController
{
/**
* Class
*/
protected $class = 'IPS\blog\Entry\Comment';
protected string $class = 'IPS\blog\Entry\Comment';
/**
* GET /blog/comments
@@ -43,9 +56,10 @@ class _comments extends \IPS\Content\Api\CommentController
* @apiparam string sortDir Sort direction. Can be 'asc' or 'desc' - defaults to 'asc'
* @apiparam int page Page number
* @apiparam int perPage Number of results per page - defaults to 25
* @return \IPS\Api\PaginatedResponse<IPS\blog\Entry\Comment>
* @apireturn PaginatedResponse<IPS\blog\Entry\Comment>
* @return PaginatedResponse<Comment>
*/
public function GETindex()
public function GETindex(): PaginatedResponse
{
/* Where clause */
$where = array();
@@ -55,9 +69,9 @@ class _comments extends \IPS\Content\Api\CommentController
{
$where[] = array( 'entry_status=?', 'published' );
}
elseif ( isset( \IPS\Request::i()->draft ) )
elseif ( isset( Request::i()->draft ) )
{
$where[] = array( 'entry_status=?', \IPS\Request::i()->draft ? 'draft' : 'published' );
$where[] = array( 'entry_status=?', Request::i()->draft ? 'draft' : 'published' );
}
/* Return */
@@ -70,12 +84,14 @@ class _comments extends \IPS\Content\Api\CommentController
*
* @param int $id ID Number
* @throws 2B301/1 INVALID_ID The comment ID does not exist or the authorized user does not have permission to view it
* @return \IPS\blog\Entry\Comment
* @apireturn \IPS\blog\Entry\Comment
* @return Response
*/
public function GETitem( $id )
public function GETitem( int $id ): Response
{
try
{
/* @var Comment $class */
$class = $this->class;
if ( $this->member )
{
@@ -86,11 +102,11 @@ class _comments extends \IPS\Content\Api\CommentController
$object = $class::load( $id );
}
return new \IPS\Api\Response( 200, $object->apiOutput( $this->member ) );
return new Response( 200, $object->apiOutput( $this->member ) );
}
catch ( \OutOfRangeException $e )
catch ( OutOfRangeException $e )
{
throw new \IPS\Api\Exception( 'INVALID_ID', '2B301/1', 404 );
throw new Exception( 'INVALID_ID', '2B301/1', 404 );
}
}
@@ -111,18 +127,19 @@ class _comments extends \IPS\Content\Api\CommentController
* @throws 1B301/3 NO_AUTHOR The author ID does not exist
* @throws 1B301/4 NO_CONTENT No content was supplied
* @throws 2B301/8 NO_PERMISSION The authorized user does not have permission to comment on that blog entry
* @return \IPS\blog\Entry\Comment
* @apireturn \IPS\blog\Entry\Comment
* @return Response
*/
public function POSTindex()
public function POSTindex(): Response
{
/* Get entry */
try
{
$entry = \IPS\blog\Entry::load( \IPS\Request::i()->entry );
$entry = Entry::load( Request::i()->entry );
}
catch ( \OutOfRangeException $e )
catch ( OutOfRangeException $e )
{
throw new \IPS\Api\Exception( 'INVALID_ID', '2B301/2', 403 );
throw new Exception( 'INVALID_ID', '2B301/2', 403 );
}
/* Get author */
@@ -130,38 +147,38 @@ class _comments extends \IPS\Content\Api\CommentController
{
if ( !$entry->canComment( $this->member ) )
{
throw new \IPS\Api\Exception( 'NO_PERMISSION', '2B301/8', 403 );
throw new Exception( 'NO_PERMISSION', '2B301/8', 403 );
}
$author = $this->member;
}
else
{
if ( \IPS\Request::i()->author )
if ( Request::i()->author )
{
$author = \IPS\Member::load( \IPS\Request::i()->author );
$author = Member::load( Request::i()->author );
if ( !$author->member_id )
{
throw new \IPS\Api\Exception( 'NO_AUTHOR', '1B301/3', 404 );
throw new Exception( 'NO_AUTHOR', '1B301/3', 404 );
}
}
else
{
if ( (int) \IPS\Request::i()->author === 0 )
if ( Request::i()->author === 0 )
{
$author = new \IPS\Member;
$author->name = \IPS\Request::i()->author_name;
$author = new Member;
$author->name = Request::i()->author_name;
}
else
{
throw new \IPS\Api\Exception( 'NO_AUTHOR', '1B301/3', 400 );
throw new Exception( 'NO_AUTHOR', '1B301/3', 400 );
}
}
}
/* Check we have a post */
if ( !\IPS\Request::i()->content )
if ( !Request::i()->content )
{
throw new \IPS\Api\Exception( 'NO_CONTENT', '1B301/4', 403 );
throw new Exception( 'NO_CONTENT', '1B301/4', 403 );
}
/* Do it */
@@ -181,21 +198,22 @@ class _comments extends \IPS\Content\Api\CommentController
* @throws 2B301/5 INVALID_ID The comment ID does not exist or the authorized user does not have permission to view it
* @throws 1B301/6 NO_AUTHOR The author ID does not exist
* @throws 2B301/9 NO_PERMISSION The authorized user does not have permission to edit the comment
* @return \IPS\blog\Entry\Comment
* @apireturn \IPS\blog\Entry\Comment
* @return Response
*/
public function POSTitem( $id )
public function POSTitem( int $id ): Response
{
try
{
/* Load */
$comment = \IPS\blog\Entry\Comment::load( $id );
$comment = Comment::load( $id );
if ( $this->member and !$comment->canView( $this->member ) )
{
throw new \OutOfRangeException;
throw new OutOfRangeException;
}
if ( $this->member and !$comment->canEdit( $this->member ) )
{
throw new \IPS\Api\Exception( 'NO_PERMISSION', '2B301/9', 403 );
throw new Exception( 'NO_PERMISSION', '2B301/9', 403 );
}
/* Do it */
@@ -203,14 +221,14 @@ class _comments extends \IPS\Content\Api\CommentController
{
return $this->_edit( $comment );
}
catch ( \InvalidArgumentException $e )
catch ( InvalidArgumentException $e )
{
throw new \IPS\Api\Exception( 'NO_AUTHOR', '1B301/6', 400 );
throw new Exception( 'NO_AUTHOR', '1B301/6', 400 );
}
}
catch ( \OutOfRangeException $e )
catch ( OutOfRangeException $e )
{
throw new \IPS\Api\Exception( 'INVALID_ID', '2B301/5', 404 );
throw new Exception( 'INVALID_ID', '2B301/5', 404 );
}
}
@@ -221,25 +239,27 @@ class _comments extends \IPS\Content\Api\CommentController
* @param int $id ID Number
* @throws 2B301/7 INVALID_ID The comment ID does not exist
* @throws 2B301/A NO_PERMISSION The authorized user does not have permission to delete the comment
* @return void
* @apireturn void
* @return Response
*/
public function DELETEitem( $id )
public function DELETEitem( int $id ): Response
{
try
{
{
/* @var Comment $class */
$class = $this->class;
$object = $class::load( $id );
if ( $this->member and !$object->canDelete( $this->member ) )
{
throw new \IPS\Api\Exception( 'NO_PERMISSION', '2B301/A', 403 );
throw new Exception( 'NO_PERMISSION', '2B301/A', 403 );
}
$object->delete();
return new \IPS\Api\Response( 200, NULL );
return new Response( 200, NULL );
}
catch ( \OutOfRangeException $e )
catch ( OutOfRangeException $e )
{
throw new \IPS\Api\Exception( 'INVALID_ID', '2B301/7', 404 );
throw new Exception( 'INVALID_ID', '2B301/7', 404 );
}
}
@@ -250,14 +270,15 @@ class _comments extends \IPS\Content\Api\CommentController
* @param int $id ID Number
* @apiparam int id ID of the reaction to add
* @apiparam int author ID of the member reacting
* @return \IPS\blog\Entry\Comment
* @apireturn \IPS\blog\Entry\Comment
* @throws 1S425/2 NO_REACTION The reaction ID does not exist
* @throws 1S425/3 NO_AUTHOR The author ID does not exist
* @throws 1S425/4 REACT_ERROR Error adding the reaction
* @throws 1S425/5 INVALID_ID Object ID does not exist
* @note If the author has already reacted to this content, any existing reaction will be removed first
* @return Response
*/
public function POSTitem_react( $id )
public function POSTitem_react( int $id ): Response
{
return $this->_reactAdd( $id );
}
@@ -268,13 +289,14 @@ class _comments extends \IPS\Content\Api\CommentController
*
* @param int $id ID Number
* @apiparam int author ID of the member who reacted
* @return \IPS\blog\Entry\Comment
* @apireturn \IPS\blog\Entry\Comment
* @throws 1S425/6 NO_AUTHOR The author ID does not exist
* @throws 1S425/7 REACT_ERROR Error adding the reaction
* @throws 1S425/8 INVALID_ID Object ID does not exist
* @note If the author has already reacted to this content, any existing reaction will be removed first
* @return Response
*/
public function DELETEitem_react( $id )
public function DELETEitem_react( int $id ): Response
{
return $this->_reactRemove( $id );
}
@@ -289,9 +311,10 @@ class _comments extends \IPS\Content\Api\CommentController
* @apiparam string message Optional message
* @throws 1S425/B NO_AUTHOR The author ID does not exist
* @throws 1S425/C REPORTED_ALREADY The member has reported this item in the past 24 hours
* @return \IPS\blog\Entry\Comment
* @apireturn \IPS\blog\Entry\Comment
* @return Response
*/
public function POSTitem_report( $id )
public function POSTitem_report( int $id ): Response
{
return $this->_report( $id );
}
+89 -68
View File
@@ -12,21 +12,36 @@
namespace IPS\blog\api;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use IPS\Api\Exception;
use IPS\Api\PaginatedResponse;
use IPS\Api\Response;
use IPS\blog\Blog;
use IPS\blog\Entry;
use IPS\blog\Entry\Comment;
use IPS\Content\Api\ItemController;
use IPS\Content\Item;
use IPS\Member;
use IPS\Request;
use IPS\Text\Parser;
use OutOfRangeException;
use function defined;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* @brief Blog Entries API
*/
class _entries extends \IPS\Content\Api\ItemController
class entries extends ItemController
{
/**
* Class
*/
protected $class = 'IPS\blog\Entry';
protected string $class = 'IPS\blog\Entry';
/**
* GET /blog/entries
@@ -45,9 +60,10 @@ class _entries extends \IPS\Content\Api\ItemController
* @apiparam string sortDir Sort direction. Can be 'asc' or 'desc' - defaults to 'asc'
* @apiparam int page Page number
* @apiparam int perPage Number of results per page - defaults to 25
* @return \IPS\Api\PaginatedResponse<IPS\blog\Entry>
* @apireturn PaginatedResponse<IPS\blog\Entry>
* @return PaginatedResponse<Entry>
*/
public function GETindex()
public function GETindex(): PaginatedResponse
{
/* Where clause */
$where = array();
@@ -57,9 +73,9 @@ class _entries extends \IPS\Content\Api\ItemController
{
$where[] = array( 'entry_status=? AND blog_disabled=0 AND blog_social_group IS NULL AND blog_club_id IS NULL', 'published' );
}
elseif ( isset( \IPS\Request::i()->draft ) )
elseif ( isset( Request::i()->draft ) )
{
$where[] = array( 'entry_status=?', \IPS\Request::i()->draft ? 'draft' : 'published' );
$where[] = array( 'entry_status=?', Request::i()->draft ? 'draft' : 'published' );
}
/* Return */
@@ -72,17 +88,18 @@ class _entries extends \IPS\Content\Api\ItemController
*
* @param int $id ID Number
* @throws 2B300/A INVALID_ID The entry ID does not exist
* @return \IPS\blog\Entry
* @apireturn \IPS\blog\Entry
* @return Response
*/
public function GETitem( $id )
public function GETitem( int $id ): Response
{
try
{
return $this->_view( $id );
}
catch ( \OutOfRangeException $e )
catch ( OutOfRangeException $e )
{
throw new \IPS\Api\Exception( 'INVALID_ID', '2B300/A', 404 );
throw new Exception( 'INVALID_ID', '2B300/A', 404 );
}
}
@@ -94,17 +111,18 @@ class _entries extends \IPS\Content\Api\ItemController
* @apiparam int page Page number
* @apiparam int perPage Number of results per page - defaults to 25
* @throws 2B300/1 INVALID_ID The entry ID does not exist or the authorized user does not have permission to view it
* @return \IPS\Api\PaginatedResponse<IPS\blog\Entry\Comment>
* @apireturn PaginatedResponse<IPS\blog\Entry\Comment>
* @return PaginatedResponse<Comment>
*/
public function GETitem_comments( $id )
public function GETitem_comments( int $id ): PaginatedResponse
{
try
{
return $this->_comments( $id, 'IPS\blog\Entry\Comment' );
}
catch ( \OutOfRangeException $e )
catch ( OutOfRangeException $e )
{
throw new \IPS\Api\Exception( 'INVALID_ID', '2B300/1', 404 );
throw new Exception( 'INVALID_ID', '2B300/1', 404 );
}
}
@@ -137,18 +155,19 @@ class _entries extends \IPS\Content\Api\ItemController
* @throws 1B300/4 NO_TITLE No title was supplied
* @throws 1B300/5 NO_CONTENT No content was supplied
* @throws 1B300/A NO_PERMISSION The authorized user does not have permission to create an entry in that blog
* @return \IPS\blog\Entry
* @apireturn \IPS\blog\Entry
* @return Response
*/
public function POSTindex()
public function POSTindex(): Response
{
/* Get blog */
try
{
$blog = \IPS\blog\Blog::load( \IPS\Request::i()->blog );
$blog = Blog::load( Request::i()->blog );
}
catch ( \OutOfRangeException $e )
catch ( OutOfRangeException $e )
{
throw new \IPS\Api\Exception( 'NO_BLOG', '1B300/2', 400 );
throw new Exception( 'NO_BLOG', '1B300/2', 400 );
}
/* Get author */
@@ -156,45 +175,45 @@ class _entries extends \IPS\Content\Api\ItemController
{
if ( !$blog->can( 'add', $this->member ) )
{
throw new \IPS\Api\Exception( 'NO_PERMISSION', '1B300/A', 403 );
throw new Exception( 'NO_PERMISSION', '1B300/A', 403 );
}
$author = $this->member;
}
else
{
if ( \IPS\Request::i()->author )
if ( Request::i()->author )
{
$author = \IPS\Member::load( \IPS\Request::i()->author );
$author = Member::load( Request::i()->author );
if ( !$author->member_id )
{
throw new \IPS\Api\Exception( 'NO_AUTHOR', '1B300/3', 400 );
throw new Exception( 'NO_AUTHOR', '1B300/3', 400 );
}
}
else
{
if ( (int) \IPS\Request::i()->author === 0 )
if ( Request::i()->author === 0 )
{
$author = new \IPS\Member;
$author = new Member;
}
else
{
throw new \IPS\Api\Exception( 'NO_AUTHOR', '1B300/3', 400 );
throw new Exception( 'NO_AUTHOR', '1B300/3', 400 );
}
}
}
/* Check we have a title and a description */
if ( !\IPS\Request::i()->title )
if ( !Request::i()->title )
{
throw new \IPS\Api\Exception( 'NO_TITLE', '1B300/4', 400 );
throw new Exception( 'NO_TITLE', '1B300/4', 400 );
}
if ( !\IPS\Request::i()->entry )
if ( !Request::i()->entry )
{
throw new \IPS\Api\Exception( 'NO_CONTENT', '1B300/5', 400 );
throw new Exception( 'NO_CONTENT', '1B300/5', 400 );
}
/* Do it */
return new \IPS\Api\Response( 201, $this->_create( $blog, $author )->apiOutput( $this->member ) );
return new Response( 201, $this->_create( $blog, $author )->apiOutput( $this->member ) );
}
/**
@@ -224,57 +243,58 @@ class _entries extends \IPS\Content\Api\ItemController
* @throws 1B300/7 NO_BLOG The blog ID does not exist or the authorized user does not have permission to post in it
* @throws 1B300/8 NO_AUTHOR The author ID does not exist
* @throws 1B300/B NO_PERMISSION The authorized user does not have permission to edit that blog entry
* @return \IPS\blog\Entry
* @apireturn \IPS\blog\Entry
* @return Response
*/
public function POSTitem( $id )
public function POSTitem( int $id ): Response
{
try
{
$entry = \IPS\blog\Entry::load( $id );
$entry = Entry::load( $id );
if ( $this->member and !$entry->can( 'read', $this->member ) )
{
throw new \OutOfRangeException;
throw new OutOfRangeException;
}
if ( $this->member and !$entry->canEdit( $this->member ) )
{
throw new \IPS\Api\Exception( 'NO_PERMISSION', '1B300/B', 403 );
throw new Exception( 'NO_PERMISSION', '1B300/B', 403 );
}
/* New blog */
if ( isset( \IPS\Request::i()->blog ) and \IPS\Request::i()->blog != $entry->blog_id and ( !$this->member or $entry->canMove( $this->member ) ) )
if ( isset( Request::i()->blog ) and Request::i()->blog != $entry->blog_id and ( !$this->member or $entry->canMove( $this->member ) ) )
{
try
{
$newBlog = \IPS\blog\Blog::load( \IPS\Request::i()->blog );
$newBlog = Blog::load( Request::i()->blog );
if ( $this->member and !$newBlog->can( 'add', $this->member ) )
{
throw new \OutOfRangeException;
throw new OutOfRangeException;
}
$entry->move( $newBlog );
}
catch ( \OutOfRangeException $e )
catch ( OutOfRangeException $e )
{
throw new \IPS\Api\Exception( 'NO_BLOG', '1B300/7', 400 );
throw new Exception( 'NO_BLOG', '1B300/7', 400 );
}
}
/* New author */
if ( !$this->member and isset( \IPS\Request::i()->author ) )
if ( !$this->member and isset( Request::i()->author ) )
{
try
{
$member = \IPS\Member::load( \IPS\Request::i()->author );
$member = Member::load( Request::i()->author );
if ( !$member->member_id )
{
throw new \OutOfRangeException;
throw new OutOfRangeException;
}
$entry->changeAuthor( $member );
}
catch ( \OutOfRangeException $e )
catch ( OutOfRangeException $e )
{
throw new \IPS\Api\Exception( 'NO_AUTHOR', '1B300/8', 400 );
throw new Exception( 'NO_AUTHOR', '1B300/8', 400 );
}
}
@@ -283,36 +303,36 @@ class _entries extends \IPS\Content\Api\ItemController
/* Save and return */
$entry->save();
return new \IPS\Api\Response( 200, $entry->apiOutput( $this->member ) );
return new Response( 200, $entry->apiOutput( $this->member ) );
}
catch ( \OutOfRangeException $e )
catch ( OutOfRangeException $e )
{
throw new \IPS\Api\Exception( 'INVALID_ID', '2B300/6', 404 );
throw new Exception( 'INVALID_ID', '2B300/6', 404 );
}
}
/**
* Create or update entry
*
* @param \IPS\Content\Item $item The item
* @param Item $item The item
* @param string $type add or edit
* @return \IPS\Content\Item
* @return Item
*/
protected function _createOrUpdate( \IPS\Content\Item $item, $type='add' )
protected function _createOrUpdate( Item $item, string $type='add' ): Item
{
/* Is draft */
if ( isset( \IPS\Request::i()->draft ) )
if ( isset( Request::i()->draft ) )
{
$item->status = \IPS\Request::i()->draft ? 'draft' : 'published';
$item->status = Request::i()->draft ? 'draft' : 'published';
}
/* Content */
if ( isset( \IPS\Request::i()->entry ) )
if ( isset( Request::i()->entry ) )
{
$entryContents = \IPS\Request::i()->entry;
$entryContents = Request::i()->entry;
if ( $this->member )
{
$entryContents = \IPS\Text\Parser::parseStatic( $entryContents, TRUE, NULL, $this->member, 'blog_Entries' );
$entryContents = Parser::parseStatic( $entryContents, NULL, $this->member, 'blog_Entries' );
}
$item->content = $entryContents;
}
@@ -321,9 +341,9 @@ class _entries extends \IPS\Content\Api\ItemController
$this->_createOrUpdatePoll( $item, $type );
/* Category */
if ( isset( \IPS\Request::i()->category ) )
if ( isset( Request::i()->category ) )
{
$item->category_id = \IPS\Request::i()->category;
$item->category_id = Request::i()->category;
}
/* Pass up */
@@ -337,25 +357,26 @@ class _entries extends \IPS\Content\Api\ItemController
* @param int $id ID Number
* @throws 2B300/9 INVALID_ID The entry ID does not exist
* @throws 2B300/C NO_PERMISSION The authorized user does not have permission to delete the entry
* @return void
* @apireturn void
* @return Response
*/
public function DELETEitem( $id )
public function DELETEitem( int $id ): Response
{
try
{
$item = \IPS\blog\Entry::load( $id );
$item = Entry::load( $id );
if ( $this->member and !$item->canDelete( $this->member ) )
{
throw new \IPS\Api\Exception( 'NO_PERMISSION', '2B300/C', 404 );
throw new Exception( 'NO_PERMISSION', '2B300/C', 404 );
}
$item->delete();
return new \IPS\Api\Response( 200, NULL );
return new Response( 200, NULL );
}
catch ( \OutOfRangeException $e )
catch ( OutOfRangeException $e )
{
throw new \IPS\Api\Exception( 'INVALID_ID', '2B300/9', 404 );
throw new Exception( 'INVALID_ID', '2B300/9', 404 );
}
}
}
+44 -26
View File
@@ -12,22 +12,35 @@
namespace IPS\blog\api;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use IPS\Api\Exception;
use IPS\Api\PaginatedResponse;
use IPS\Api\Response;
use IPS\blog\Entry\Category;
use IPS\Db;
use IPS\Node\Api\NodeController;
use IPS\Request;
use OutOfRangeException;
use function defined;
use function in_array;
use function intval;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* @brief Blog Categories API
*/
class _entrycategories extends \IPS\Node\Api\NodeController
class entrycategories extends NodeController
{
/**
* Class
*/
protected $class = 'IPS\blog\Entry\Category';
protected string $class = 'IPS\blog\Entry\Category';
/**
* GET /blog/entrycategories
@@ -38,47 +51,49 @@ class _entrycategories extends \IPS\Node\Api\NodeController
* @apiparam string sortDir Sort direction. Can be 'asc' or 'desc' - defaults to 'asc'
* @apiparam int page Page number
* @apiparam int perPage Number of results per page - defaults to 25
* @return \IPS\Api\PaginatedResponse<IPS\blog\Entry\Category>
* @apireturn PaginatedResponse<IPS\blog\Entry\Category>
* @return PaginatedResponse<Category>
*/
public function GETindex()
public function GETindex(): PaginatedResponse
{
/* Where clause */
$where = array();
/* @var Category $class */
$class = $this->class;
if ( isset( \IPS\Request::i()->ids ) )
if ( isset( Request::i()->ids ) )
{
$idField = $class::$databaseTable . '.' . $class::$databasePrefix . '.' . $class::$databaseColumnId;
$where[] = array( \IPS\Db::i()->in( $idField, array_map( 'intval', explode( ',', \IPS\Request::i()->ids ) ) ) );
$where[] = array( Db::i()->in( $idField, array_map( 'intval', explode( ',', Request::i()->ids ) ) ) );
}
/* Blog */
if ( isset( \IPS\Request::i()->blog ) )
if ( isset( Request::i()->blog ) )
{
$where[] = array( 'entry_category_blog_id=?', \intval( \IPS\Request::i()->blog ) );
$where[] = array( 'entry_category_blog_id=?', intval( Request::i()->blog ) );
}
/* Sort */
if ( isset( \IPS\Request::i()->sortBy ) and \in_array( \IPS\Request::i()->sortBy, array( 'position' ) ) )
if ( isset( Request::i()->sortBy ) and Request::i()->sortBy == 'position' )
{
$sortBy = 'entry_category_' . \IPS\Request::i()->sortBy;
$sortBy = 'entry_category_' . Request::i()->sortBy;
}
else
{
$sortBy = 'entry_category_id';
}
$sortDir = ( isset( \IPS\Request::i()->sortDir ) and \in_array( mb_strtolower( \IPS\Request::i()->sortDir ), array( 'asc', 'desc' ) ) ) ? \IPS\Request::i()->sortDir : 'asc';
$sortDir = ( isset( Request::i()->sortDir ) and in_array( mb_strtolower( Request::i()->sortDir ), array( 'asc', 'desc' ) ) ) ? Request::i()->sortDir : 'asc';
/* Return */
return new \IPS\Api\PaginatedResponse(
return new PaginatedResponse(
200,
\IPS\Db::i()->select( '*', 'blog_entry_categories', $where, "{$sortBy} {$sortDir}" ),
isset( \IPS\Request::i()->page ) ? \IPS\Request::i()->page : 1,
Db::i()->select( '*', 'blog_entry_categories', $where, "{$sortBy} {$sortDir}" ),
isset( Request::i()->page ) ? Request::i()->page : 1,
'IPS\blog\Entry\Category',
\IPS\Db::i()->select( 'COUNT(*)', 'blog_entry_categories', $where )->first(),
Db::i()->select( 'COUNT(*)', 'blog_entry_categories', $where )->first(),
$this->member,
isset( \IPS\Request::i()->perPage ) ? \IPS\Request::i()->perPage : NULL
isset( Request::i()->perPage ) ? Request::i()->perPage : NULL
);
}
@@ -87,9 +102,10 @@ class _entrycategories extends \IPS\Node\Api\NodeController
* Get information about a specific entry category
*
* @param int $id ID Number
* @return \IPS\blog\Entry\Category
* @apireturn \IPS\blog\Entry\Category
* @return Response
*/
public function GETitem( $id )
public function GETitem( int $id ): Response
{
return $this->_view( $id );
}
@@ -99,11 +115,13 @@ class _entrycategories extends \IPS\Node\Api\NodeController
* Delete an entry category
*
* @param int $id ID Number
* @return void
* @apireturn void
* @throws 2B408/5 INVALID_ID The category ID does not exist or the authorized user does not have permission to delete it
* @return Response
*/
public function DELETEitem( $id )
public function DELETEitem( int $id ): Response
{
/* @var Category $class */
$class = $this->class;
try
@@ -111,15 +129,15 @@ class _entrycategories extends \IPS\Node\Api\NodeController
$category = $class::load( $id );
if ( !$category->canDelete( $this->member ) )
{
throw new \IPS\Api\Exception( 'INVALID_ID', '2B408/5', 404 );
throw new Exception( 'INVALID_ID', '2B408/5', 404 );
}
$category->delete();
return new \IPS\Api\Response( 200, NULL );
return new Response( 200, NULL );
}
catch ( \OutOfRangeException $e )
catch ( OutOfRangeException $e )
{
throw new \IPS\Api\Exception( 'INVALID_ID', '2B408/6', 404 );
throw new Exception( 'INVALID_ID', '2B408/6', 404 );
}
}
+1 -2
View File
@@ -2,12 +2,10 @@
<build>
<module key="admin/blogs"><![CDATA[{"default_controller":"","protected":0,"default":1}]]></module>
<module key="front/blogs"><![CDATA[{"default_controller":"browse","protected":0,"default":1}]]></module>
<setting key="blog_allow_grid"><![CDATA[{"key":"blog_allow_grid","default":"1","report":"full"}]]></setting>
<setting key="blog_allow_rss"><![CDATA[{"key":"blog_allow_rss","default":"1","report":"full"}]]></setting>
<setting key="blog_allow_rssimport"><![CDATA[{"key":"blog_allow_rssimport","default":"1","report":"full"}]]></setting>
<setting key="blog_enable_rating"><![CDATA[{"key":"blog_enable_rating","default":"0","report":"full"}]]></setting>
<setting key="blog_enable_sidebar"><![CDATA[{"key":"blog_enable_sidebar","default":"0","report":"full"}]]></setting>
<setting key="blog_view_mode"><![CDATA[{"key":"blog_view_mode","default":"grid","report":"bool"}]]></setting>
<widget key="blogStatistics"><![CDATA[{"class":"\\IPS\\Widget\\StaticCache","restrict":[],"default_area":"","allow_reuse":false,"menu_style":"menu","embeddable":true}]]></widget>
<widget key="entryFeed"><![CDATA[{"class":"\\IPS\\Widget\\PermissionCache","restrict":["sidebar","cms"],"default_area":"","allow_reuse":true,"menu_style":"modal","embeddable":true}]]></widget>
<widget key="blogCommentFeed"><![CDATA[{"class":"\\IPS\\Widget\\PermissionCache","restrict":["sidebar","cms"],"default_area":"","allow_reuse":true,"menu_style":"modal","embeddable":true}]]></widget>
@@ -27,4 +25,5 @@
<acpsearch key="app=core&amp;module=members&amp;controller=groups&amp;searchResult=4_g_blog_allowlocal"><![CDATA[{"lang_key":"g_blog_allowlocal","restriction":"groups_manage","keywords":["blogs","blogs permission","create blogs","post blogs"]}]]></acpsearch>
<acpsearch key="app=core&amp;module=members&amp;controller=groups&amp;searchResult=g_blog_allowdelete"><![CDATA[{"lang_key":"g_blog_allowdelete","restriction":"groups_manage","keywords":["delete blogs","delete own blogs"]}]]></acpsearch>
<acpsearch key="app=core&amp;module=members&amp;controller=groups&amp;searchResult=g_blog_allowprivate"><![CDATA[{"lang_key":"g_blog_allowprivate","restriction":"groups_manage","keywords":["private blogs"]}]]></acpsearch>
<themeeditorsetting key="layout_blog_view"><![CDATA[{"key":"layout_blog_view","type":"select","name":"Blog View","desc":"Change the default layout of the blog view","refresh":true,"options":[["table","Table"],["grid","Grid"]],"default":"grid","cat":"pageLayouts"}]]></themeeditorsetting>
</build>
+3 -13
View File
@@ -1,15 +1,8 @@
{
"core": {
"BBCode": {
"blog": "IPS\\blog\\extensions\\core\\BBCode\\blog",
"entry": "IPS\\blog\\extensions\\core\\BBCode\\entry"
},
"ContentRouter": {
"Blog": "IPS\\blog\\extensions\\core\\ContentRouter\\Blog"
},
"CreateMenu": {
"Entry": "IPS\\blog\\extensions\\core\\CreateMenu\\Entry"
},
"Dashboard": {
"Overview": "IPS\\blog\\extensions\\core\\Dashboard\\Overview"
},
@@ -34,9 +27,6 @@
"MemberFilter": {
"Blog": "IPS\\blog\\extensions\\core\\MemberFilter\\Blog"
},
"MemberSync": {
"Blog": "IPS\\blog\\extensions\\core\\MemberSync\\Blog"
},
"ModeratorPermissions": {
"Blogs": "IPS\\blog\\extensions\\core\\ModeratorPermissions\\Blogs"
},
@@ -46,11 +36,11 @@
"Profile": {
"blog": "IPS\\blog\\extensions\\core\\Profile\\blog"
},
"Queue": {
"RebuildEntryImages": "IPS\\blog\\extensions\\core\\Queue\\RebuildEntryImages"
},
"RssImport": {
"RssImport": "IPS\\blog\\extensions\\core\\RssImport\\RssImport"
},
"SearchContent": {
"Entries": "IPS\\blog\\extensions\\core\\SearchContent\\Entries"
}
}
}
-23
View File
@@ -1,26 +1,3 @@
/**
* Friendly URL Structure
*
* For each value in the $furl array:
* The key should be the "SEO Template" - an identifier which you'll use when displaying a URL.
* The value should be an associative array with two or three elements: 'friendly' and 'real', and optionally 'verify':
* 'friendly'
* The friendly URL to use - encase variables in {curly braces} containing a symbol, followed by the name of the parameter that matches in the "real" URL
* The symbol should be # for numbers or @ for strings
* For example, if the "real" URL contains id=XXX, where XXX is a number, you should include {#id} somewhere in the friendly URL.
* You can also use the tag {?} for the "SEO Title" (that is, any variables that shouldn't be part of the real URL, such as the name of the topipc being viewed).
* If you want to support more than one SEO Title, you can give them zero-indexed keys like so: {?0} {?1} {?2}
* 'real'
* This should be the base of the real URL. You should not include parameters which will be parsed out from the friendly URL.
* 'verify'
* This should be the name of a class that contains a loadFromUrl() and an url() method. The dynamic URL (i.e. app=core&...) will be passed to loadFromUrl(), and the url()
* method will subsequently be called to retrieve the correct URL, ideal with ActiveRecord pattern classes.
*
* IMPORTANT: Ensure values are listed with the most specific ones first. This is to ensure that non-FURL redirects are done correctly. For example, if you have these FURLs:
* /index.php?app=myapp&module=mymodule&controller=mycontroller&do=myaction -> /myfolder/myaction
* /index.php?app=myapp&module=mymodule&controller=mycontroller -> /myfolder
* They must be provided in that order, otherwise the former will redirec to /myfolder/?do=myaction rather than /myfolder/myaction
*/
{
"topLevel": "blogs",
"pages": {
+14 -80
View File
@@ -1,72 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<javascript app="blog">
<file javascript_app="blog" javascript_location="front" javascript_path="controllers/browse" javascript_name="ips.browse.grid.js" javascript_type="controller" javascript_version="107827" javascript_position="1000150"><![CDATA[/**
* Invision Community
* (c) Invision Power Services, Inc. - https://www.invisioncommunity.com
*
* ips.browse.list.js - Blog browse list controller
*
* Author: Rikki Tissier
*/
;( function($, _, undefined){
"use strict";
ips.controller.register('blog.front.browse.grid', {
initialize: function () {
this.on('click', '.cBlog_grid_item', this.clickNewsItem);
this.setup();
},
setup: function () {
},
clickNewsItem: function (e) {
var link = $( e.currentTarget ).find('[data-role="newsTitle"]');
if( $( e.target ).closest('a').length > 0 ){
return;
}
if( $( e.target ).closest('input').length > 0 ){
return;
}
window.location = link.attr('href');
}
});
}(jQuery, _));]]></file>
<file javascript_app="blog" javascript_location="front" javascript_path="controllers/browse" javascript_name="ips.browse.list.js" javascript_type="controller" javascript_version="107827" javascript_position="1000150">/**
* Invision Community
* (c) Invision Power Services, Inc. - https://www.invisioncommunity.com
*
* ips.browse.list.js - Blog browse list controller
*
* Author: Rikki Tissier
*/
;( function($, _, undefined){
&quot;use strict&quot;;
ips.controller.register('blog.front.browse.list', {
initialize: function () {
this.on( 'change', '[data-role=&quot;moderation&quot;]', this.selectEntry );
},
/**
* Toggles classes when the moderation checkbox is checked
*
* @param {event} e Event object
* @returns {void}
*/
selectEntry: function (e) {
var row = $( e.currentTarget ).closest('.cBlogView_entry');
row.toggleClass( 'cBlogView_entrySelected', $( e.currentTarget ).is(':checked') );
}
});
}(jQuery, _));</file>
<file javascript_app="blog" javascript_location="front" javascript_path="controllers/view" javascript_name="ips.view.manageCategories.js" javascript_type="controller" javascript_version="107827" javascript_position="1000100"><![CDATA[/**
<file javascript_app="blog" javascript_location="front" javascript_path="controllers/view" javascript_name="ips.view.manageCategories.js" javascript_type="controller" javascript_version="5000026" javascript_position="1000100"><![CDATA[/**
* Invision Community
* (c) Invision Power Services, Inc. - https://www.invisioncommunity.com
*
@@ -98,7 +32,7 @@
/* Save button changes */
$('.ipsTabs ul[role="tablist"] a').on( 'click', this.tabChange );
$('.ipsForm .ipsToolList').append( ips.templates.render('blog.view.addButton') );
$('.ipsForm .ipsButtons').append( ips.templates.render('blog.view.addButton') );
$('[data-action="addNew"]').on( 'click', _.bind( this.newRow, this ) );
this.renderList();
@@ -235,7 +169,7 @@
* @returns {void}
*/
tabChange: function (e) {
if ( ! $('#form_tab_blog_entry_categories').hasClass('ipsTabs_activeItem') ) { // This looks back to front but the tab status is changed after this has fired
if ( ! $('#form_tab_blog_entry_categories').hasClass('ipsTabs__tab--active') ) { // This looks back to front but the tab status is changed after this has fired
$('button[type="submit"]').addClass('ipsHide');
$('button[data-action="addNew"]').removeClass('ipsHide');
} else {
@@ -343,23 +277,23 @@
}
});
}(jQuery, _));]]></file>
<file javascript_app="blog" javascript_location="front" javascript_path="templates" javascript_name="ips.templates.view.js" javascript_type="template" javascript_version="107827" javascript_position="1000050"><![CDATA[/* CLASS LIST TEMPLATES */
<file javascript_app="blog" javascript_location="front" javascript_path="templates" javascript_name="ips.templates.view.js" javascript_type="template" javascript_version="5000026" javascript_position="1000050"><![CDATA[/* CLASS LIST TEMPLATES */
ips.templates.set('blog.view.addButton', "\
<button type=\"button\" class=\"ipsButton ipsButton_primary ipsHide\" data-action=\"addNew\">{{#lang}}manage_cats_new_row{{/lang}}</button>\
<button type=\"button\" class=\"ipsButton ipsButton--primary ipsHide\" data-action=\"addNew\">{{#lang}}manage_cats_new_row{{/lang}}</button>\
");
ips.templates.set('blog.view.categoryRow', "\
<li class=\"ipsDataItem ipsClearfix\" itemprop=\"itemListElement\" data-category-id=\"{{cat}}\">\
<div class=\"ipsDataItem_main\">\
<span data-role=\"sortHandle\" class=\"ipsCursor_drag\"><i class=\"fa fa-bars\"></i></span>&nbsp;\
<span class=\"ipsDataItem_title\" data-role=\"title_{{cat}}\">{{name}}</span>\
<li class=\"ipsData__item\" itemprop=\"itemListElement\" data-category-id=\"{{cat}}\">\
<span data-role=\"sortHandle\" class=\"i-cursor_move\"><i class=\"fa-solid fa-bars\"></i></span>\
<div class=\"ipsData__main i-flex i-gap_1\">\
<span class=\"ipsData__title\" data-role=\"title_{{cat}}\">{{name}}</span>\
<input type=\"text\" name=\"blog_name_{{cat}}\" value=\"\" data-role=\"input_{{cat}}\" class=\"ipsHide\">\
<a href=\"#\" data-role=\"saveChanges\" data-category-id=\"{{cat}}\" class=\"ipsHide ipsButton ipsButton_verySmall ipsButton_light ipsButton_narrow\" data-ipstooltip=\"\" title=\"{{#lang}}save{{/lang}}\">{{#lang}}save{{/lang}}</a>\
<a href=\"#\" data-role=\"cancelChanges\" data-category-id=\"{{cat}}\" class=\"ipsHide\" data-ipstooltip=\"\" title=\"{{#lang}}cancel{{/lang}}\">{{#lang}}cancel{{/lang}}</a>\
<a href=\"#\" data-role=\"saveChanges\" data-category-id=\"{{cat}}\" class=\"ipsHide i-flex_00 ipsButton ipsButton--positive\" data-ipstooltip=\"\" title=\"{{#lang}}save{{/lang}}\">{{#lang}}save{{/lang}}</a>\
<a href=\"#\" data-role=\"cancelChanges\" data-category-id=\"{{cat}}\" class=\"ipsHide i-flex_00 ipsButton ipsButton--negative\" data-ipstooltip=\"\" title=\"{{#lang}}cancel{{/lang}}\">{{#lang}}cancel{{/lang}}</a>\
</div>\
<div class=\"ipsDataItem_generic ipsDataItem_size3 cBlog_manage_edit ipsPos_top ipsType_right\">\
<a href=\"#\" data-action=\"delete\" data-category-id=\"{{cat}}\" class=\"ipsButton ipsButton_verySmall ipsButton_light ipsButton_narrow ipsPos_right\" data-ipstooltip title=\"{{#lang}}delete{{/lang}}\"><i class=\"fa fa-times-circle\"></i></a>\
<a href=\"#\" data-action=\"edit\" data-category-id=\"{{cat}}\" class=\"ipsButton ipsButton_verySmall ipsButton_light ipsButton_narrow ipsPos_right\" data-ipstooltip title=\"{{#lang}}edit{{/lang}}\"><i class\=\"fa fa-pencil\"></i></a>\
<div class=\"cBlog_manage_edit ipsButtonGroup ipsButton--soft\">\
<a href=\"#\" data-action=\"delete\" data-category-id=\"{{cat}}\" class=\"ipsButtonGroup__button\" data-ipstooltip title=\"{{#lang}}delete{{/lang}}\"><i class=\"fa-solid fa-circle-xmark\"></i></a>\
<a href=\"#\" data-action=\"edit\" data-category-id=\"{{cat}}\" class=\"ipsButtonGroup__button\" data-ipstooltip title=\"{{#lang}}edit{{/lang}}\"><i class\=\"fa-solid fa-pencil\"></i></a>\
</div>\
</li>\
");
+14 -16
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<language>
<app key="blog" version="107827">
<app key="blog" version="5000026">
<word key="__app_blog" js="0">Blogs</word>
<word key="frontnavigation_blogs" js="0">Blogs</word>
<word key="__indefart_blog_entry_comment" js="0">a comment on a blog entry</word>
@@ -37,13 +37,9 @@
<word key="blog_allow_rssimport" js="0">Allow RSS imports</word>
<word key="blog_allow_rssimport_desc" js="0"><![CDATA[Allowing users to import RSS feeds will make your site susceptible to <a href='https://owasp.org/www-community/attacks/Server_Side_Request_Forgery' target='_blank' rel='noopener'>SSRF attacks</a>. You should not allow RSS imports to Blog if untrusted users are permitted to create blogs, and you should only import RSS feeds from sources that are trusted and that do not allow user-submitted content to be included in the feed.]]></word>
<word key="blog_allow_rss" js="0">Allow RSS exports</word>
<word key="blog_allow_grid" js="0">Enable grid view</word>
<word key="blog_allow_grid_desc" js="0">Grid view showcases blog entries as cards with space for a feature photo</word>
<word key="blog_view_mode" js="0">Default view</word>
<word key="blog_view_mode_grid" js="0">Grid of latest entries</word>
<word key="blog_view_mode_grid_desc" js="0">Displays entries as cards in a grid with space for a feature photo</word>
<word key="blog_view_mode_list" js="0">List of blogs</word>
<word key="blog_view_mode_list_desc" js="0">Displays blogs as a sortable and filterable list</word>
<word key="blog_view" js="0">Blog view</word>
<word key="blog_view_mode_grid" js="0">Grid: Display entries as cards</word>
<word key="blog_view_mode_table" js="0">Table: Traditional table view</word>
<word key="blogs" js="0">Blogs</word>
<word key="blog_word_custom" js="0">Blog Name</word>
<word key="blog_blog_member_id" js="0">Blog Author</word>
@@ -131,7 +127,7 @@
<word key="next_entry" js="0">Next entry</word>
<word key="blog_entry__comment_placeholder" js="0">Add a comment...</word>
<word key="blog_entry_submit_comment" js="0">Submit Comment</word>
<word key="entry_actions" js="0">Entry Actions</word>
<word key="entry_actions" js="0"><![CDATA[<i class='fa-solid fa-gear'></i> Entry Actions]]></word>
<word key="edit_title_blog" js="0">Edit this blog entry</word>
<word key="feature_title_blog" js="0">Feature this blog entry</word>
<word key="unfeature_title_blog" js="0">Unfeature this blog entry</word>
@@ -148,14 +144,14 @@
<word key="unpublished" js="0">Unpublished</word>
<word key="blog_entry_locked_can_comment" js="0">This blog entry is locked, but your permissions allow you to add new comments.</word>
<word key="blog_entry_locked_cannot_comment" js="0">This blog entry is now closed to further comments.</word>
<word key="entry_posted" js="0">Entry posted by %s</word>
<word key="entry_future_posted" js="0">Entry by %s publishes on</word>
<word key="entry_posted" js="0">By %s</word>
<word key="entry_future_posted" js="0">By %s, publishes on</word>
<word key="entry_images" js="0">Images</word>
<word key="entry_posted_with_cat" js="0">Entry posted by %s in %s</word>
<word key="entry_future_posted_with_cat" js="0">Entry by %s in %s publishes on</word>
<word key="blog_comments" js="0">{!#[1:comment][?:comments]}</word>
<word key="blog_entries" js="0">{!#[1:entry][?:entries]}</word>
<word key="blog_views" js="0">{!#[1:view][?:views]}</word>
<word key="entry_posted_with_cat" js="0">By %s in %s</word>
<word key="entry_future_posted_with_cat" js="0">By %s in %s, publishes on</word>
<word key="blog_comments" js="0">{!#[1:Comment][?:Comments]}</word>
<word key="blog_entries" js="0">{!#[1:Entry][?:Entries]}</word>
<word key="blog_views" js="0">{!#[1:View][?:Views]}</word>
<word key="recent_entries" js="0">Recent Entries</word>
<word key="featured_entries" js="0">Featured Entries</word>
<word key="our_community_blogs" js="0">Our community blogs</word>
@@ -174,6 +170,7 @@
<word key="read_blog" js="0">You've read this entry</word>
<word key="go_to_blog" js="0">Go to the blog %s</word>
<word key="latest_entry" js="0">Latest Entry</word>
<word key="latest_entry_by" js="0">Latest entry by %s, </word>
<word key="entry_name_with_cat" js="0">%s in %s</word>
<word key="no_entries" js="0">No blog entries have been created</word>
<word key="pin_blog" js="0">Pin</word>
@@ -262,6 +259,7 @@
<word key="can_add_item_message_blog_entry" js="0">Can add messages to entries?</word>
<word key="can_edit_item_message_blog_entry" js="0">Can edit messages on entries?</word>
<word key="can_delete_item_message_blog_entry" js="0">Can delete messages on entries?</word>
<word key="can_view_reports_blog_entry" js="0">Can view reported blog entries?</word>
<word key="group__blog_Blog" js="0">Blog</word>
<word key="g_blog_allowlocal" js="0">Can create blogs?</word>
<word key="g_blog_maxblogs" js="0">Maximum number of blogs</word>
+7
View File
@@ -0,0 +1,7 @@
{
"Blog": {
"type": "MemberListenerType",
"classname": "IPS\\blog\\listeners\\Blog",
"extends": "IPS\\Member"
}
}
-10
View File
@@ -1,9 +1,4 @@
[
{
"key": "blog_allow_grid",
"default": "1",
"report": "full"
},
{
"key": "blog_allow_rss",
"default": "1",
@@ -23,10 +18,5 @@
"key": "blog_enable_sidebar",
"default": "0",
"report": "full"
},
{
"key": "blog_view_mode",
"default": "grid",
"report": "bool"
}
]
File diff suppressed because it is too large. Load diff
+23
View File
@@ -0,0 +1,23 @@
{
"settings": {
"layout_blog_view": {
"key": "layout_blog_view",
"type": "select",
"name": "Blog View",
"desc": "Change the default layout of the blog view",
"refresh": true,
"options": [
[
"table",
"Table"
],
[
"grid",
"Grid"
]
],
"default": "grid",
"cat": "pageLayouts"
}
}
}
+26 -394
View File
@@ -1,361 +1,4 @@
{
"20000": "2.0.0 Beta 1",
"20001": "2.0.0 Beta 2",
"20002": "2.0.0 Beta 3",
"20003": "2.0.0 RC 1",
"20004": "2.0.0 RC 2",
"20005": "2.0.0",
"20006": "2.0.1",
"20007": "2.0.2",
"20008": "2.0.3",
"20009": "2.0.4",
"21000": "2.1.0 Beta 1",
"21001": "2.1.0 RC 1",
"21002": "2.1.0 RC 2",
"21003": "2.1.0",
"22000": "2.2.0 Beta 1",
"22001": "2.2.0 Beta 2",
"22002": "2.2.0 Beta 3",
"22003": "2.2.0",
"22004": "2.2.1",
"22005": "2.2.2",
"23000": "2.3.0",
"23001": "2.3.1",
"23002": "2.3.2",
"24000": "2.4.0 Beta 1",
"24001": "2.4.0 Beta 2",
"24002": "2.4.0",
"24003": "2.4.1",
"25000": "2.5.0 Alpha",
"25001": "2.5.0 Beta 1",
"25002": "2.5.0 Beta 2",
"25003": "2.5.0",
"25004": "2.5.1",
"25005": "2.5.2",
"26000": "2.6.0 Beta 1",
"26001": "2.6.0 Beta 2",
"26002": "2.6.0",
"26003": "2.6.1",
"26004": "2.6.2",
"26005": "2.6.3",
"40000": "4.0.0",
"100000": "4.0.0 Beta 0",
"100001": "4.0.0 Beta 1",
"100002": "4.0.0 Beta 2",
"100003": "4.0.0 Beta 3",
"100004": "4.0.0 Beta 3a",
"100005": "4.0.0 Beta 4",
"100006": "4.0.0 Beta 4a",
"100007": "4.0.0 Beta 4b",
"100008": "4.0.0 Beta 5",
"100009": "4.0.0 Beta 5a",
"100010": "4.0.0 Beta 6",
"100011": "4.0.0 Beta 7",
"100012": "4.0.0 Beta 7a",
"100013": "4.0.0 Beta 8",
"100014": "4.0.0 RC 1",
"100015": "4.0.0 RC2",
"100016": "4.0.0 RC3",
"100017": "4.0.0 RC4",
"100018": "4.0.0 RC5",
"100019": "4.0.0 RC5a",
"100020": "4.0.0 RC6",
"100021": "4.0.0 RC7",
"100022": "4.0.0 RC7a",
"100023": "4.0.0",
"100024": "4.0.1",
"100025": "4.0.2",
"100026": "4.0.3",
"100027": "4.0.4",
"100028": "4.0.5",
"100029": "4.0.5.1",
"100030": "4.0.6",
"100031": "4.0.6.1",
"100032": "4.0.7",
"100033": "4.0.8",
"100034": "4.0.8.1",
"100035": "4.0.9",
"100036": "4.0.9.1",
"100037": "4.0.9.2",
"100038": "4.0.10",
"100039": "4.0.10.1",
"100040": "4.0.10.2",
"100041": "4.0.11",
"100042": "4.0.12",
"100043": "4.0.12.1",
"100044": "4.0.13",
"100045": "4.0.13.1",
"101000": "4.1.0 Beta 1",
"101001": "4.1.0 Beta 2",
"101002": "4.1.0 Beta 3",
"101003": "4.1.0 Beta 4",
"101004": "4.1.0 Beta 5",
"101005": "4.1.0 Beta 6",
"101006": "4.1.0 Beta 7",
"101007": "4.1.0 Beta 8",
"101008": "4.1.0 Beta 9",
"101009": "4.1.0 Beta 10",
"101010": "4.1.0",
"101011": "4.1.1",
"101012": "4.1.2",
"101013": "4.1.3",
"101014": "4.1.3.1",
"101015": "4.1.3.2",
"101016": "4.1.4",
"101017": "4.1.4.1",
"101018": "4.1.5",
"101019": "4.1.5.1",
"101020": "4.1.5.2",
"101021": "4.1.6",
"101022": "4.1.6.1",
"101023": "4.1.7",
"101024": "4.1.8",
"101025": "4.1.8.1",
"101026": "4.1.9",
"101027": "4.1.10",
"101028": "4.1.11",
"101029": "4.1.11.1",
"101030": "4.1.12",
"101031": "4.1.12.1",
"101032": "4.1.12.2",
"101033": "4.1.12.3",
"101034": "4.1.13 Beta 1",
"101035": "4.1.13 Beta 2",
"101036": "4.1.13",
"101037": "4.1.13",
"101038": "4.1.13.1",
"101040": "4.1.13.2",
"101041": "4.1.13.2",
"101042": "4.1.14 Beta 1",
"101043": "4.1.14 Beta 2",
"101044": "4.1.14 Beta 3",
"101045": "4.1.14 Beta 4",
"101046": "4.1.14 Beta 5",
"101049": "4.1.14 Beta 6",
"101050": "4.1.14 Beta 7",
"101051": "4.1.14 RC",
"101052": "4.1.14",
"101053": "4.1.14.1",
"101054": "4.1.14.2",
"101055": "4.1.14.3",
"101056": "4.1.15",
"101057": "4.1.15 Beta 1",
"101058": "4.1.15 Beta 2",
"101059": "4.1.15 Beta 2a",
"101060": "4.1.15 Beta 3",
"101061": "4.1.15",
"101062": "4.1.15",
"101063": "4.1.15",
"101064": "4.1.16 Beta 1",
"101065": "4.1.16 Beta 2",
"101066": "4.1.16 Beta 3",
"101067": "4.1.16 Beta 4",
"101068": "4.1.16 Beta 5",
"101069": "4.1.16",
"101070": "4.1.16.1",
"101071": "4.1.17 Beta 1",
"101072": "4.1.17 Beta 1a",
"101073": "4.1.17 Beta 1b",
"101074": "4.1.17 Beta 2",
"101075": "4.1.17 Beta 3",
"101076": "4.1.17 Beta 3",
"101077": "4.1.17",
"101078": "4.1.17.1",
"101079": "4.1.18 Beta 1",
"101082": "4.1.18 Beta 1b",
"101083": "4.1.18 Beta 2",
"101084": "4.1.18 Beta 3",
"101085": "4.1.18",
"101088": "4.1.18.1",
"101089": "4.1.18.2",
"101090": "4.1.19 Beta 1",
"101091": "4.1.19 Beta 2",
"101092": "4.1.19 Beta 3",
"101093": "4.1.19",
"101094": "4.1.19.1",
"101095": "4.1.19.2 Beta 1",
"101096": "4.1.19.2",
"101097": "4.1.19.2",
"101098": "4.1.19.3",
"101099": "4.1.19.4",
"101100": "4.2.0 Beta 1",
"101101": "4.2.0 Beta 1",
"101102": "4.2.0 Beta 1",
"101103": "4.2.0 Beta 1",
"101104": "4.2.0 Beta 2",
"101105": "4.2.0 Beta 3",
"101106": "4.2.0 Beta 3a",
"101107": "4.2.0 Beta 4",
"101108": "4.2.0 Beta 4",
"101109": "4.2.0 Beta 5",
"101110": "4.2.0 Beta 5a",
"101111": "4.2.0 Beta 6",
"101112": "4.2.0 Beta 6a",
"101113": "4.2.0 Beta 6a",
"101114": "4.2.0 Beta 7",
"101115": "4.2.0 Beta 7a",
"101116": "4.2.0 Beta 8",
"101117": "4.2.0 Beta 8",
"102000": "4.2.0",
"102001": "4.2.0",
"102002": "4.2.0",
"102003": "4.2.0",
"102004": "4.2.1",
"102005": "4.2.2 Beta 1",
"102006": "4.2.2 Beta 2",
"102007": "4.2.2",
"102008": "4.2.2",
"102009": "4.2.2",
"102010": "4.2.3 Beta 1",
"102011": "4.2.3",
"102012": "4.2.3",
"102013": "4.2.3",
"102014": "4.2.4 Beta 1",
"102015": "4.2.4 Beta 2",
"102016": "4.2.4",
"102017": "4.2.4",
"102018": "4.2.4",
"102019": "4.2.4",
"102020": "4.2.4",
"102021": "4.2.5 Beta 1",
"102022": "4.2.5 Beta 2",
"102023": "4.2.5 Beta 3",
"102024": "4.2.5",
"102025": "4.2.5",
"102026": "4.2.5",
"102027": "4.2.5",
"102028": "4.2.5",
"102029": "4.2.5",
"102030": "4.2.6 Beta 1",
"102031": "4.2.6 Beta 1",
"102032": "4.2.6 Beta 2",
"102033": "4.2.6 Beta 3",
"102034": "4.2.6",
"102035": "4.2.6",
"102036": "4.2.6",
"102037": "4.2.7 Beta 1",
"102038": "4.2.7 Beta 2",
"102039": "4.2.7 Beta 3",
"102040": "4.2.7 Beta 4",
"102041": "4.2.7 Beta 5",
"102042": "4.2.7",
"102043": "4.2.7",
"102044": "4.2.7",
"102045": "4.2.7",
"102046": "4.2.7",
"102047": "4.2.8",
"102048": "4.2.8",
"102049": "4.2.9",
"103000": "4.3.0 Beta 1",
"103002": "4.3.0 Beta 2",
"103003": "4.3.0 Beta 3",
"103004": "4.3.0 Beta 4",
"103005": "4.3.0",
"103006": "4.3.1",
"103007": "4.3.1",
"103008": "4.3.1",
"103009": "4.3.2",
"103010": "4.3.2",
"103011": "4.3.3",
"103012": "4.3.3",
"103013": "4.3.3",
"103014": "4.3.3",
"103015": "4.3.3",
"103016": "4.3.3",
"103017": "4.3.3",
"103018": "4.3.3",
"103019": "4.3.3",
"103020": "4.3.3",
"103021": "4.3.4",
"103022": "4.3.4",
"103023": "4.3.4",
"103024": "4.3.4",
"103025": "4.3.4",
"103026": "4.3.5 Beta 1",
"103027": "4.3.5 Beta 2",
"103028": "4.3.5",
"103029": "4.3.5",
"103030": "4.3.5",
"103031": "4.3.5",
"103032": "4.3.5",
"103033": "4.3.6 Beta 1",
"103034": "4.3.6 Beta 2",
"103035": "4.3.6",
"103036": "4.3.6",
"103037": "4.3.6",
"103038": "4.3.6",
"103039": "4.3.6",
"104000": "4.4.0 Beta 1",
"104001": "4.4.0 Beta 2",
"104002": "4.4.0 Beta 3",
"104004": "4.4.0 Beta 4",
"104003": "4.4.0 Beta 4",
"104005": "4.4.0",
"104006": "4.4.0",
"104007": "4.4.0",
"104008": "4.4.0",
"104009": "4.4.1",
"104010": "4.4.1 Beta 2",
"104011": "4.4.1",
"104012": "4.4.1",
"104013": "4.4.1",
"104014": "4.4.1",
"104015": "4.4.2 Beta 1",
"104016": "4.4.2",
"104017": "4.4.2",
"104018": "4.4.2",
"104019": "4.4.2",
"104020": "4.4.2",
"104021": "4.4.3 Beta 1",
"104022": "4.4.3 Beta 2",
"104023": "4.4.3",
"104024": "4.4.3",
"104025": "4.4.3",
"104026": "4.4.4 Beta 1",
"104027": "4.4.4",
"104028": "4.4.4",
"104029": "4.4.4",
"104030": "4.4.5 Beta 1",
"104031": "4.4.5 Beta 2",
"104032": "4.4.5 Beta 2",
"104033": "4.4.5",
"104034": "4.4.5",
"104035": "4.4.5",
"104036": "4.4.5",
"104037": "4.4.5",
"104038": "4.4.6",
"104039": "4.4.6",
"104040": "4.4.6",
"104041": "4.4.7 Beta 1",
"104042": "4.4.7 Beta 2",
"104043": "4.4.7 Beta 3",
"104044": "4.4.7",
"104045": "4.4.8 Beta 1",
"104046": "4.4.8 Beta 2",
"104047": "4.4.8",
"104048": "4.4.9 Beta 1",
"104049": "4.4.9",
"104050": "4.4.9",
"104051": "4.4.9",
"104052": "4.4.9",
"104053": "4.4.9.1",
"104054": "4.4.9.1",
"104055": "4.4.9.2",
"104056": "4.4.9.2",
"104057": "4.4.10 Beta 1",
"104058": "4.4.10 Beta 2",
"104059": "4.4.10 Beta 3",
"104060": "4.4.10 Beta 4",
"104061": "4.4.10",
"104062": "4.4.10",
"104063": "4.4.10",
"104064": "4.4.10",
"104065": "4.4.10",
"104066": "4.4.10",
"104067": "4.4.10",
"104068": "4.4.10",
"104069": "4.4.10",
"104070": "4.4.11",
"105013": "4.5.0 Beta 1",
"105014": "4.5.0 Beta 1",
"105015": "4.5.0 Beta 2",
@@ -607,41 +250,30 @@
"107751": "4.7.16",
"107760": "4.7.17 Beta 1",
"107761": "4.7.17 Beta 2",
"107762": "4.7.17 Beta 3",
"107763": "4.7.17",
"107764": "4.7.17",
"107765": "4.7.17",
"107770": "4.7.18 Beta 1",
"107771": "4.7.18 Beta 2",
"107772": "4.7.18 Beta 3",
"107773": "4.7.18",
"107774": "4.7.18",
"107775": "4.7.18",
"107780": "4.7.19 Beta 1",
"107781": "4.7.19 Beta 2",
"107782": "4.7.19 Beta 3",
"107783": "4.7.19 Beta 4",
"107784": "4.7.19",
"107785": "4.7.19",
"107786": "4.7.19",
"107787": "4.7.19",
"107795": "4.7.20 Beta 1",
"107796": "4.7.20 Beta 2",
"107797": "4.7.20 Beta 3",
"107798": "4.7.20 Beta 4",
"107799": "4.7.20 Beta 5",
"107800": "4.7.20",
"107801": "4.7.20",
"107802": "4.7.20",
"107803": "4.7.20",
"107810": "4.7.21 Beta 1",
"107811": "4.7.21",
"107815": "4.7.22 Beta 1",
"107816": "4.7.22 Beta 2",
"107817": "4.7.22",
"107818": "4.7.22",
"107819": "4.7.22",
"107820": "4.7.22",
"107826": "4.7.23 Beta 1",
"107827": "4.7.23"
"500001": "5.0.0 Alpha 1",
"500002": "5.0.0 Alpha 2",
"5000003": "5.0.0 Alpha 3",
"5000004": "5.0.0 Alpha 4",
"5000005": "5.0.0 Alpha 5",
"5000006": "5.0.0 Alpha 5",
"5000007": "5.0.0 Alpha 5",
"5000008": "5.0.0 Alpha 5",
"5000009": "5.0.0 Alpha 6",
"5000010": "5.0.0 Alpha 7",
"5000011": "5.0.0 Alpha 8",
"5000012": "5.0.0 Alpha 9",
"5000013": "5.0.0 Alpha 9",
"5000014": "5.0.0 Alpha 9",
"5000015": "5.0.0 Alpha 10",
"5000016": "5.0.0 Alpha 11",
"5000017": "5.0.0 Alpha 11",
"5000018": "5.0.0 Alpha 12",
"5000019": "5.0.0 Alpha 12",
"5000020": "5.0.0 Alpha 12",
"5000021": "5.0.0 Alpha 13",
"5000022": "5.0.0 Alpha 14",
"5000023": "5.0.0 Alpha 15",
"5000024": "5.0.0 Alpha 16",
"5000025": "5.0.0 Alpha 16",
"5000026": "5.0.0 Beta 1"
}
@@ -1,71 +0,0 @@
<?php
/**
* @brief BBCode Tag
* @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 Blogs
* @since 05 Feb 2016
*/
namespace IPS\blog\extensions\core\BBCode;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* BBCode Tag
*/
class _blog
{
/**
* Permission Check
*
* @param \IPS\Member $member The member
* @param string $area The Editor area
* @return bool
*/
public function permissionCheck( \IPS\Member $member, $area )
{
return \IPS\Text\Parser::canUse( $member, 'ipsLink', $area );
}
/**
* Get Configuration
*
* @code
return array(
'tag' => 'span', // The HTML tag to use
'attributes' => array( ... ) // Key/Value pairs of attributes to use (optional) - can use {option} to get the [tag=option] value
'callback' => function( $node, $matches, $document ) // A callback to modify the DOMNode object
{
...
},
'block' => FALSE, // If this is a block-level tag (optional, default false)
'single' => FALSE, // If this is a single tag, with no content (optional, default false)
)
* @endcode
* @return array
*/
public function getConfiguration()
{
return array(
'tag' => 'a',
'callback' => function( \DOMElement $node, $matches, \DOMDocument $document )
{
try
{
$node->setAttribute( 'href', (string) \IPS\blog\Blog::load( \intval( $matches[2] ) )->url() );
}
catch ( \Exception $e ) {}
return $node;
},
);
}
}
@@ -1,71 +0,0 @@
<?php
/**
* @brief BBCode Tag
* @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 Blogs
* @since 08 Feb 2016
*/
namespace IPS\blog\extensions\core\BBCode;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* BBCode Tag
*/
class _entry
{
/**
* Permission Check
*
* @param \IPS\Member $member The member
* @param string $area The Editor area
* @return bool
*/
public function permissionCheck( \IPS\Member $member, $area )
{
return \IPS\Text\Parser::canUse( $member, 'ipsLink', $area );
}
/**
* Get Configuration
*
* @code
return array(
'tag' => 'span', // The HTML tag to use
'attributes' => array( ... ) // Key/Value pairs of attributes to use (optional) - can use {option} to get the [tag=option] value
'callback' => function( $node, $matches, $document ) // A callback to modify the DOMNode object
{
...
},
'block' => FALSE, // If this is a block-level tag (optional, default false)
'single' => FALSE, // If this is a single tag, with no content (optional, default false)
)
* @endcode
* @return array
*/
public function getConfiguration()
{
return array(
'tag' => 'a',
'callback' => function( \DOMElement $node, $matches, \DOMDocument $document )
{
try
{
$node->setAttribute( 'href', (string) \IPS\blog\Entry::load( \intval( $matches[2] ) )->url() );
}
catch ( \Exception $e ) {}
return $node;
},
);
}
}
@@ -12,41 +12,43 @@
namespace IPS\blog\extensions\core\ContentRouter;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use IPS\Application\Module;
use IPS\Extensions\ContentRouterAbstract;
use IPS\Member;
use IPS\Member\Group;
use function defined;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* @brief Content Router extension: Entries
*/
class _Blog
class Blog extends ContentRouterAbstract
{
/**
* @brief Owned Node Classes
*/
public $ownedNodes = array( 'IPS\blog\Blog' );
/**
* @brief Content Item Classes
*/
public $classes = array();
public array $ownedNodes = array( 'IPS\blog\Blog' );
/**
* @brief Can be shown in similar content
*/
public $similarContent = TRUE;
public bool $similarContent = TRUE;
/**
* Constructor
*
* @param \IPS\Member|\IPS\Member\Group|NULL $member If checking access, the member/group to check for, or NULL to not check access
* @param Group|Member|null $member If checking access, the member/group to check for, or NULL to not check access
* @return void
*/
public function __construct( $member = NULL )
public function __construct( Group|Member $member = NULL )
{
if ( $member === NULL or $member->canAccessModule( \IPS\Application\Module::get( 'blog', 'blogs', 'front' ) ) )
if ( $member === NULL or $member->canAccessModule( Module::get( 'blog', 'blogs', 'front' ) ) )
{
$this->classes[] = 'IPS\blog\Entry';
}
@@ -1,70 +0,0 @@
<?php
/**
* @brief Create Menu Extension : Entry
* @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 Blog
* @since 10 Mar 2014
*/
namespace IPS\blog\extensions\core\CreateMenu;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Create Menu Extension: Entry
*/
class _Entry
{
/**
* Get Items
*
* @return array
*/
public function getItems()
{
/* Posting limits */
if ( \IPS\Member::loggedIn()->checkPostsPerDay() === FALSE )
{
return array();
}
$blogs = \IPS\blog\Blog::loadByOwner( \IPS\Member::loggedIn(), array( array( 'blog_disabled=?', 0 ) ) );
if (
\count( $blogs )
or
( \IPS\Settings::i()->club_nodes_in_apps and \count( \IPS\blog\Blog::clubNodes( 'add' ) ) )
) {
if ( !\IPS\Settings::i()->club_nodes_in_apps AND \count( $blogs ) === 1 )
{
$ourBlog = array_shift( $blogs );
return array(
'blog_entry' => array(
'link' => \IPS\Http\Url::internal( "app=blog&module=blogs&controller=submit&id=" . $ourBlog->_id, 'front', 'blog_submit' ),
)
);
}
else
{
return array(
'blog_entry' => array(
'link' => \IPS\Http\Url::internal( "app=blog&module=blogs&controller=submit", 'front', 'blog_submit' ),
'extraData' => array( 'data-ipsDialog' => true, 'data-ipsDialog-size' => "narrow", ),
'title' => 'select_blog'
)
);
}
}
else
{
return array();
}
}
}
@@ -12,23 +12,29 @@
namespace IPS\blog\extensions\core\Dashboard;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use IPS\Db;
use IPS\Extensions\DashboardAbstract;
use IPS\Theme;
use function defined;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* @brief Dashboard extension: Overview
*/
class _Overview
class Overview extends DashboardAbstract
{
/**
* Can the current user view this dashboard item?
*
* @return bool
*/
public function canView()
public function canView(): bool
{
return TRUE;
}
@@ -38,26 +44,16 @@ class _Overview
*
* @return string
*/
public function getBlock()
public function getBlock(): string
{
/* Basic stats */
$data = array(
'total_blogs' => (int) \IPS\Db::i()->select( 'COUNT(*)', 'blog_blogs' )->first(),
'total_entries' => (int) \IPS\Db::i()->select( 'COUNT(*)', 'blog_entries' )->first(),
'total_comments' => (int) \IPS\Db::i()->select( 'COUNT(*)', 'blog_comments' )->first(),
'total_blogs' => (int) Db::i()->select( 'COUNT(*)', 'blog_blogs' )->first(),
'total_entries' => (int) Db::i()->select( 'COUNT(*)', 'blog_entries' )->first(),
'total_comments' => (int) Db::i()->select( 'COUNT(*)', 'blog_comments' )->first(),
);
/* Display */
return \IPS\Theme::i()->getTemplate( 'dashboard', 'blog' )->overview( $data );
}
/**
* Return the block information
*
* @return array array( 'name' => 'Block title', 'key' => 'unique_key', 'size' => [1,2,3], 'by' => 'Author name' )
*/
public function getInfo()
{
return array();
return Theme::i()->getTemplate( 'dashboard', 'blog' )->overview( $data );
}
}
@@ -12,36 +12,41 @@
namespace IPS\blog\extensions\core\EditorLocations;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use InvalidArgumentException;
use IPS\blog\Blog;
use IPS\blog\Entry\Comment;
use IPS\Content;
use IPS\Db;
use IPS\Extensions\EditorLocationsAbstract;
use IPS\Helpers\Form\Editor;
use IPS\Http\Url;
use IPS\Member;
use IPS\Node\Model;
use IPS\Text\Parser;
use LogicException;
use RuntimeException;
use function defined;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Editor Extension: Blogs
*/
class _Blogs
class Blogs extends EditorLocationsAbstract
{
/**
* Can we use HTML in this editor?
*
* @param \IPS\Member $member The member
* @return bool|null NULL will cause the default value (based on the member's permissions) to be used, and is recommended in most cases. A boolean value will override that.
*/
public function canUseHtml( $member )
{
return NULL;
}
/**
* Can we use attachments in this editor?
*
* @param \IPS\Member $member The member
* @param \IPS\Helpers\Form\Editor $field The editor field
* @param Member $member The member
* @param Editor $field The editor field
* @return bool|null NULL will cause the default value (based on the member's permissions) to be used, and is recommended in most cases. A boolean value will override that.
*/
public function canAttach( $member, $field )
public function canAttach( Member $member, Editor $field ): ?bool
{
return NULL;
}
@@ -50,11 +55,11 @@ class _Blogs
* Can whatever is posted in this editor be moderated?
* If this returns TRUE, we must ensure the content is ran through word, link and image filters
*
* @param \IPS\Member $member The member
* @param \IPS\Helpers\Form\Editor $field The editor field
* @param Member $member The member
* @param Editor $field The editor field
* @return bool
*/
public function canBeModerated( $member, $field )
public function canBeModerated( Member $member, Editor $field ): bool
{
if ( preg_match( '/^blogs\-(?:new-blog|blog|new-blog-sidebar|new-blog-group\d+)$/', $field->options['autoSaveKey'] ) )
{
@@ -80,89 +85,72 @@ class _Blogs
{
if ( \IPS\IN_DEV )
{
throw new \RuntimeException( 'Unknown canBeModerated: ' . $field->options['autoSaveKey'] );
throw new RuntimeException( 'Unknown canBeModerated: ' . $field->options['autoSaveKey'] );
}
return FALSE;
return parent::canBeModerated( $member, $field );
}
}
/**
* Permission check for attachments
*
* @param \IPS\Member $member The member
* @param int|null $id1 Primary ID
* @param int|null $id2 Secondary ID
* @param string|null $id3 Arbitrary data
* @param array $attachment The attachment data
* @param bool $viewOnly If true, just check if the user can see the attachment rather than download it
* @param Member $member The member
* @param int|null $id1 Primary ID
* @param int|null $id2 Secondary ID
* @param string|null $id3 Arbitrary data
* @param array $attachment The attachment data
* @param bool $viewOnly If true, just check if the user can see the attachment rather than download it
* @return bool
*/
public function attachmentPermissionCheck( $member, $id1, $id2, $id3, $attachment, $viewOnly=FALSE )
public function attachmentPermissionCheck( Member $member, ?int $id1, ?int $id2, ?string $id3, array $attachment, bool $viewOnly=FALSE ): bool
{
/* The attachment is attached to a comment */
if ( $id2 )
{
return \IPS\blog\Entry\Comment::load( $id2 )->canView( $member );
return Comment::load( $id2 )->canView( $member );
}
else
{
return \IPS\blog\Blog::load( $id1 )->can( 'view', $member );
return Blog::load( $id1 )->can( 'view', $member );
}
}
/**
* Attachment lookup
*
* @param int|null $id1 Primary ID
* @param int|null $id2 Secondary ID
* @param string|null $id3 Arbitrary data
* @return \IPS\blog\Blog
* @throws \LogicException
* @param int|null $id1 Primary ID
* @param int|null $id2 Secondary ID
* @param string|null $id3 Arbitrary data
* @return Content|Member|Model|Url|null
* @throws LogicException
*/
public function attachmentLookup( $id1, $id2, $id3 )
public function attachmentLookup( ?int $id1=null, ?int $id2=null, ?string $id3=null ): Model|Content|Url|Member|null
{
/* The attachment is attached to a comment */
if ( $id2 )
{
return \IPS\blog\Entry\Comment::load( $id2 );
return Comment::load( $id2 );
}
else
{
return \IPS\blog\Blog::load( $id1 );
return Blog::load( $id1 );
}
}
/**
* Rebuild attachment images in non-content item areas
*
* @param int|null $offset Offset to start from
* @param int|null $max Maximum to parse
* @return int Number completed
* @note This method is optional and will only be called if it exists
*/
public function rebuildAttachmentImages( $offset, $max )
{
return $this->performRebuild( $offset, $max, array( 'IPS\Text\Parser', 'rebuildAttachmentUrls' ) );
}
/**
* Rebuild content post-upgrade
*
* @param int|null $offset Offset to start from
* @param int|null $max Maximum to parse
* @param int|null $offset Offset to start from
* @param int|null $max Maximum to parse
* @return int Number completed
* @note This method is optional and will only be called if it exists
*/
public function rebuildContent( $offset, $max )
public function rebuildContent( ?int $offset, ?int $max ): int
{
return $this->performRebuild( $offset, $max, array( 'IPS\Text\LegacyParser', 'parseStatic' ) );
}
/**
* @brief Use the cached image URL instead of the original URL
*/
protected $proxyUrl = FALSE;
/**
* Rebuild content to add or remove image proxy
*
@@ -172,66 +160,53 @@ class _Blogs
* @return int Number completed
* @note This method is optional and will only be called if it exists
*/
public function rebuildImageProxy( $offset, $max, $proxyUrl = FALSE )
public function rebuildImageProxy( ?int $offset, ?int $max, bool $proxyUrl = FALSE ): int
{
$this->proxyUrl = $proxyUrl;
return $this->performRebuild( $offset, $max, 'parseImageProxy' );
$callback = function( $value ) use ( $proxyUrl ) {
return Parser::removeImageProxy( $value, $proxyUrl );
};
return $this->performRebuild( $offset, $max, $callback );
}
/**
* @brief Store lazy loading status ( true = enabled )
*/
protected $_lazyLoadStatus = null;
/**
* Rebuild content to add or remove lazy loading
*
* @param int|null $offset Offset to start from
* @param int|null $max Maximum to parse
* @param bool $status Enable/Disable lazy loading
* @return int Number completed
* @note This method is optional and will only be called if it exists
*/
public function rebuildLazyLoad( $offset, $max, $status=TRUE )
public function rebuildLazyLoad( ?int $offset, ?int $max ): int
{
$this->_lazyLoadStatus = $status;
return $this->performRebuild( $offset, $max, 'parseLazyLoad' );
return $this->performRebuild( $offset, $max, [ 'IPS\Text\Parser', 'parseLazyLoad' ] );
}
/**
* Perform rebuild - abstracted as the call for rebuildContent() and rebuildAttachmentImages() is nearly identical
*
* @param int|null $offset Offset to start from
* @param int|null $max Maximum to parse
* @param callable $callback Method to call to rebuild content
* @param int|null $offset Offset to start from
* @param int|null $max Maximum to parse
* @param callable $callback Method to call to rebuild content
* @return int Number completed
*/
protected function performRebuild( $offset, $max, $callback )
protected function performRebuild( ?int $offset, ?int $max, callable $callback ): int
{
$did = 0;
/* Language bits */
foreach( \IPS\Db::i()->select( '*', 'core_sys_lang_words', "word_key LIKE 'blogs_blog_%_desc'", 'word_id ASC', array( $offset, $max ) ) as $word )
foreach( Db::i()->select( '*', 'core_sys_lang_words', "word_key LIKE 'blogs_blog_%_desc'", 'word_id ASC', array( $offset, $max ) ) as $word )
{
$did++;
$rebuilt = FALSE;
try
{
if( $callback == 'parseImageProxy' )
{
$rebuilt = \IPS\Text\Parser::removeImageProxy( $word['word_custom'], $this->proxyUrl );
}
elseif( $callback == 'parseLazyLoad' )
{
$rebuilt = \IPS\Text\Parser::parseLazyLoad( $word['word_custom'], $this->_lazyLoadStatus );
}
else
if( !empty( $word['word_custom'] ) )
{
$rebuilt = $callback( $word['word_custom'] );
}
}
catch( \InvalidArgumentException $e )
catch( InvalidArgumentException $e )
{
if( $callback[1] == 'parseStatic' AND $e->getcode() == 103014 )
{
@@ -245,7 +220,7 @@ class _Blogs
if( $rebuilt !== FALSE )
{
\IPS\Db::i()->update( 'core_sys_lang_words', array( 'word_custom' => $rebuilt ), 'word_id=' . $word['word_id'] );
Db::i()->update( 'core_sys_lang_words', array( 'word_custom' => $rebuilt ), 'word_id=' . $word['word_id'] );
}
}
@@ -257,8 +232,8 @@ class _Blogs
*
* @return int Total Count
*/
public function contentCount()
public function contentCount(): int
{
return \IPS\Db::i()->select( 'COUNT(*) as count', 'core_sys_lang_words', "word_key LIKE 'blogs_blog_%_desc'" )->first();
return Db::i()->select( 'COUNT(*) as count', 'core_sys_lang_words', "word_key LIKE 'blogs_blog_%_desc'" )->first();
}
}
@@ -12,36 +12,38 @@
namespace IPS\blog\extensions\core\EditorLocations;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use InvalidArgumentException;
use IPS\Content;
use IPS\Db;
use IPS\Extensions\EditorLocationsAbstract;
use IPS\Helpers\Form\Editor;
use IPS\Http\Url;
use IPS\Member;
use IPS\Node\Model;
use IPS\Text\Parser;
use LogicException;
use function defined;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Editor Extension: Categories
*/
class _Categories
class Categories extends EditorLocationsAbstract
{
/**
* Can we use HTML in this editor?
*
* @param \IPS\Member $member The member
* @return bool|null NULL will cause the default value (based on the member's permissions) to be used, and is recommended in most cases. A boolean value will override that.
*/
public function canUseHtml( $member )
{
return NULL;
}
/**
* Can we use attachments in this editor?
*
* @param \IPS\Member $member The member
* @param \IPS\Helpers\Form\Editor $field The editor field
* @param Member $member The member
* @param Editor $field The editor field
* @return bool|null NULL will cause the default value (based on the member's permissions) to be used, and is recommended in most cases. A boolean value will override that.
*/
public function canAttach( $member, $field )
public function canAttach( Member $member, Editor $field ): ?bool
{
return NULL;
}
@@ -49,15 +51,15 @@ class _Categories
/**
* Permission check for attachments
*
* @param \IPS\Member $member The member
* @param int|null $id1 Primary ID
* @param int|null $id2 Secondary ID
* @param string|null $id3 Arbitrary data
* @param array $attachment The attachment data
* @param bool $viewOnly If true, just check if the user can see the attachment rather than download it
* @param Member $member The member
* @param int|null $id1 Primary ID
* @param int|null $id2 Secondary ID
* @param string|null $id3 Arbitrary data
* @param array $attachment The attachment data
* @param bool $viewOnly If true, just check if the user can see the attachment rather than download it
* @return bool
*/
public function attachmentPermissionCheck( $member, $id1, $id2, $id3, $attachment, $viewOnly=FALSE )
public function attachmentPermissionCheck( Member $member, ?int $id1, ?int $id2, ?string $id3, array $attachment, bool $viewOnly=FALSE ): bool
{
return TRUE;
}
@@ -65,108 +67,80 @@ class _Categories
/**
* Attachment lookup
*
* @param int|null $id1 Primary ID
* @param int|null $id2 Secondary ID
* @param string|null $id3 Arbitrary data
* @return \IPS\Http\Url|\IPS\Content|\IPS\Node\Model
* @throws \LogicException
* @param int|null $id1 Primary ID
* @param int|null $id2 Secondary ID
* @param string|null $id3 Arbitrary data
* @return Content|Member|Model|Url|NULL
* @throws LogicException
*/
public function attachmentLookup( $id1, $id2, $id3 )
public function attachmentLookup( ?int $id1=null, ?int $id2=null, ?string $id3=null ): Model|Content|Url|Member|null
{
switch ( $id3 )
{
case 'bcategory':
return \IPS\Http\Url::internal( "app=blog&module=blogs&controller=categories&do=form&id={$id1}", 'admin' );
break;
};
}
return Url::internal( "app=blog&module=blogs&controller=categories&do=form&id={$id1}", 'admin' );
}
/**
* Rebuild attachment images in non-content item areas
*
* @param int|null $offset Offset to start from
* @param int|null $max Maximum to parse
* @return int Number completed
* @note This method is optional and will only be called if it exists
*/
public function rebuildAttachmentImages( $offset, $max )
{
return $this->performRebuild( $offset, $max, array( 'IPS\Text\Parser', 'rebuildAttachmentUrls' ) );
return NULL;
}
/**
* @brief Use the cached image URL instead of the original URL
*/
protected $proxyUrl = FALSE;
/**
* Rebuild content to add or remove image proxy
*
* @param int|null $offset Offset to start from
* @param int|null $max Maximum to parse
* @param bool $proxyUrl Use the cached image URL instead of the original URL
* @param int|null $offset Offset to start from
* @param int|null $max Maximum to parse
* @param bool $proxyUrl Use the cached image URL instead of the original URL
* @return int Number completed
* @note This method is optional and will only be called if it exists
*/
public function rebuildImageProxy( $offset, $max, $proxyUrl = FALSE )
public function rebuildImageProxy( ?int $offset, ?int $max, bool $proxyUrl=FALSE ): int
{
$this->proxyUrl = $proxyUrl;
return $this->performRebuild( $offset, $max, 'parseImageProxy' );
$callback = function( $value ) use ( $proxyUrl ) {
return Parser::removeImageProxy( $value, $proxyUrl );
};
return $this->performRebuild( $offset, $max, $callback );
}
/**
* @brief Store lazy loading status ( true = enabled )
*/
protected $_lazyLoadStatus = null;
/**
* Rebuild content to add or remove lazy loading
*
* @param int|null $offset Offset to start from
* @param int|null $max Maximum to parse
* @param bool $status Enable/Disable lazy loading
* @param int|null $offset Offset to start from
* @param int|null $max Maximum to parse
* @return int Number completed
* @note This method is optional and will only be called if it exists
*/
public function rebuildLazyLoad( $offset, $max, $status=TRUE )
public function rebuildLazyLoad( ?int $offset, ?int $max ): int
{
$this->_lazyLoadStatus = $status;
return $this->performRebuild( $offset, $max, 'parseLazyLoad' );
return $this->performRebuild( $offset, $max, [ 'IPS\Text\Parser', 'parseLazyLoad' ] );
}
/**
* Perform rebuild - abstracted as the call for rebuildContent() and rebuildAttachmentImages() is nearly identical
*
* @param int|null $offset Offset to start from
* @param int|null $max Maximum to parse
* @param callable $callback Method to call to rebuild content
* @return int Number completed
* @param int|null $offset Offset to start from
* @param int|null $max Maximum to parse
* @param callable $callback Method to call to rebuild content
* @return int
*/
protected function performRebuild( $offset, $max, $callback )
protected function performRebuild( ?int $offset, ?int $max, callable $callback ): int
{
/* We will do everything except pages first */
$did = 0;
if( !$offset )
{
/* Language bits */
foreach( \IPS\Db::i()->select( '*', 'core_sys_lang_words', "word_key LIKE 'blog_category_%_desc'", 'word_id ASC', array( $offset, $max ) ) as $word )
foreach( Db::i()->select( '*', 'core_sys_lang_words', "word_key LIKE 'blog_category_%_desc'", 'word_id ASC', array( $offset, $max ) ) as $word )
{
$did++;
$rebuilt = FALSE;
try
{
if( $callback == 'parseImageProxy' )
{
$rebuilt = \IPS\Text\Parser::removeImageProxy( $word['word_custom'], $this->proxyUrl );
}
elseif( $callback == 'parseLazyLoad' )
{
$rebuilt = \IPS\Text\Parser::parseLazyLoad( $word['word_custom'], $this->_lazyLoadStatus );
}
else
if( !empty( $word['word_custom'] ) )
{
$rebuilt = $callback( $word['word_custom'] );
}
}
catch( \InvalidArgumentException $e )
catch( InvalidArgumentException $e )
{
if( $callback[1] == 'parseStatic' AND $e->getcode() == 103014 )
{
@@ -180,11 +154,12 @@ class _Categories
if( $rebuilt !== FALSE )
{
\IPS\Db::i()->update( 'core_sys_lang_words', array( 'word_custom' => $rebuilt ), 'word_id=' . $word['word_id'] );
Db::i()->update( 'core_sys_lang_words', array( 'word_custom' => $rebuilt ), 'word_id=' . $word['word_id'] );
}
}
}
return $did;
}
/**
@@ -192,8 +167,8 @@ class _Categories
*
* @return int Total Count
*/
public function contentCount()
public function contentCount(): int
{
return \IPS\Db::i()->select( 'COUNT(*) as count', 'core_sys_lang_words', "word_key LIKE 'blog_category_%_desc'" )->first();
return Db::i()->select( 'COUNT(*) as count', 'core_sys_lang_words', "word_key LIKE 'blog_category_%_desc'" )->first();
}
}
@@ -12,36 +12,37 @@
namespace IPS\blog\extensions\core\EditorLocations;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use IPS\blog\Entry;
use IPS\Content;
use IPS\Extensions\EditorLocationsAbstract;
use IPS\Helpers\Form\Editor;
use IPS\Http\Url;
use IPS\Member;
use IPS\Node\Model;
use LogicException;
use RuntimeException;
use function defined;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Editor Extension: Blogs
*/
class _Entries
class Entries extends EditorLocationsAbstract
{
/**
* Can we use HTML in this editor?
*
* @param \IPS\Member $member The member
* @return bool|null NULL will cause the default value (based on the member's permissions) to be used, and is recommended in most cases. A boolean value will override that.
*/
public function canUseHtml( $member )
{
return NULL;
}
/**
* Can we use attachments in this editor?
*
* @param \IPS\Member $member The member
* @param \IPS\Helpers\Form\Editor $field The editor field
* @param Member $member The member
* @param Editor $field The editor field
* @return bool|null NULL will cause the default value (based on the member's permissions) to be used, and is recommended in most cases. A boolean value will override that.
*/
public function canAttach( $member, $field )
public function canAttach( Member $member, Editor $field ): ?bool
{
return NULL;
}
@@ -50,11 +51,11 @@ class _Entries
* Can whatever is posted in this editor be moderated?
* If this returns TRUE, we must ensure the content is ran through word, link and image filters
*
* @param \IPS\Member $member The member
* @param \IPS\Helpers\Form\Editor $field The editor field
* @param Member $member The member
* @param Editor $field The editor field
* @return bool
*/
public function canBeModerated( $member, $field )
public function canBeModerated( Member $member, Editor $field ): bool
{
if ( preg_match( '/^blog\-(?:entry|edit)\-\d+$/', $field->options['autoSaveKey'] ) )
{
@@ -64,40 +65,41 @@ class _Entries
{
if ( \IPS\IN_DEV )
{
throw new \RuntimeException( 'Unknown canBeModerated: ' . $field->options['autoSaveKey'] );
throw new RuntimeException( 'Unknown canBeModerated: ' . $field->options['autoSaveKey'] );
}
return FALSE;
return parent::canBeModerated( $member, $field );
}
}
/**
* Permission check for attachments
*
* @param \IPS\Member $member The member
* @param int|null $id1 Primary ID
* @param int|null $id2 Secondary ID
* @param string|null $id3 Arbitrary data
* @param array $attachment The attachment data
* @param bool $viewOnly If true, just check if the user can see the attachment rather than download it
* @param Member $member The member
* @param int|null $id1 Primary ID
* @param int|null $id2 Secondary ID
* @param string|null $id3 Arbitrary data
* @param array $attachment The attachment data
* @param bool $viewOnly If true, just check if the user can see the attachment rather than download it
* @return bool
*/
public function attachmentPermissionCheck( $member, $id1, $id2, $id3, $attachment, $viewOnly=FALSE )
public function attachmentPermissionCheck( Member $member, ?int $id1, ?int $id2, ?string $id3, array $attachment, bool $viewOnly=FALSE ): bool
{
return \IPS\blog\Entry::load( $id1 )->canView( $member );
return Entry::load( $id1 )->canView( $member );
}
/**
* Attachment lookup
*
* @param int|null $id1 Primary ID
* @param int|null $id2 Secondary ID
* @param string|null $id3 Arbitrary data
* @return \IPS\blog\Blog
* @throws \LogicException
* @param int|null $id1 Primary ID
* @param int|null $id2 Secondary ID
* @param string|null $id3 Arbitrary data
* @return Content|Member|Model|Url|null
* @throws LogicException
*/
public function attachmentLookup( $id1, $id2, $id3 )
public function attachmentLookup( ?int $id1=null, ?int $id2=null, ?string $id3=null ): Model|Content|Url|Member|null
{
return \IPS\blog\Entry::load( $id1 );
return Entry::load( $id1 );
}
}
@@ -12,86 +12,78 @@
namespace IPS\blog\extensions\core\FileStorage;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use Exception;
use IPS\Db;
use IPS\Extensions\FileStorageAbstract;
use IPS\File;
use UnderflowException;
use function defined;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* File Storage Extension: Blogs (cover photos)
*/
class _Blogs
class Blogs extends FileStorageAbstract
{
/**
* Count stored files
*
* @return int
*/
public function count()
public function count(): int
{
return \IPS\Db::i()->select( 'COUNT(*)', 'blog_blogs', 'blog_cover_photo IS NOT NULL' )->first();
return Db::i()->select( 'COUNT(*)', 'blog_blogs', 'blog_cover_photo IS NOT NULL' )->first();
}
/**
* Move stored files
*
* @param int $offset This will be sent starting with 0, increasing to get all files stored by this extension
* @param int $storageConfiguration New storage configuration ID
* @param int|NULL $oldConfiguration Old storage configuration ID
* @throws \Underflowexception When file record doesn't exist. Indicating there are no more files to move
* @param int $offset This will be sent starting with 0, increasing to get all files stored by this extension
* @param int $storageConfiguration New storage configuration ID
* @param int|null $oldConfiguration Old storage configuration ID
* @return void
*@throws UnderflowException When file record doesn't exist. Indicating there are no more files to move
*/
public function move( $offset, $storageConfiguration, $oldConfiguration=NULL )
public function move( int $offset, int $storageConfiguration, int $oldConfiguration=NULL ) : void
{
$record = \IPS\Db::i()->select( '*', 'blog_blogs', 'blog_cover_photo IS NOT NULL', 'blog_id', array( $offset, 1 ) )->first();
$record = Db::i()->select( '*', 'blog_blogs', 'blog_cover_photo IS NOT NULL', 'blog_id', array( $offset, 1 ) )->first();
try
{
$file = \IPS\File::get( $oldConfiguration ?: 'blog_Blogs', $record['blog_cover_photo'] )->move( $storageConfiguration );
$file = File::get( $oldConfiguration ?: 'blog_Blogs', $record['blog_cover_photo'] )->move( $storageConfiguration );
if ( (string) $file != $record['blog_cover_photo'] )
{
\IPS\Db::i()->update( 'blog_blogs', array( 'blog_cover_photo' => (string) $file ), array( 'blog_id=?', $record['blog_id'] ) );
Db::i()->update( 'blog_blogs', array( 'blog_cover_photo' => (string) $file ), array( 'blog_id=?', $record['blog_id'] ) );
}
}
catch( \Exception $e )
catch( Exception )
{
/* Any issues are logged and the \IPS\Db::i()->update not run as the exception is thrown */
}
}
/**
* Fix all URLs
*
* @param int $offset This will be sent starting with 0, increasing to get all files stored by this extension
* @return void
*/
public function fixUrls( $offset )
{
$record = \IPS\Db::i()->select( '*', 'blog_blogs', 'blog_cover_photo IS NOT NULL', 'blog_id', array( $offset, 1 ) )->first();
if ( $new = \IPS\File::repairUrl( $record['blog_cover_photo'] ) )
{
\IPS\Db::i()->update( 'blog_blogs', array( 'blog_cover_photo' => $new ), array( 'blog_id=?', $record['blog_id'] ) );
}
}
/**
* Check if a file is valid
*
* @param string $file The file path to check
* @param File|string $file The file path to check
* @return bool
*/
public function isValidFile( $file )
public function isValidFile( File|string $file ): bool
{
try
{
$record = \IPS\Db::i()->select( '*', 'blog_blogs', array( 'blog_cover_photo=?', (string) $file ) )->first();
$record = Db::i()->select( '*', 'blog_blogs', array( 'blog_cover_photo=?', (string) $file ) )->first();
return TRUE;
}
catch ( \UnderflowException $e )
catch ( UnderflowException )
{
return FALSE;
}
@@ -102,15 +94,15 @@ class _Blogs
*
* @return void
*/
public function delete()
public function delete() : void
{
foreach( \IPS\Db::i()->select( '*', 'blog_blogs', 'blog_cover_photo IS NOT NULL' ) as $blog )
foreach( Db::i()->select( '*', 'blog_blogs', 'blog_cover_photo IS NOT NULL' ) as $blog )
{
try
{
\IPS\File::get( 'blog_Blogs', $blog['blog_cover_photo'] )->delete();
File::get( 'blog_Blogs', $blog['blog_cover_photo'] )->delete();
}
catch( \Exception $e ){}
catch( Exception ){}
}
}
}
@@ -12,86 +12,78 @@
namespace IPS\blog\extensions\core\FileStorage;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use Exception;
use IPS\Db;
use IPS\Extensions\FileStorageAbstract;
use IPS\File;
use UnderflowException;
use function defined;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* File Storage Extension: Blog Entries (cover photos)
*/
class _Entries
class Entries extends FileStorageAbstract
{
/**
* Count stored files
*
* @return int
*/
public function count()
public function count(): int
{
return \IPS\Db::i()->select( 'COUNT(*)', 'blog_entries', 'entry_cover_photo IS NOT NULL' )->first();
return Db::i()->select( 'COUNT(*)', 'blog_entries', 'entry_cover_photo IS NOT NULL' )->first();
}
/**
* Move stored files
*
* @param int $offset This will be sent starting with 0, increasing to get all files stored by this extension
* @param int $storageConfiguration New storage configuration ID
* @param int|NULL $oldConfiguration Old storage configuration ID
* @throws \Underflowexception When file record doesn't exist. Indicating there are no more files to move
* @param int $offset This will be sent starting with 0, increasing to get all files stored by this extension
* @param int $storageConfiguration New storage configuration ID
* @param int|null $oldConfiguration Old storage configuration ID
* @return void
*@throws UnderflowException When file record doesn't exist. Indicating there are no more files to move
*/
public function move( $offset, $storageConfiguration, $oldConfiguration=NULL )
public function move( int $offset, int $storageConfiguration, int $oldConfiguration=NULL ) : void
{
$record = \IPS\Db::i()->select( '*', 'blog_entries', 'entry_cover_photo IS NOT NULL', 'entry_id', array( $offset, 1 ) )->first();
$record = Db::i()->select( '*', 'blog_entries', 'entry_cover_photo IS NOT NULL', 'entry_id', array( $offset, 1 ) )->first();
try
{
$file = \IPS\File::get( $oldConfiguration ?: 'blog_Entries', $record['entry_cover_photo'] )->move( $storageConfiguration );
$file = File::get( $oldConfiguration ?: 'blog_Entries', $record['entry_cover_photo'] )->move( $storageConfiguration );
if ( (string) $file != $record['entry_cover_photo'] )
{
\IPS\Db::i()->update( 'blog_entries', array( 'entry_cover_photo' => (string) $file ), array( 'entry_id=?', $record['entry_id'] ) );
Db::i()->update( 'blog_entries', array( 'entry_cover_photo' => (string) $file ), array( 'entry_id=?', $record['entry_id'] ) );
}
}
catch( \Exception $e )
catch( Exception )
{
/* Any issues are logged and the \IPS\Db::i()->update not run as the exception is thrown */
}
}
/**
* Fix all URLs
*
* @param int $offset This will be sent starting with 0, increasing to get all files stored by this extension
* @return void
*/
public function fixUrls( $offset )
{
$record = \IPS\Db::i()->select( '*', 'blog_entries', 'entry_cover_photo IS NOT NULL', 'entry_id', array( $offset, 1 ) )->first();
if ( $new = \IPS\File::repairUrl( $record['blog_cover_photo'] ) )
{
\IPS\Db::i()->update( 'blog_entries', array( 'blog_cover_photo' => $new ), array( 'entry_id=?', $record['entry_id'] ) );
}
}
/**
* Check if a file is valid
*
* @param string $file The file path to check
* @param File|string $file The file path to check
* @return bool
*/
public function isValidFile( $file )
public function isValidFile( File|string $file ): bool
{
try
{
$record = \IPS\Db::i()->select( '*', 'blog_entries', array( 'entry_cover_photo=?', (string) $file ) )->first();
$record = Db::i()->select( '*', 'blog_entries', array( 'entry_cover_photo=?', (string) $file ) )->first();
return TRUE;
}
catch ( \UnderflowException $e )
catch ( UnderflowException )
{
return FALSE;
}
@@ -102,15 +94,15 @@ class _Entries
*
* @return void
*/
public function delete()
public function delete() : void
{
foreach( \IPS\Db::i()->select( '*', 'blog_entries', 'entry_cover_photo IS NOT NULL' ) as $blog )
foreach( Db::i()->select( '*', 'blog_entries', 'entry_cover_photo IS NOT NULL' ) as $blog )
{
try
{
\IPS\File::get( 'blog_Entries', $blog['entry_cover_photo'] )->delete();
File::get( 'blog_Entries', $blog['entry_cover_photo'] )->delete();
}
catch( \Exception $e ){}
catch( Exception ){}
}
}
}
@@ -12,64 +12,78 @@
namespace IPS\blog\extensions\core\FrontNavigation;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use IPS\Application\Module;
use IPS\core\FrontNavigation;
use IPS\core\FrontNavigation\FrontNavigationAbstract;
use IPS\Dispatcher;
use IPS\Http\Url;
use IPS\Member;
use function defined;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Front Navigation Extension: Blogs
*/
class _Blogs extends \IPS\core\FrontNavigation\FrontNavigationAbstract
class Blogs extends FrontNavigationAbstract
{
/**
* @var string Default icon
*/
public string $defaultIcon = '\f044';
/**
* Get Type Title which will display in the AdminCP Menu Manager
*
* @return string
*/
public static function typeTitle()
public static function typeTitle(): string
{
return \IPS\Member::loggedIn()->language()->addToStack('frontnavigation_blogs');
return Member::loggedIn()->language()->addToStack('frontnavigation_blogs');
}
/**
* Can the currently logged in user access the content this item links to?
*
* @return bool
* @return bool
*/
public function canAccessContent()
public function canAccessContent(): bool
{
return \IPS\Member::loggedIn()->canAccessModule( \IPS\Application\Module::get( 'blog', 'blogs' ) );
return Member::loggedIn()->canAccessModule( Module::get( 'blog', 'blogs' ) );
}
/**
* Get Title
*
* @return string
* @return string
*/
public function title()
public function title(): string
{
return \IPS\Member::loggedIn()->language()->addToStack('frontnavigation_blogs');
return Member::loggedIn()->language()->addToStack('frontnavigation_blogs');
}
/**
* Get Link
*
* @return \IPS\Http\Url
* @return string|Url|null
*/
public function link()
public function link(): Url|string|null
{
return \IPS\Http\Url::internal( "app=blog&module=blogs&controller=browse", 'front', 'blogs' );
return Url::internal( "app=blog&module=blogs&controller=browse", 'front', 'blogs' );
}
/**
* Is Active?
*
* @return bool
* @return bool
*/
public function active()
public function active(): bool
{
return !\IPS\core\FrontNavigation::$clubTabActive and \IPS\Dispatcher::i()->application->directory === 'blog';
return !FrontNavigation::$clubTabActive and !FrontNavigation::nodeExtensionIsActive( 'blog' ) and Dispatcher::i()->application->directory === 'blog';
}
}
@@ -11,53 +11,61 @@
namespace IPS\blog\extensions\core\GroupForm;
use IPS\Settings;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use IPS\Extensions\GroupFormAbstract;
use IPS\Helpers\Form;
use IPS\Helpers\Form\Number;
use IPS\Helpers\Form\YesNo;
use IPS\Member;
use IPS\Member\Group;
use IPS\Settings;
use function defined;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Admin CP Group Form
*/
class _Blog
class Blog extends GroupFormAbstract
{
/**
* Process Form
*
* @param \IPS\Helpers\Form $form The form
* @param \IPS\Member\Group $group Existing Group
* @param Form $form The form
* @param Group $group Existing Group
* @return void
*/
public function process( &$form, $group )
public function process( Form $form, Group $group ) : void
{
if( $group->g_id != Settings::i()->guest_group )
{
$form->add(new \IPS\Helpers\Form\YesNo('g_blog_allowlocal', $group->g_blog_allowlocal, FALSE, array('togglesOn' => array('g_blog_maxblogs', 'g_blog_allowprivate', 'g_blog_preventpublish', 'g_blog_allowownmod', 'g_blog_allowdelete'))));
$form->add(new \IPS\Helpers\Form\Number('g_blog_maxblogs', $group->g_blog_maxblogs, FALSE, array('unlimited' => 0), NULL, NULL, NULL, 'g_blog_maxblogs'));
$form->add(new \IPS\Helpers\Form\YesNo('g_blog_allowprivate', $group->g_blog_allowprivate, FALSE, array(), NULL, NULL, NULL, 'g_blog_allowprivate'));
$form->add(new \IPS\Helpers\Form\YesNo('g_blog_allowownmod', $group->g_blog_allowownmod, FALSE, array(), NULL, NULL, NULL, 'g_blog_allowownmod'));
$form->add(new \IPS\Helpers\Form\YesNo('g_blog_allowdelete', $group->g_blog_allowdelete, FALSE, array(), NULL, NULL, NULL, 'g_blog_allowdelete'));
$form->add(new YesNo('g_blog_allowlocal', $group->g_blog_allowlocal, FALSE, array('togglesOn' => array('g_blog_maxblogs', 'g_blog_allowprivate', 'g_blog_preventpublish', 'g_blog_allowownmod', 'g_blog_allowdelete'))));
$form->add(new Number('g_blog_maxblogs', $group->g_blog_maxblogs, FALSE, array('unlimited' => 0), NULL, NULL, NULL, 'g_blog_maxblogs'));
$form->add(new YesNo('g_blog_allowprivate', $group->g_blog_allowprivate, FALSE, array(), NULL, NULL, NULL, 'g_blog_allowprivate'));
$form->add(new YesNo('g_blog_allowownmod', $group->g_blog_allowownmod, FALSE, array(), NULL, NULL, NULL, 'g_blog_allowownmod'));
$form->add(new YesNo('g_blog_allowdelete', $group->g_blog_allowdelete, FALSE, array(), NULL, NULL, NULL, 'g_blog_allowdelete'));
}
$form->add(new \IPS\Helpers\Form\YesNo('g_blog_allowcomment', $group->g_blog_allowcomment));
if( $group->g_id == Settings::i()->guest_group AND Settings::i()->post_before_registering and Settings::i()->bot_antispam_type !== 'none' )
$form->add(new YesNo('g_blog_allowcomment', $group->g_blog_allowcomment));
if( $group->g_id == Settings::i()->guest_group AND Settings::i()->post_before_registering )
{
\IPS\Member::loggedIn()->language()->words['g_blog_allowcomment_desc'] = \IPS\Member::loggedIn()->language()->addToStack('g_blog_allowcomment_guestreg');
Member::loggedIn()->language()->words['g_blog_allowcomment_desc'] = Member::loggedIn()->language()->addToStack('g_blog_allowcomment_guestreg');
}
}
/**
* Save
*
* @param array $values Values from form
* @param \IPS\Member\Group $group The group
* @param array $values Values from form
* @param Group $group The group
* @return void
*/
public function save( $values, &$group )
public function save( array $values, Group $group ) : void
{
if( $group->g_id != Settings::i()->guest_group )
{
@@ -12,35 +12,44 @@
namespace IPS\blog\extensions\core\LiveSearch;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use IPS\blog\Blog;
use IPS\Db;
use IPS\Dispatcher;
use IPS\Extensions\LiveSearchAbstract;
use IPS\Member;
use IPS\Theme;
use function defined;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* @brief ACP Live Search Extension
*/
class _Blogs
class Blogs extends LiveSearchAbstract
{
/**
* Check we have access
*
* @return bool
*/
public function hasAccess()
public function hasAccess(): bool
{
/* Check Permissions */
return \IPS\Member::loggedIn()->hasAcpRestriction( 'blog', 'blog', 'blogs_manage' );
return Member::loggedIn()->hasAcpRestriction( 'blog', 'blog', 'blogs_manage' );
}
/**
* Get the search results
*
* @param string $searchTerm Search Term
* @param string $searchTerm Search Term
* @return array Array of results
*/
public function getResults( $searchTerm )
public function getResults( string $searchTerm ): array
{
/* Init */
$results = array();
@@ -50,10 +59,10 @@ class _Blogs
if( $this->hasAccess() )
{
/* Perform the search */
$blogs = \IPS\Db::i()->select(
$blogs = Db::i()->select(
"*",
'blog_blogs',
array( "blog_club_id IS NULL AND ( word_custom LIKE CONCAT( '%', ?, '%' ) AND lang_id=? )", $searchTerm, \IPS\Member::loggedIn()->language()->id ),
array( "blog_club_id IS NULL AND ( word_custom LIKE CONCAT( '%', ?, '%' ) AND lang_id=? )", $searchTerm, Member::loggedIn()->language()->id ),
NULL,
array( 0, 500 )
)->join(
@@ -64,9 +73,9 @@ class _Blogs
/* Format results */
foreach ( $blogs as $blog )
{
$blog = \IPS\blog\Blog::constructFromData( $blog );
$blog = Blog::constructFromData( $blog );
$results[] = \IPS\Theme::i()->getTemplate( 'livesearch', 'blog', 'admin' )->blog( $blog );
$results[] = Theme::i()->getTemplate( 'livesearch', 'blog', 'admin' )->blog( $blog );
}
}
@@ -78,8 +87,8 @@ class _Blogs
*
* @return bool
*/
public function isDefault()
public function isDefault(): bool
{
return \IPS\Dispatcher::i()->application->directory == 'blog';
return Dispatcher::i()->application->directory == 'blog';
}
}
@@ -12,53 +12,63 @@
namespace IPS\blog\extensions\core\MemberFilter;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use IPS\Db;
use IPS\Db\Select;
use IPS\Extensions\MemberFilterAbstract;
use IPS\Helpers\Form\Radio;
use IPS\Member;
use LogicException;
use function defined;
use function in_array;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Member Filter Extension
*/
class _Blog
class Blog extends MemberFilterAbstract
{
/**
* Determine if the filter is available in a given area
*
* @param string $area Area to check
* @param string $area Area to check (bulkmail, group_permissions, automatic_moderation, passwordreset)
* @return bool
*/
public function availableIn( $area )
public function availableIn( string $area ): bool
{
return \in_array( $area, array( 'bulkmail', 'group_promotions' ) );
return in_array( $area, array( 'bulkmail', 'group_promotions' ) );
}
/**
* Get Setting Field
*
* @param mixed $criteria Value returned from the save() method
* @param array $criteria Value returned from the save() method
* @return array Array of form elements
*/
public function getSettingField( $criteria )
public function getSettingField( array $criteria ): array
{
$options = array( 'any' => 'any', 'yes' => 'yes', 'no' => 'no' );
return array(
new \IPS\Helpers\Form\Radio( 'mf_has_blog', isset( $criteria['has_blog'] ) ? $criteria['has_blog'] : 'any', FALSE, array( 'options' => $options ) ),
new Radio( 'mf_has_blog', $criteria['has_blog'] ?? 'any', FALSE, array( 'options' => $options ) ),
);
}
/**
* Save the filter data
*
* @param array $post Form values
* @return mixed False, or an array of data to use later when filtering the members
* @throws \LogicException
* @param array $post Form values
* @return bool|array False, or an array of data to use later when filtering the members
* @throws LogicException
*/
public function save( $post )
public function save( array $post ): bool|array
{
if( isset( $post['mf_has_blog'] ) and \in_array( $post['mf_has_blog'], array( 'yes', 'no' ) ) )
if( isset( $post['mf_has_blog'] ) and in_array( $post['mf_has_blog'], array( 'yes', 'no' ) ) )
{
return array( 'has_blog' => $post['mf_has_blog'] );
}
@@ -69,10 +79,10 @@ class _Blog
/**
* Get where clause to add to the member retrieval database query
*
* @param mixed $data The array returned from the save() method
* @param array $data The array returned from the save() method
* @return array|NULL Where clause - must be a single array( "clause" )
*/
public function getQueryWhereClause( $data )
public function getQueryWhereClause( array $data ): ?array
{
if( isset( $data['has_blog'] ) )
{
@@ -86,29 +96,28 @@ class _Blog
* Callback for member retrieval database query
* Can be used to set joins
*
* @param mixed $data The array returned from the save() method
* @param \IPS\Db\Query $query The query
* @return void
* @param array $data The array returned from the save() method
* @param Select $query The query
* @return void
*/
public function queryCallback( $data, &$query )
public function queryCallback( array $data, Select $query ) : void
{
if( isset( $data['has_blog'] ) )
{
$query->join( 'blog_blogs', "core_members.member_id=blog_blogs.blog_member_id" );
}
return NULL;
}
/**
* Determine if a member matches specified filters
*
* @param Member $member
* @param array $filters
* @param object|null $object
* @note This is only necessary if availableIn() includes group_promotions
* @param \IPS\Member $member Member object to check
* @param array $filters Previously defined filters
* @return bool
*/
public function matches( \IPS\Member $member, $filters )
public function matches( Member $member, array $filters, ?object $object = NULL ): bool
{
/* If we aren't filtering by this, then any member matches */
if( !isset( $filters['has_blog'] ) OR !$filters['has_blog'] )
@@ -116,7 +125,7 @@ class _Blog
return TRUE;
}
$result = (bool) \IPS\Db::i()->select( 'COUNT(*)', 'blog_blogs', array( 'blog_member_id=?', $member->member_id ) )->first();
$result = (bool) Db::i()->select( 'COUNT(*)', 'blog_blogs', array( 'blog_member_id=?', $member->member_id ) )->first();
return ( $filters['has_blog'] == 'no' ) ? !$result : $result;
}
@@ -1,95 +0,0 @@
<?php
/**
* @brief Member Sync
* @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 Blog
* @since 20 Mar 2014
*/
namespace IPS\blog\extensions\core\MemberSync;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Member Sync
*/
class _Blog
{
/**
* Member is merged with another member
*
* @param \IPS\Member $member Member being kept
* @param \IPS\Member $member2 Member being removed
* @return void
*/
public function onMerge( $member, $member2 )
{
\IPS\Db::i()->update( 'blog_blogs', array( 'blog_member_id' => $member->member_id ), array( 'blog_member_id=?', $member2->member_id ) );
foreach( \IPS\blog\Blog::loadByOwner( $member2 ) as $blog )
{
/* Only do this if the blog is not a group blog */
if ( !$blog->groupblog_ids )
{
$blog->member_id = $member->member_id;
$blog->save();
}
}
}
/**
* Member is deleted
*
* @param $member \IPS\Member The member
* @return void
*/
public function onDelete( $member )
{
foreach( \IPS\blog\Blog::loadByOwner( $member ) as $blog )
{
/* We only want to do this if the blog is owned by the member - loadByOwner() also returns Blogs that are assigned to member groups */
if ( !$blog->groupblog_ids )
{
/* Delete blog entries & blog */
\IPS\Task::queue( 'core', 'DeleteOrMoveContent', array( 'class' => 'IPS\blog\Blog', 'id' => $blog->id, 'deleteWhenDone' => TRUE ) );
}
}
}
/**
* Member is flagged as spammer
*
* @param $member \IPS\Member The member
* @return void
*/
public function onSetAsSpammer( $member )
{
$actions = explode( ',', \IPS\Settings::i()->spm_option );
/* Hide or delete */
if ( \in_array( 'unapprove', $actions ) or \in_array( 'delete', $actions ) )
{
foreach( \IPS\blog\Blog::loadByOwner( $member ) as $blog )
{
if( !$blog->groupblog_ids )
{
$blog->disabled = TRUE;
$blog->save();
if( \in_array( 'delete', $actions ) )
{
\IPS\Task::queue( 'core', 'DeleteOrMoveContent', array( 'class' => 'IPS\blog\Blog', 'id' => $blog->id, 'deleteWhenDone' => TRUE ), 3 );
}
}
}
}
}
}
@@ -12,16 +12,20 @@
namespace IPS\blog\extensions\core\ModeratorPermissions;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use IPS\Extensions\ModeratorPermissionsAbstract;
use function defined;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Moderator Permissions
*/
class _Blogs
class Blogs extends ModeratorPermissionsAbstract
{
/**
* Get Permissions
@@ -38,33 +42,11 @@ class _Blogs
...
);
* @endcode
* @param array $toggles
* @return array
*/
public function getPermissions()
public function getPermissions( array $toggles ): array
{
return array( 'can_mod_blogs' => 'YesNo' );
}
/**
* After change
*
* @param array $moderator The moderator
* @param array $changed Values that were changed
* @return void
*/
public function onChange( $moderator, $changed )
{
}
/**
* After delete
*
* @param array $moderator The moderator
* @return void
*/
public function onDelete( $moderator )
{
}
}
@@ -12,21 +12,28 @@
namespace IPS\blog\extensions\core\OverviewStatistics;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use IPS\Db;
use IPS\Extensions\OverviewStatisticsAbstract;
use IPS\Member;
use IPS\Theme;
use function defined;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* @brief Overview statistics extension: Blogs
*/
class _Blogs
class Blogs extends OverviewStatisticsAbstract
{
/**
* @brief Which statistics page (activity or user)
*/
public $page = 'activity';
public string $page = 'activity';
/**
* Return the sub-block keys
@@ -34,7 +41,7 @@ class _Blogs
* @note This is designed to allow one class to support multiple blocks, for instance using the ContentRouter to generate blocks.
* @return array
*/
public function getBlocks()
public function getBlocks(): array
{
return array( 'blogs' );
}
@@ -42,26 +49,26 @@ class _Blogs
/**
* Return block details (title and description)
*
* @param string|NULL $subBlock The subblock we are loading as returned by getBlocks()
* @param string|null $subBlock The subblock we are loading as returned by getBlocks()
* @return array
*/
public function getBlockDetails( $subBlock = NULL )
public function getBlockDetails( string $subBlock = NULL ): array
{
/* Description can be null and will not be shown if so */
return array( 'app' => 'blog', 'title' => 'stats_overview_blogs', 'description' => \IPS\Member::loggedIn()->language()->addToStack( 'stats_overview_blogs_desc' ), 'refresh' => 120 );
return array( 'app' => 'blog', 'title' => 'stats_overview_blogs', 'description' => Member::loggedIn()->language()->addToStack( 'stats_overview_blogs_desc' ), 'refresh' => 120 );
}
/**
* Return the block HTML to show
*
* @param array|NULL $dateRange NULL for all time, or an array with 'start' and 'end' \IPS\DateTime objects to restrict to
* @param string|NULL $subBlock The subblock we are loading as returned by getBlocks()
* @param array|string|null $dateRange NULL for all time, or an array with 'start' and 'end' \IPS\DateTime objects to restrict to
* @param string|null $subBlock The subblock we are loading as returned by getBlocks()
* @return string
*/
public function getBlock( $dateRange = NULL, $subBlock = NULL )
public function getBlock( array|string|null $dateRange = NULL, string $subBlock = NULL ): string
{
$total = \IPS\Db::i()->select( 'COUNT(*)', 'blog_blogs' )->first();
$total = Db::i()->select( 'COUNT(*)', 'blog_blogs' )->first();
return \IPS\Theme::i()->getTemplate( 'stats' )->overviewComparisonCount( $total, NULL, NULL );
return Theme::i()->getTemplate( 'stats' )->overviewComparisonCount( $total, NULL, NULL );
}
}
@@ -12,55 +12,47 @@
namespace IPS\blog\extensions\core\Profile;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use IPS\blog\Blog\ProfileTable;
use IPS\Db;
use IPS\Extensions\ProfileAbstract;
use IPS\Member;
use IPS\Theme;
use function defined;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* @brief Profile extension: Blogs
*/
class _Blog
class Blog extends ProfileAbstract
{
/**
* Member
*/
protected $member;
/**
* Constructor
*
* @param \IPS\Member $member Member whose profile we are viewing
* @return void
*/
public function __construct( \IPS\Member $member )
{
$this->member = $member;
}
/**
* Is there content to display?
*
* @return bool
*/
public function showTab()
public function showTab(): bool
{
$where = array(
array( '(' . \IPS\Db::i()->findInSet( 'blog_groupblog_ids', $this->member->groups ) . ' OR ' . 'blog_member_id=? )', $this->member->member_id ),
array( '(' . Db::i()->findInSet( 'blog_groupblog_ids', $this->member->groups ) . ' OR ' . 'blog_member_id=? )', $this->member->member_id ),
array( 'blog_disabled=0' )
);
if ( \IPS\Member::loggedIn()->member_id )
if ( Member::loggedIn()->member_id )
{
$where[] = array( '( blog_social_group IS NULL OR blog_member_id=? OR blog_social_group IN(?) )', \IPS\Member::loggedIn()->member_id, \IPS\Db::i()->select( 'group_id', 'core_sys_social_group_members', array( 'member_id=?', \IPS\Member::loggedIn()->member_id ) ) );
$where[] = array( '( blog_social_group IS NULL OR blog_member_id=? OR blog_social_group IN(?) )', Member::loggedIn()->member_id, Db::i()->select( 'group_id', 'core_sys_social_group_members', array( 'member_id=?', Member::loggedIn()->member_id ) ) );
}
else
{
$where[] = array( 'blog_social_group IS NULL' );
}
return (bool) \IPS\Db::i()->select( 'COUNT(*)', 'blog_blogs', $where )->first();
return (bool) Db::i()->select( 'COUNT(*)', 'blog_blogs', $where )->first();
}
/**
@@ -68,14 +60,12 @@ class _Blog
*
* @return string
*/
public function render()
public function render(): string
{
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'profile.css', 'blog', 'front' ) );
$table = new \IPS\blog\Blog\ProfileTable( $this->member->url() );
$table = new ProfileTable( $this->member->url() );
$table->setOwner( $this->member );
$table->tableTemplate = array( \IPS\Theme::i()->getTemplate( 'global', 'blog' ), 'profileBlogTable' );
$table->rowsTemplate = array( \IPS\Theme::i()->getTemplate( 'global', 'blog' ), 'profileBlogRows' );
$table->tableTemplate = array( Theme::i()->getTemplate( 'global', 'blog' ), 'profileBlogTable' );
$table->rowsTemplate = array( Theme::i()->getTemplate( 'global', 'blog' ), 'profileBlogRows' );
return (string) $table;
}
@@ -1,130 +0,0 @@
<?php
/**
* @brief Background Task
* @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 Blogs
* @since 12 Apr 2016
*/
namespace IPS\blog\extensions\core\Queue;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Background Task
*/
class _RebuildEntryImages
{
/**
* @brief Number of entry images to rebuild per cycle
*/
public $rebuild = \IPS\REBUILD_SLOW;
/**
* Parse data before queuing
*
* @param array $data
* @return array
*/
public function preQueueData( $data )
{
$data['count'] = (int) \IPS\Db::i()->select( 'count(*)', 'blog_entries', "entry_image<>''" )->first();
if( $data['count'] == 0 )
{
return NULL;
}
return $data;
}
/**
* Run Background Task
*
* @param mixed $data Data as it was passed to \IPS\Task::queue()
* @param int $offset Offset
* @return int New offset
* @throws \IPS\Task\Queue\OutOfRangeException Indicates offset doesn't exist and thus task is complete
*/
public function run( $data, $offset )
{
$select = \IPS\Db::i()->select( '*', 'blog_entries', array( "entry_image<>? AND entry_id > ?", '', $offset ), 'entry_id ASC', array( 0, $this->rebuild ) );
$last = NULL;
foreach ( $select as $entry )
{
try
{
$filePath = \IPS\ROOT_PATH . '/uploads/' . $entry['entry_image'];
if ( ! file_exists( $filePath ) )
{
continue;
}
/* Have we processed this before? It's a bit crude but it is accurate */
if ( mb_substr( trim( $entry['entry_content'] ), 0, 37 ) === '<a href="<fileStore.core_Attachment>/' and mb_stristr( $entry['entry_content'], '/' . $entry['entry_image'] . '.' ) and mb_stristr( $entry['entry_content'], 'data-fileid="' ) )
{
continue;
}
$file = \IPS\File::create( 'core_Attachment', $entry['entry_image'], NULL, NULL, FALSE, $filePath );
$attachment = $file->makeAttachment('', \IPS\Member::load( $entry['entry_author_id'] ) );
$fileName = htmlspecialchars( $attachment['attach_file'], ENT_DISALLOWED, 'UTF-8', TRUE );
$image = <<<IMAGE
<a href="<fileStore.core_Attachment>/{$file}" class="ipsAttachLink ipsAttachLink_image" style="float:left;"><img data-fileid="{$attachment['attach_id']}" src="<fileStore.core_Attachment>/{$file}" class="ipsImage ipsImage_thumbnailed" style="margin:10px;" alt="{$fileName}"></a>
IMAGE;
\IPS\Db::i()->update( 'blog_entries', array( 'entry_content' => $image . $entry['entry_content'] ), array( 'entry_id=?', $entry['entry_id'] ) );
$map = array(
'attachment_id' => $attachment['attach_id'],
'location_key' => 'blog_Entries',
'id1' => $entry['entry_id'],
'id2' => NULL,
'id3' => NULL,
'temp' => NULL,
);
\IPS\Db::i()->replace( 'core_attachments_map', $map );
}
catch ( \Exception $e ) {}
$last = $entry['entry_id'];
}
if( $last === NULL )
{
throw new \IPS\Task\Queue\OutOfRangeException;
}
return $last;
}
/**
* Get Progress
*
* @param mixed $data Data as it was passed to \IPS\Task::queue()
* @param int $offset Offset
* @return array( 'text' => 'Doing something...', 'complete' => 50 ) Text explaining task and percentage complete
* @throws \OutOfRangeException Indicates offset doesn't exist and thus task is complete
*/
public function getProgress( $data, $offset )
{
return array(
'text' => \IPS\Member::loggedIn()->language()->addToStack( 'rebuilding_blog_entry_images', FALSE ),
'complete' => ( isset( $data['count'] ) AND $data['count'] )
? ( round( 100 / $data['count'] * $offset, 2 ) )
: 100
);
}
}
@@ -12,23 +12,28 @@
namespace IPS\blog\extensions\core\RssImport;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use IPS\Content;
use IPS\Content\Search\Index;
use IPS\core\Rss\Import;
use IPS\Extensions\RssImportAbstract;
use IPS\Helpers\Form;
use IPS\Member;
use IPS\Node\Model;
use function defined;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* @brief RSS Import extension: RssImport
*/
class _RssImport
class RssImport extends RssImportAbstract
{
/**
* @brief RSSImport Class
*/
public $classes = array();
public $fileStorage = 'blog_Blogs';
public string $fileStorage = 'blog_Blogs';
/**
* Constructor
@@ -45,7 +50,7 @@ class _RssImport
*
* @return array
*/
public function availableOptions()
public function availableOptions(): array
{
/* We don't want to set up Blog feeds in the ACP */
return array();
@@ -54,10 +59,9 @@ class _RssImport
/**
* Show in the Admin CP?
*
* @param Object $class The class to check
* @return boolean
*/
public function showInAdminCp( $class ): bool
public function showInAdminCp(): bool
{
return false;
}
@@ -65,26 +69,26 @@ class _RssImport
/**
* Node selector options
*
* @param \IPS\core\Rss\Import|null $rss Existing RSS object if editing|NULL if not
* @param Import|null $rss Existing RSS object if editing|null if not
* @return array
*/
public function nodeSelectorOptions( $rss )
public function nodeSelectorOptions( ?Import $rss ): array
{
return array( 'class' => 'IPS\blog\Blog', 'permissionCheck' => 'view' );
}
/**
* @param \IPS\core\Rss\Import $rss RSS object
* @param array $article RSS feed article importing
* @param \IPS\Node\Model $container Container object
* @param string $content Post content with read more link if set
* @return \IPS\Content
* @param Import $rss RSS object
* @param array $article RSS feed article importing
* @param Model $container Container object
* @param string $content Post content with read more link if set
* @return Content
*/
public function create( \IPS\core\Rss\Import $rss, $article, \IPS\Node\Model $container, $content )
public function create( Import $rss, array $article, Model $container, string $content ): Content
{
$settings = $rss->settings;
$class = $rss->_class;
$member = \IPS\Member::load( $rss->member );
$member = Member::load( $rss->member );
$entry = $class::createItem( $member, NULL, $article['date'], $container );
$entry->name = $article['title'];
$entry->content = $content;
@@ -92,7 +96,7 @@ class _RssImport
$entry->save();
/* Add to search index */
\IPS\Content\Search\Index::i()->index( $entry );
Index::i()->index( $entry );
/* Send notifications */
$entry->sendNotifications();
@@ -105,11 +109,11 @@ class _RssImport
/**
* Addition Form elements
*
* @param \IPS\Helpers\Form $form The form
* @param \IPS\core\Rss\Import|null $rss Existing RSS object if editing|NULL if not
* @param Form $form The form
* @param Import|null $rss Existing RSS object if editing|null if not
* @return void
*/
public function form( &$form, $rss=NULL )
public function form( Form $form, ?Import $rss=NULL ): void
{
/* Blogs has it's own front end controller */
}
@@ -117,11 +121,11 @@ class _RssImport
/**
* Process additional fields unique to this extension
*
* @param array $values Values from form
* @param \IPS\core\Rss\Import $rss Existing RSS object
* @param array $values Values from form
* @param Import $rss Existing RSS object
* @return array
*/
public function saveForm( &$values, $rss )
public function saveForm( array &$values, Import $rss ): array
{
/* Blogs has it's own front end controller */
return array( $values );
@@ -0,0 +1,62 @@
<?php
/**
* @brief SearchContent extension: Entries
* @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 Blogs
* @since 10 Jul 2023
*/
namespace IPS\blog\extensions\core\SearchContent;
/* To prevent PHP errors (extending class does not exist) revealing path */
use IPS\blog\Entry;
use IPS\Content\Search\SearchContentAbstract;
use function defined;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* @brief SearchContent extension: Entries
*/
class Entries extends SearchContentAbstract
{
/**
* Return all searchable classes in your application,
* including comments and/or reviews
*
* @return array
*/
public static function supportedClasses() : array
{
return array(
Entry::class,
Entry\Comment::class
);
}
/**
* Search Index Permissions
*
* @return string Comma-delimited values or '*'
* @li Number indicates a group
* @li Number prepended by "m" indicates a member
* @li Number prepended by "s" indicates a social group
*/
public function searchIndexPermissions(): string
{
if( $this->object instanceof Entry AND $this->object->status == 'draft' )
{
return '0';
}
return parent::searchIndexPermissions();
}
}
+104
View File
@@ -0,0 +1,104 @@
<?php
/**
* @brief Member Listener
* @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}
* @since 22 May 2023
*/
namespace IPS\blog\listeners;
/* To prevent PHP errors (extending class does not exist) revealing path */
use IPS\blog\Blog as BlogClass;
use IPS\Db;
use IPS\Events\ListenerType\MemberListenerType;
use IPS\Member;
use IPS\Settings;
use IPS\Task;
use function defined;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Member Listener
*/
class Blog extends MemberListenerType
{
/**
* Member is merged with another member
*
* @param Member $member Member being kept
* @param Member $member2 Member being removed
* @return void
*/
public function onMerge( Member $member, Member $member2 ) : void
{
Db::i()->update( 'blog_blogs', array( 'blog_member_id' => $member->member_id ), array( 'blog_member_id=?', $member2->member_id ) );
foreach( BlogClass::loadByOwner( $member2 ) as $blog )
{
/* Only do this if the blog is not a group blog */
if ( !$blog->groupblog_ids )
{
$blog->member_id = $member->member_id;
$blog->save();
}
}
}
/**
* Member is deleted
*
* @param $member Member The member
* @return void
*/
public function onDelete( Member $member ) : void
{
foreach( BlogClass::loadByOwner( $member ) as $blog )
{
/* We only want to do this if the blog is owned by the member - loadByOwner() also returns Blogs that are assigned to member groups */
if ( !$blog->groupblog_ids )
{
/* Delete blog entries & blog */
Task::queue( 'core', 'DeleteOrMoveContent', array( 'class' => 'IPS\blog\Blog', 'id' => $blog->id, 'deleteWhenDone' => TRUE ) );
}
}
}
/**
* Member is flagged as spammer
*
* @param $member Member The member
* @return void
*/
public function onSetAsSpammer( Member $member ) : void
{
$actions = explode( ',', Settings::i()->spm_option );
/* Hide or delete */
if ( in_array( 'unapprove', $actions ) or in_array( 'delete', $actions ) )
{
foreach( BlogClass::loadByOwner( $member ) as $blog )
{
if( !$blog->groupblog_ids )
{
$blog->disabled = TRUE;
$blog->save();
if( in_array( 'delete', $actions ) )
{
Task::queue( 'core', 'DeleteOrMoveContent', array( 'class' => 'IPS\blog\Blog', 'id' => $blog->id, 'deleteWhenDone' => TRUE ), 3 );
}
}
}
}
}
}
+17 -10
View File
@@ -12,35 +12,42 @@
namespace IPS\blog\modules\admin\blogs;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use IPS\Dispatcher;
use IPS\Http\Url;
use IPS\Node\Controller;
use IPS\Output;
use function defined;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* groupBlogs
*/
class _blogs extends \IPS\Node\Controller
class blogs extends Controller
{
/**
* @brief Has been CSRF-protected
*/
public static $csrfProtected = TRUE;
public static bool $csrfProtected = TRUE;
/**
* Node Class
*/
protected $nodeClass = '\IPS\blog\Category';
protected string $nodeClass = '\IPS\blog\Category';
/**
* Execute
*
* @return void
*/
public function execute()
public function execute() : void
{
\IPS\Dispatcher::i()->checkAcpPermission( 'blogs_manage' );
Dispatcher::i()->checkAcpPermission( 'blogs_manage' );
parent::execute();
}
@@ -49,16 +56,16 @@ class _blogs extends \IPS\Node\Controller
*
* @return void
*/
protected function manage()
protected function manage() : void
{
parent::manage();
/* Root buttons */
\IPS\Output::i()->sidebar['actions']['add'] = array(
Output::i()->sidebar['actions']['add'] = array(
'primary' => true,
'icon' => 'plus',
'title' => 'blog_create_category',
'link' => \IPS\Http\Url::internal( 'app=blog&module=blogs&controller=blogs&do=form' ),
'link' => Url::internal( 'app=blog&module=blogs&controller=blogs&do=form' ),
'data' => array()
);
}
@@ -12,30 +12,42 @@
namespace IPS\blog\modules\admin\blogs;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use IPS\Dispatcher;
use IPS\Dispatcher\Controller;
use IPS\Helpers\Form;
use IPS\Helpers\Form\Radio;
use IPS\Helpers\Form\YesNo;
use IPS\Member;
use IPS\Output;
use IPS\Session;
use IPS\Settings as SettingsClass;
use function defined;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Blog settings
*/
class _settings extends \IPS\Dispatcher\Controller
class settings extends Controller
{
/**
* @brief Has been CSRF-protected
*/
public static $csrfProtected = TRUE;
public static bool $csrfProtected = TRUE;
/**
* Execute
*
* @return void
*/
public function execute()
public function execute() : void
{
\IPS\Dispatcher::i()->checkAcpPermission( 'settings_manage', 'blog' );
Dispatcher::i()->checkAcpPermission( 'settings_manage', 'blog' );
parent::execute();
}
@@ -44,33 +56,25 @@ class _settings extends \IPS\Dispatcher\Controller
*
* @return void
*/
protected function manage()
protected function manage() : void
{
$form = new \IPS\Helpers\Form;
$form->add( new \IPS\Helpers\Form\YesNo( 'blog_enable_rating', \IPS\Settings::i()->blog_enable_rating ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'blog_enable_sidebar', \IPS\Settings::i()->blog_enable_sidebar ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'blog_allow_grid', \IPS\Settings::i()->blog_allow_grid, FALSE, array( 'togglesOn' => array( 'blog_view_mode' ) ) ) );
$form->add( new \IPS\Helpers\Form\Radio( 'blog_view_mode', \IPS\Settings::i()->blog_view_mode, FALSE, array( 'options' => array(
'grid' => 'blog_view_mode_grid',
'list' => 'blog_view_mode_list'
) ), NULL, NULL, NULL, 'blog_view_mode' ) );
$form = new Form;
$form->add( new YesNo( 'blog_enable_rating', SettingsClass::i()->blog_enable_rating ) );
$form->add( new YesNo( 'blog_enable_sidebar', SettingsClass::i()->blog_enable_sidebar ) );
$form->addHeader('blog_settings_rss');
$form->add( new \IPS\Helpers\Form\YesNo( 'blog_allow_rssimport', \IPS\Settings::i()->blog_allow_rssimport ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'blog_allow_rss', \IPS\Settings::i()->blog_allow_rss ) );
$form->add( new YesNo( 'blog_allow_rssimport', SettingsClass::i()->blog_allow_rssimport ) );
$form->add( new YesNo( 'blog_allow_rss', SettingsClass::i()->blog_allow_rss ) );
if ( $form->values() )
{
$form->saveAsSettings();
/* Clear guest page caches */
\IPS\Data\Cache::i()->clearAll();
\IPS\Session::i()->log( 'acplogs__blog_settings' );
Session::i()->log( 'acplogs__blog_settings' );
}
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('settings');
\IPS\Output::i()->output = $form;
Output::i()->title = Member::loggedIn()->language()->addToStack('settings');
Output::i()->output = $form;
}
}
@@ -12,54 +12,61 @@
namespace IPS\blog\modules\front\blogs;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use DateInterval;
use IPS\blog\Blog;
use IPS\blog\Blog\Table;
use IPS\blog\Category;
use IPS\blog\Entry;
use IPS\Content\Filter;
use IPS\DateTime;
use IPS\Db;
use IPS\Dispatcher\Controller;
use IPS\Http\Url;
use IPS\Member;
use IPS\Output;
use IPS\Request;
use IPS\Session;
use IPS\Settings;
use IPS\Theme;
use OutOfRangeException;
use function count;
use function defined;
use function intval;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* browse
*/
class _browse extends \IPS\Dispatcher\Controller
class browse extends Controller
{
/**
* Manage
*
* @return void
*/
protected function manage()
protected function manage() : void
{
/* Category */
try
{
$category = \IPS\blog\Category::loadAndCheckPerms( \IPS\Request::i()->id );
$category = Category::loadAndCheckPerms( Request::i()->id );
}
catch ( \OutOfRangeException $e )
catch ( OutOfRangeException )
{
$category = NULL;
}
/* Featured stuff */
$featured = iterator_to_array( \IPS\blog\Entry::featured( 5, '_rand' ) );
$blogs = \IPS\blog\Blog::loadByOwner( \IPS\Member::loggedIn(), array( array( 'blog_disabled=?', 0 ) ) );
if ( ! \IPS\Settings::i()->blog_allow_grid )
{
$viewMode = 'list';
}
else
{
$viewMode = ( isset( \IPS\Request::i()->view ) ) ? \IPS\Request::i()->view : ( isset( \IPS\Request::i()->cookie['blog_view'] ) ? \IPS\Request::i()->cookie['blog_view'] : \IPS\Settings::i()->blog_view_mode );
}
if ( isset( \IPS\Request::i()->view ) )
{
\IPS\Session::i()->csrfCheck();
\IPS\Request::i()->setCookie( 'blog_view', \IPS\Request::i()->view, ( new \IPS\DateTime )->add( new \DateInterval( 'P1Y' ) ) );
$featured = iterator_to_array( Entry::featured( 5, '_rand' ) );
$blogs = Blog::loadByOwner( Member::loggedIn(), array( array( 'blog_disabled=?', 0 ) ) );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=blog', 'front', 'blogs' ) );
}
$viewMode = Member::loggedIn()->getLayoutValue( 'blog_view' );
/* Grid view */
if ( $viewMode == 'grid' )
@@ -67,9 +74,9 @@ class _browse extends \IPS\Dispatcher\Controller
$perpage = 23;
$page = 1;
if ( \IPS\Request::i()->page )
if ( Request::i()->page )
{
$page = \intval( \IPS\Request::i()->page );
$page = intval( Request::i()->page );
if ( !$page OR $page < 1 )
{
$page = 1;
@@ -80,7 +87,7 @@ class _browse extends \IPS\Dispatcher\Controller
$where = array();
$where[] = array( "blog_entries.entry_status!=?", 'draft' );
if ( !\IPS\Settings::i()->club_nodes_in_apps )
if ( !Settings::i()->club_nodes_in_apps )
{
$where[] = array( "blog_blogs.blog_club_id IS NULL" );
}
@@ -88,8 +95,8 @@ class _browse extends \IPS\Dispatcher\Controller
{
$where[] = array( 'blog_blogs.blog_category_id=?', $category->_id );
}
$count = \IPS\blog\Entry::getItemsWithPermission( $where, 'entry_date desc', NULL, 'read', \IPS\Content\Hideable::FILTER_AUTOMATIC, 0, NULL, TRUE, FALSE, FALSE, TRUE );
$entries = \IPS\blog\Entry::getItemsWithPermission( $where, 'entry_date desc', array( ( $perpage * ( $page - 1 ) ), $perpage ), 'read', \IPS\Content\Hideable::FILTER_AUTOMATIC, 0, NULL, TRUE );
$count = Entry::getItemsWithPermission( $where, 'entry_date desc', NULL, 'read', Filter::FILTER_AUTOMATIC, 0, NULL, TRUE, FALSE, FALSE, TRUE );
$entries = Entry::getItemsWithPermission( $where, 'entry_date desc', array( ( $perpage * ( $page - 1 ) ), $perpage ), 'read', Filter::FILTER_AUTOMATIC, 0, NULL, TRUE );
/* Validate Pagination */
$totalPages = ceil( $count / $perpage );
@@ -102,67 +109,68 @@ class _browse extends \IPS\Dispatcher\Controller
}
}
$queryString = 'app=blog&module=blogs&controller=browse';
$queryString = 'app=blog&module=blogs&controller=browse';
if( $category )
{
$queryString .= '&id=' . $category->_id;
}
$paginationUrl = \IPS\Http\Url::internal( $queryString, 'front', ( $category ) ? 'blog_category' : 'blogs' );
$paginationUrl = Url::internal( $queryString, 'front', ( $category ) ? 'blog_category' : 'blogs' );
if( $redirect )
{
\IPS\Output::i()->redirect( $paginationUrl->setPage('page', 1 ), NULL, 303 );
Output::i()->redirect( $paginationUrl->setPage('page', 1 ), NULL, 303 );
}
$pagination = array(
'page' => $page,
'pages' => $totalPages,
'perpage' => $perpage,
'url' => $paginationUrl
);
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'grid.css', 'blog', 'front' ) );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'browse' )->indexGrid( $entries, $featured, $blogs, $pagination, $viewMode, $category );
Output::i()->output = Theme::i()->getTemplate( 'browse' )->indexGrid( $entries, $featured, $blogs, $pagination, $viewMode, $category );
}
else
{
/* Blogs table */
$table = new \IPS\blog\Blog\Table( \IPS\Http\Url::internal( 'app=blog&module=blogs&controller=browse', 'front', 'blogs' ) );
$table = new Table( Url::internal( 'app=blog&module=blogs&controller=browse', 'front', 'blogs' ) );
if( $category )
{
$table->where[] = array( 'blog_category_id=?', $category->_id );
}
$table->title = 'our_community_blogs';
$table->classes = array( 'cBlogList', 'ipsAreaBackground', 'ipsDataList_large' );
$table->classes = array( 'cBlogList', 'ipsBlogData' );
/* Filters */
$table->filters = array(
'my_blogs' => array( '(' . \IPS\Db::i()->findInSet( 'blog_groupblog_ids', \IPS\Member::loggedIn()->groups ) . ' OR ' . 'blog_member_id=? )', \IPS\Member::loggedIn()->member_id ),
'my_blogs' => array( '(' . Db::i()->findInSet( 'blog_groupblog_ids', Member::loggedIn()->groups ) . ' OR ' . 'blog_member_id=? )', Member::loggedIn()->member_id ),
'blogs_with_content' => array( 'blog_count_entries>0' )
);
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'browse' )->index( $table, $featured, $blogs, $viewMode, $category );
Output::i()->output = Theme::i()->getTemplate( 'browse' )->index( $table, $featured, $blogs, $viewMode, $category );
}
\IPS\Session::i()->setLocation( \IPS\Http\Url::internal( 'app=blog', 'front', 'blogs' ), array(), 'loc_blog_viewing_index' );
Session::i()->setLocation( Url::internal( 'app=blog', 'front', 'blogs' ), array(), 'loc_blog_viewing_index' );
/* Display */
if( \count( \IPS\blog\Category::roots() ) > 1 )
if( count( Category::roots() ) > 1 )
{
\IPS\Output::i()->sidebar['contextual'] = \IPS\Theme::i()->getTemplate( 'browse' )->categories( $category );
Output::i()->sidebar['contextual'] = Theme::i()->getTemplate( 'browse' )->categories( $category );
}
if( $category )
{
foreach( $category->parents() as $parent )
{
\IPS\Output::i()->breadcrumb[] = array( $parent->url(), $parent->_title );
Output::i()->breadcrumb[] = array( $parent->url(), $parent->_title );
}
\IPS\Output::i()->breadcrumb[] = array( $category->url(), $category->_title );
Output::i()->breadcrumb[] = array( $category->url(), $category->_title );
/* Set default search option */
\IPS\Output::i()->defaultSearchOption = array( 'blog_entry', 'blog_entry_pl' );
Output::i()->defaultSearchOption = array( 'blog_entry', 'blog_entry_pl' );
}
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'front_browse.js', 'blog', 'front' ) );
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('blogs');
Output::i()->jsFiles = array_merge( Output::i()->jsFiles, Output::i()->js( 'front_browse.js', 'blog', 'front' ) );
Output::i()->title = Member::loggedIn()->language()->addToStack('blogs');
}
}
@@ -12,23 +12,35 @@
namespace IPS\blog\modules\front\blogs;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use IPS\blog\Blog;
use IPS\Dispatcher\Controller;
use IPS\Helpers\Form;
use IPS\Http\Url;
use IPS\Member;
use IPS\Output;
use IPS\Request;
use IPS\Session;
use IPS\Theme;
use function defined;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Create Blog
*/
class _create extends \IPS\Dispatcher\Controller
class create extends Controller
{
/**
* Execute
*
* @return void
*/
public function execute()
public function execute() : void
{
parent::execute();
}
@@ -38,18 +50,18 @@ class _create extends \IPS\Dispatcher\Controller
*
* @return void
*/
protected function manage()
protected function manage() : void
{
if ( !\IPS\blog\Blog::canCreate() )
if ( !Blog::canCreate() )
{
\IPS\Output::i()->error( 'no_module_permission', '2B227/1', 403, '' );
Output::i()->error( 'no_module_permission', '2B227/1', 403, '' );
}
$form = new \IPS\Helpers\Form( 'select_blog', 'continue' );
$form->class = 'ipsForm_vertical';
$form = new Form( 'select_blog', 'continue' );
$form->class = 'ipsForm--vertical ipsForm--create-blog';
$blog = new \IPS\blog\Blog;
$blog->member_id = \IPS\Member::loggedIn()->member_id;
$blog = new Blog;
$blog->member_id = Member::loggedIn()->member_id;
$blog->form( $form, TRUE );
if ( $values = $form->values() )
@@ -57,21 +69,21 @@ class _create extends \IPS\Dispatcher\Controller
$blog->saveForm( $blog->formatFormValues( $values ) );
/* Redirect */
\IPS\Output::i()->redirect( $blog->url() );
Output::i()->redirect( $blog->url() );
}
\IPS\Session::i()->setLocation( \IPS\Http\Url::internal( 'app=blog', 'front', 'blogs' ), array(), 'loc_blog_creating' );
Session::i()->setLocation( Url::internal( 'app=blog', 'front', 'blogs' ), array(), 'loc_blog_creating' );
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'front_view.js', 'blog', 'front' ) );
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('create_blog');
Output::i()->jsFiles = array_merge( Output::i()->jsFiles, Output::i()->js( 'front_view.js', 'blog', 'front' ) );
Output::i()->title = Member::loggedIn()->language()->addToStack('create_blog');
if( \IPS\Request::i()->isAjax() )
if( Request::i()->isAjax() )
{
\IPS\Output::i()->output = $form->customTemplate( array( \IPS\Theme::i()->getTemplate( 'forms', 'core' ), 'popupTemplate' ) );
Output::i()->output = $form->customTemplate( array( Theme::i()->getTemplate( 'forms', 'core' ), 'popupTemplate' ) );
}
else
{
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'submit' )->createBlog( $form );
Output::i()->output = Theme::i()->getTemplate( 'submit' )->createBlog( $form );
}
}
}
+148 -109
View File
@@ -12,52 +12,93 @@
namespace IPS\blog\modules\front\blogs;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use DomainException;
use Exception;
use InvalidArgumentException;
use IPS\blog\Blog;
use IPS\blog\Entry as EntryClass;
use IPS\blog\Entry\Category;
use IPS\Content\Controller;
use IPS\Content\ReadMarkers;
use IPS\core\FrontNavigation;
use IPS\DateTime;
use IPS\Db;
use IPS\File;
use IPS\Helpers\Form;
use IPS\Helpers\Form\Node;
use IPS\Helpers\Form\Radio;
use IPS\Helpers\Form\Select;
use IPS\Helpers\Form\Text;
use IPS\Helpers\Wizard;
use IPS\Http\Url;
use IPS\Http\Url\Friendly;
use IPS\IPS;
use IPS\Member;
use IPS\Output;
use IPS\Request;
use IPS\Session;
use IPS\Settings;
use IPS\Theme;
use OutOfBoundsException;
use OutOfRangeException;
use RuntimeException;
use UnderflowException;
use function count;
use function defined;
use function get_class;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* View Blog Entry Controller
*/
class _entry extends \IPS\Content\Controller
class entry extends Controller
{
/**
* [Content\Controller] Class
*/
protected static $contentModel = 'IPS\blog\Entry';
protected static string $contentModel = 'IPS\blog\Entry';
/**
* Entry object
*/
protected ?EntryClass $entry = NULL;
/**
* Execute
*
* @return void
*/
public function execute()
public function execute() : void
{
try
{
$this->entry = \IPS\blog\Entry::load( \IPS\Request::i()->id );
$this->entry = EntryClass::load( Request::i()->id );
if ( !$this->entry->canView( \IPS\Member::loggedIn() ) )
if ( !$this->entry->canView( Member::loggedIn() ) )
{
\IPS\Output::i()->error( 'node_error', '2B202/1', 403, '' );
Output::i()->error( 'node_error', '2B202/1', 403, '' );
}
if( $this->entry->cover_photo )
{
\IPS\Output::i()->metaTags['og:image'] = \IPS\File::get( 'blog_Entries', $this->entry->cover_photo )->url;
Output::i()->metaTags['og:image'] = File::get( 'blog_Entries', $this->entry->cover_photo )->url;
}
elseif ( $this->entry->container()->cover_photo )
{
\IPS\Output::i()->metaTags['og:image'] = \IPS\File::get( 'blog_Blogs', $this->entry->container()->cover_photo )->url;
Output::i()->metaTags['og:image'] = File::get( 'blog_Blogs', $this->entry->container()->cover_photo )->url;
}
}
catch ( \OutOfRangeException $e )
catch ( OutOfRangeException )
{
if ( !isset( \IPS\Request::i()->do ) or \IPS\Request::i()->do !== 'embed' )
if ( !isset( Request::i()->do ) or Request::i()->do !== 'embed' )
{
\IPS\Output::i()->error( 'node_error', '2B202/2', 404, '' );
Output::i()->error( 'node_error', '2B202/2', 404, '' );
}
}
@@ -67,9 +108,9 @@ class _entry extends \IPS\Content\Controller
/**
* Manage
*
* @return void
* @return mixed
*/
protected function manage()
protected function manage() : mixed
{
parent::manage();
@@ -81,7 +122,7 @@ class _entry extends \IPS\Content\Controller
/* Prev */
try
{
$previous = \IPS\Db::i()->select(
$previous = Db::i()->select(
'*',
'blog_entries',
array( 'entry_blog_id=? AND entry_date<? AND entry_status=? AND entry_is_future_entry=0 AND entry_hidden=?', $this->entry->blog_id, $this->entry->date, "published", 1 ),
@@ -89,14 +130,14 @@ class _entry extends \IPS\Content\Controller
,1
)->first();
$previous = \IPS\blog\Entry::constructFromData( $previous );
$previous = EntryClass::constructFromData( $previous );
}
catch ( \UnderflowException $e ) {}
catch ( UnderflowException ) {}
/* Next */
try
{
$next = \IPS\Db::i()->select(
$next = Db::i()->select(
'*',
'blog_entries',
array( 'entry_blog_id=? AND entry_date>? AND entry_status=? AND entry_is_future_entry=0 AND entry_hidden=?', $this->entry->blog_id, $this->entry->date, "published", 1 ),
@@ -104,49 +145,49 @@ class _entry extends \IPS\Content\Controller
,1
)->first();
$next = \IPS\blog\Entry::constructFromData( $next );
$next = EntryClass::constructFromData( $next );
}
catch ( \UnderflowException $e ) {}
catch ( UnderflowException ) {}
/* Online User Location */
if( !$this->entry->container()->social_group )
{
\IPS\Session::i()->setLocation( $this->entry->url(), $this->entry->onlineListPermissions(), 'loc_blog_viewing_entry', array( $this->entry->name => FALSE ) );
Session::i()->setLocation( $this->entry->url(), $this->entry->onlineListPermissions(), 'loc_blog_viewing_entry', array( $this->entry->name => FALSE ) );
}
/* Add JSON-ld output */
\IPS\Output::i()->jsonLd['blog'] = array(
'@context' => "http://schema.org",
Output::i()->jsonLd['blog'] = array(
'@context' => "https://schema.org",
'@type' => "Blog",
'url' => (string) $this->entry->container()->url(),
'name' => $this->entry->container()->_title,
'description' => \IPS\Member::loggedIn()->language()->addToStack( \IPS\blog\Blog::$titleLangPrefix . $this->entry->container()->_id . \IPS\blog\Blog::$descriptionLangSuffix, TRUE, array( 'striptags' => TRUE, 'escape' => TRUE ) ),
'description' => Member::loggedIn()->language()->addToStack( Blog::$titleLangPrefix . $this->entry->container()->_id . Blog::$descriptionLangSuffix, TRUE, array( 'striptags' => TRUE, 'escape' => TRUE ) ),
'commentCount' => $this->entry->container()->_comments,
'interactionStatistic' => array(
array(
'@type' => 'InteractionCounter',
'interactionType' => "http://schema.org/ViewAction",
'interactionType' => "https://schema.org/ViewAction",
'userInteractionCount' => $this->entry->container()->num_views
),
array(
'@type' => 'InteractionCounter',
'interactionType' => "http://schema.org/FollowAction",
'userInteractionCount' => \IPS\blog\Entry::containerFollowerCount( $this->entry->container() )
'interactionType' => "https://schema.org/FollowAction",
'userInteractionCount' => EntryClass::containerFollowerCount( $this->entry->container() )
),
array(
'@type' => 'InteractionCounter',
'interactionType' => "http://schema.org/CommentAction",
'interactionType' => "https://schema.org/CommentAction",
'userInteractionCount' => $this->entry->container()->_comments
),
array(
'@type' => 'InteractionCounter',
'interactionType' => "http://schema.org/WriteAction",
'interactionType' => "https://schema.org/WriteAction",
'userInteractionCount' => $this->entry->container()->_items
)
),
'blogPost' => array(
'@context' => "http://schema.org",
'@context' => "https://schema.org",
'@type' => "BlogPosting",
'url' => (string) $this->entry->url(),
'mainEntityOfPage' => (string) $this->entry->url(),
@@ -154,37 +195,37 @@ class _entry extends \IPS\Content\Controller
'headline' => $this->entry->mapped('title'),
'articleBody' => $this->entry->truncated( TRUE, NULL ),
'commentCount' => $this->entry->mapped('num_comments'),
'dateCreated' => \IPS\DateTime::ts( $this->entry->date )->format( \IPS\DateTime::ISO8601 ),
'datePublished' => \IPS\DateTime::ts( $this->entry->publish_date )->format( \IPS\DateTime::ISO8601 ),
'dateCreated' => DateTime::ts( $this->entry->date )->format( DateTime::ATOM ),
'datePublished' => DateTime::ts( $this->entry->publish_date )->format( DateTime::ATOM ),
'author' => array(
'@type' => 'Person',
'name' => \IPS\Member::load( $this->entry->mapped('author') )->name,
'url' => (string) \IPS\Member::load( $this->entry->mapped('author') )->url(),
'image' => \IPS\Member::load( $this->entry->mapped('author') )->get_photo( TRUE, TRUE )
'name' => Member::load( $this->entry->mapped('author') )->name,
'url' => (string) Member::load( $this->entry->mapped('author') )->url(),
'image' => Member::load( $this->entry->mapped('author') )->get_photo( TRUE, TRUE )
),
'publisher' => array(
'@id' => \IPS\Settings::i()->base_url . '#organization',
'@id' => Settings::i()->base_url . '#organization',
'member' => array(
'@type' => 'Person',
'name' => \IPS\Member::load( $this->entry->mapped('author') )->name,
'url' => (string) \IPS\Member::load( $this->entry->mapped('author') )->url(),
'image' => \IPS\Member::load( $this->entry->mapped('author') )->get_photo( TRUE, TRUE )
'name' => Member::load( $this->entry->mapped('author') )->name,
'url' => (string) Member::load( $this->entry->mapped('author') )->url(),
'image' => Member::load( $this->entry->mapped('author') )->get_photo( TRUE, TRUE )
)
),
'interactionStatistic' => array(
array(
'@type' => 'InteractionCounter',
'interactionType' => "http://schema.org/ViewAction",
'interactionType' => "https://schema.org/ViewAction",
'userInteractionCount' => $this->entry->views
),
array(
'@type' => 'InteractionCounter',
'interactionType' => "http://schema.org/FollowAction",
'userInteractionCount' => \IPS\blog\Entry::containerFollowerCount( $this->entry->container() )
'interactionType' => "https://schema.org/FollowAction",
'userInteractionCount' => EntryClass::containerFollowerCount( $this->entry->container() )
),
array(
'@type' => 'InteractionCounter',
'interactionType' => "http://schema.org/CommentAction",
'interactionType' => "https://schema.org/CommentAction",
'userInteractionCount' => $this->entry->mapped('num_comments')
)
)
@@ -193,32 +234,32 @@ class _entry extends \IPS\Content\Controller
if( $this->entry->container()->coverPhoto()->file )
{
\IPS\Output::i()->jsonLd['blog']['image'] = (string) $this->entry->container()->coverPhoto()->file->url;
Output::i()->jsonLd['blog']['image'] = (string) $this->entry->container()->coverPhoto()->file->url;
}
if( $this->entry->container()->member_id )
{
\IPS\Output::i()->jsonLd['blog']['author'] = array(
Output::i()->jsonLd['blog']['author'] = array(
'@type' => 'Person',
'name' => \IPS\Member::load( $this->entry->container()->member_id )->name,
'url' => (string) \IPS\Member::load( $this->entry->container()->member_id )->url(),
'image' => \IPS\Member::load( $this->entry->container()->member_id )->get_photo( TRUE, TRUE )
'name' => Member::load( $this->entry->container()->member_id )->name,
'url' => (string) Member::load( $this->entry->container()->member_id )->url(),
'image' => Member::load( $this->entry->container()->member_id )->get_photo( TRUE, TRUE )
);
}
if( $this->entry->edit_time )
{
\IPS\Output::i()->jsonLd['blog']['blogPost']['dateModified'] = \IPS\DateTime::ts( $this->entry->edit_time )->format( \IPS\DateTime::ISO8601 );
Output::i()->jsonLd['blog']['blogPost']['dateModified'] = DateTime::ts( $this->entry->edit_time )->format( DateTime::ATOM );
}
else
{
\IPS\Output::i()->jsonLd['blog']['blogPost']['dateModified'] = \IPS\DateTime::ts( $this->entry->publish_date ?: $this->entry->date )->format( \IPS\DateTime::ISO8601 );
Output::i()->jsonLd['blog']['blogPost']['dateModified'] = DateTime::ts( $this->entry->publish_date ?: $this->entry->date )->format( DateTime::ATOM );
}
$file = NULL;
if( $this->entry->image )
{
$file = \IPS\File::get( 'blog_Blogs', $this->entry->image );
$file = File::get( 'blog_Blogs', $this->entry->image );
}
elseif( $this->entry->coverPhoto()->file )
{
@@ -235,39 +276,36 @@ class _entry extends \IPS\Content\Controller
{
$dimensions = $file->getImageDimensions();
\IPS\Output::i()->jsonLd['blog']['blogPost']['image'] = array(
Output::i()->jsonLd['blog']['blogPost']['image'] = array(
'@type' => 'ImageObject',
'url' => (string) $file->url,
'width' => $dimensions[0],
'height' => $dimensions[1]
);
}
/* File does not exist */
catch( \RuntimeException $e ) {}
/* Image is invalid */
catch( \InvalidArgumentException $e ){}
catch( \DomainException $e ) {}
/* File does not exist or image is invalid */
catch( RuntimeException | InvalidArgumentException | DomainException ){}
}
/* Display */
if( \IPS\Settings::i()->blog_enable_sidebar and $this->entry->container()->sidebar )
if( Settings::i()->blog_enable_sidebar and $this->entry->container()->sidebar )
{
\IPS\Output::i()->sidebar['contextual'] = \IPS\Theme::i()->getTemplate('view')->blogSidebar( $this->entry->container()->sidebar );
Output::i()->sidebar['contextual'] = Theme::i()->getTemplate('view')->blogSidebar( $this->entry->container()->sidebar );
}
/* Breadcrumb */
\IPS\Output::i()->breadcrumb = array();
Output::i()->breadcrumb = array();
if ( $club = $this->entry->container()->club() )
{
\IPS\core\FrontNavigation::$clubTabActive = TRUE;
\IPS\Output::i()->breadcrumb = array();
\IPS\Output::i()->breadcrumb[] = array( \IPS\Http\Url::internal( 'app=core&module=clubs&controller=directory', 'front', 'clubs_list' ), \IPS\Member::loggedIn()->language()->addToStack('module__core_clubs') );
\IPS\Output::i()->breadcrumb[] = array( $club->url(), $club->name );
FrontNavigation::$clubTabActive = TRUE;
Output::i()->breadcrumb = array();
Output::i()->breadcrumb[] = array( Url::internal( 'app=core&module=clubs&controller=directory', 'front', 'clubs_list' ), Member::loggedIn()->language()->addToStack('module__core_clubs') );
Output::i()->breadcrumb[] = array( $club->url(), $club->name );
}
else
{
\IPS\Output::i()->breadcrumb['module'] = array( \IPS\Http\Url::internal( 'app=blog', 'front', 'blogs' ), \IPS\Member::loggedIn()->language()->addToStack( '__app_blog' ) );
Output::i()->breadcrumb['module'] = array( Url::internal( 'app=blog', 'front', 'blogs' ), Member::loggedIn()->language()->addToStack( '__app_blog' ) );
}
@@ -275,30 +313,31 @@ class _entry extends \IPS\Content\Controller
{
foreach( $this->entry->container()->category()->parents() as $parent )
{
\IPS\Output::i()->breadcrumb[] = array( $parent->url(), $parent->_title );
Output::i()->breadcrumb[] = array( $parent->url(), $parent->_title );
}
\IPS\Output::i()->breadcrumb[] = array( $this->entry->container()->category()->url(), $this->entry->container()->category()->_title );
Output::i()->breadcrumb[] = array( $this->entry->container()->category()->url(), $this->entry->container()->category()->_title );
}
catch ( \OutOfRangeException $e ) {}
catch ( OutOfRangeException ) {}
/* Set default search option */
\IPS\Output::i()->defaultSearchOption = array( 'blog_entry', 'blog_entry_pl' );
Output::i()->defaultSearchOption = array( 'blog_entry', 'blog_entry_pl' );
\IPS\Output::i()->breadcrumb[] = array( $this->entry->container()->url(), $this->entry->container()->_title );
\IPS\Output::i()->breadcrumb[] = array( NULL, $this->entry->name );
Output::i()->breadcrumb[] = array( $this->entry->container()->url(), $this->entry->container()->_title );
Output::i()->breadcrumb[] = array( NULL, $this->entry->name );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'view' )->entry( $this->entry, $previous, $next );
Output::i()->output = Theme::i()->getTemplate( 'view' )->entry( $this->entry, $previous, $next );
return null;
}
/**
* Return the form for editing. Abstracted so controllers can define a custom template if desired.
*
* @param \IPS\Helpers\Form $form The form
* @param Form $form The form
* @return string
*/
protected function getEditForm( $form )
protected function getEditForm( Form $form ): string
{
return $form->customTemplate( array( \IPS\Theme::i()->getTemplate( 'submit', 'blog' ), 'submitFormTemplate' ) );
return $form->customTemplate( array( Theme::i()->getTemplate( 'submit', 'blog' ), 'submitFormTemplate' ) );
}
/**
@@ -306,34 +345,34 @@ class _entry extends \IPS\Content\Controller
*
* @return void
*/
protected function move()
protected function move(): void
{
try
{
$item = \IPS\blog\Entry::loadAndCheckPerms( \IPS\Request::i()->id );
$item = EntryClass::loadAndCheckPerms( Request::i()->id );
if ( !$item->canMove() )
{
throw new \DomainException;
throw new DomainException;
}
$container = $item->container();
$wizard = new \IPS\Helpers\Wizard( array(
$wizard = new Wizard( array(
'blog' => function( $data ) use ( $container ) {
$data['item'] = \IPS\Request::i()->id;
$item = \IPS\blog\Entry::loadAndCheckPerms( $data['item'] );
$form = new \IPS\Helpers\Form;
$form->class = 'ipsForm_vertical';
$form->add( new \IPS\Helpers\Form\Node( 'move_to', NULL, TRUE, array(
'class' => \get_class( $item->container() ),
$data['item'] = Request::i()->id;
$item = EntryClass::loadAndCheckPerms( $data['item'] );
$form = new Form;
$form->class = 'ipsForm--vertical ipsForm--move-blog';
$form->add( new Node( 'move_to', NULL, TRUE, array(
'class' => get_class( $item->container() ),
'permissionCheck' => function( $node ) use ( $item )
{
try
{
/* If the item is in a club, only allow moving to other clubs that you moderate */
if ( \IPS\IPS::classUsesTrait( $item->container(), 'IPS\Content\ClubContainer' ) and $item->container()->club() )
if ( IPS::classUsesTrait( $item->container(), 'IPS\Content\ClubContainer' ) and $item->container()->club() )
{
return $item::modPermission( 'move', \IPS\Member::loggedIn(), $node ) and $node->can( 'add' ) ;
return $item::modPermission( 'move', Member::loggedIn(), $node ) and $node->can( 'add' ) ;
}
if ( $node->can( 'add' ) )
@@ -341,7 +380,7 @@ class _entry extends \IPS\Content\Controller
return true;
}
}
catch( \OutOfBoundsException $e ) { }
catch( OutOfBoundsException ) { }
return false;
},
@@ -357,27 +396,27 @@ class _entry extends \IPS\Content\Controller
return $form;
},
'category' => function( $data ) {
$item = \IPS\blog\Entry::loadAndCheckPerms( $data['item'] );
$item = EntryClass::loadAndCheckPerms( $data['item'] );
$newBlog = $data['blog'];
$form = new \IPS\Helpers\Form;
$form = new Form;
$categories = \IPS\blog\Entry\Category::roots( NULL, NULL, array( 'entry_category_blog_id=?', $newBlog->id ) );
$categories = Category::roots( NULL, NULL, array( 'entry_category_blog_id=?', $newBlog->id ) );
$choiceOptions = array( 0 => 'entry_category_choice_new' );
$choiceToggles = array( 0 => array( 'blog_entry_new_category' ) );
if( \count( $categories ) )
if( count( $categories ) )
{
$choiceOptions[1] = 'entry_category_choice_existing';
$choiceToggles[1] = array( 'entry_category_id' );
}
$form->add( new \IPS\Helpers\Form\Radio( 'entry_category_choice', 0, FALSE, array(
$form->add( new Radio( 'entry_category_choice', 0, FALSE, array(
'options' => $choiceOptions,
'toggles' => $choiceToggles
) ) );
if( \count( $categories ) )
if( count( $categories ) )
{
$options = array();
foreach ( $categories as $category )
@@ -385,20 +424,20 @@ class _entry extends \IPS\Content\Controller
$options[ $category->id ] = $category->name;
}
$form->add( new \IPS\Helpers\Form\Select( 'entry_category_id', NULL, FALSE, array( 'options' => $options, 'parse' => 'normal' ), NULL, NULL, NULL, "entry_category_id" ) );
$form->add( new Select( 'entry_category_id', NULL, FALSE, array( 'options' => $options, 'parse' => 'normal' ), NULL, NULL, NULL, "entry_category_id" ) );
}
$form->add( new \IPS\Helpers\Form\Text( 'blog_entry_new_category', NULL, TRUE, array(), NULL, NULL, NULL, "blog_entry_new_category" ) );
$form->add( new Text( 'blog_entry_new_category', NULL, TRUE, array(), NULL, NULL, NULL, "blog_entry_new_category" ) );
$this->moderationAlertField( $form, $item );
if ( $values = $form->values() )
{
if ( $data['blog'] === NULL OR !$data['blog']->can( 'add' ) )
{
\IPS\Output::i()->error( 'node_move_invalid', '1S136/L', 403, '' );
Output::i()->error( 'node_move_invalid', '1S136/L', 403, '' );
}
/* If this item is read, we need to re-mark it as such after moving */
if( $item instanceof \IPS\Content\ReadMarkers )
if( IPS::classUsesTrait( $item, ReadMarkers::class ) )
{
$unread = $item->unread();
}
@@ -412,9 +451,9 @@ class _entry extends \IPS\Content\Controller
}
else
{
$newCategory = new \IPS\blog\Entry\Category;
$newCategory = new Category;
$newCategory->name = $values['blog_entry_new_category'];
$newCategory->seo_name = \IPS\Http\Url\Friendly::seoTitle( $values['blog_entry_new_category'] );
$newCategory->seo_name = Friendly::seoTitle( $values['blog_entry_new_category'] );
$newCategory->blog_id = $item->blog_id;
$newCategory->save();
@@ -425,7 +464,7 @@ class _entry extends \IPS\Content\Controller
$item->save();
/* Mark it as read */
if( $item instanceof \IPS\Content\ReadMarkers and $unread == 0 )
if( IPS::classUsesTrait( $item, ReadMarkers::class ) and $unread == 0 )
{
$item->markRead( NULL, NULL, NULL, TRUE );
}
@@ -435,9 +474,9 @@ class _entry extends \IPS\Content\Controller
$this->sendModerationAlert($values, $item);
}
\IPS\Session::i()->modLog( 'modlog__action_move', array( $item::$title => TRUE, $item->url()->__toString() => FALSE, $item->mapped( 'title' ) ?: ( method_exists( $item, 'item' ) ? $item->item()->mapped( 'title' ) : NULL ) => FALSE ), $item );
Session::i()->modLog( 'modlog__action_move', array( $item::$title => TRUE, $item->url()->__toString() => FALSE, $item->mapped( 'title' ) ?: ( method_exists( $item, 'item' ) ? $item->item()->mapped( 'title' ) : NULL ) => FALSE ), $item );
\IPS\Output::i()->redirect( $item->url() );
Output::i()->redirect( $item->url() );
}
return $form;
@@ -445,12 +484,12 @@ class _entry extends \IPS\Content\Controller
), $item->url()->setQueryString( array( 'do' => 'move' ) ) );
$this->_setBreadcrumbAndTitle( $item );
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( 'move_item', FALSE, array( 'sprintf' => array( \IPS\Member::loggedIn()->language()->addToStack( \IPS\blog\Entry::$title ) ) ) );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'global', 'core' )->box( $wizard, array( 'ipsPad' ) );
Output::i()->title = Member::loggedIn()->language()->addToStack( 'move_item', FALSE, array( 'sprintf' => array( Member::loggedIn()->language()->addToStack( EntryClass::$title ) ) ) );
Output::i()->output = Theme::i()->getTemplate( 'global', 'core' )->box( $wizard, array( 'i-padding_2' ) );
}
catch ( \Exception $e )
catch ( Exception )
{
\IPS\Output::i()->error( 'node_error', '2S136/D', 403, '' );
Output::i()->error( 'node_error', '2S136/D', 403, '' );
}
}
}
@@ -12,36 +12,53 @@
namespace IPS\blog\modules\front\blogs;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use IPS\blog\Blog;
use IPS\blog\Entry;
use IPS\core\FrontNavigation;
use IPS\Dispatcher\Controller;
use IPS\Helpers\Form;
use IPS\Helpers\Form\Node;
use IPS\Http\Url;
use IPS\Member;
use IPS\Output;
use IPS\Request;
use IPS\Session;
use IPS\Settings;
use IPS\Theme;
use OutOfRangeException;
use function defined;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Submit
*/
class _submit extends \IPS\Dispatcher\Controller
class submit extends Controller
{
/**
* @brief This blog
*/
protected $blog = NULL;
protected ?Blog $blog = NULL;
/**
* Execute
*
* @return void
*/
public function execute()
public function execute() : void
{
if ( isset( \IPS\Request::i()->id ) )
if ( isset( Request::i()->id ) )
{
try
{
$this->blog = \IPS\blog\Blog::load( \IPS\Request::i()->id );
$this->blog = Blog::load( Request::i()->id );
}
catch( \OutOfRangeException $e ) {}
\IPS\blog\Entry::canCreate( \IPS\Member::loggedIn(), $this->blog, TRUE );
catch( OutOfRangeException ) {}
Entry::canCreate( Member::loggedIn(), $this->blog, TRUE );
}
parent::execute();
@@ -52,9 +69,9 @@ class _submit extends \IPS\Dispatcher\Controller
*
* @return void
*/
protected function manage()
protected function manage() : void
{
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( 'submit_entry' );
Output::i()->title = Member::loggedIn()->language()->addToStack( 'submit_entry' );
/* Load Blog */
try
@@ -62,54 +79,54 @@ class _submit extends \IPS\Dispatcher\Controller
/* Can we add to this Blog? We load the blog in execute, so emulate an OutOfRangeException here if we don't actually have one. */
if ( $this->blog === NULL )
{
throw new \OutOfRangeException;
throw new OutOfRangeException;
}
\IPS\blog\Entry::canCreate( \IPS\Member::loggedIn(), $this->blog, TRUE );
Entry::canCreate( Member::loggedIn(), $this->blog, TRUE );
$form = \IPS\blog\Entry::create( $this->blog );
$formTemplate = $form->customTemplate( array( \IPS\Theme::i()->getTemplate( 'submit', 'blog' ), 'submitFormTemplate' ) );
$form = Entry::create( $this->blog );
$formTemplate = $form->customTemplate( array( Theme::i()->getTemplate( 'submit', 'blog' ), 'submitFormTemplate' ) );
if ( $club = $this->blog->club() )
{
\IPS\core\FrontNavigation::$clubTabActive = TRUE;
\IPS\Output::i()->breadcrumb = array();
\IPS\Output::i()->breadcrumb[] = array( \IPS\Http\Url::internal( 'app=core&module=clubs&controller=directory', 'front', 'clubs_list' ), \IPS\Member::loggedIn()->language()->addToStack('module__core_clubs') );
\IPS\Output::i()->breadcrumb[] = array( $club->url(), $club->name );
FrontNavigation::$clubTabActive = TRUE;
Output::i()->breadcrumb = array();
Output::i()->breadcrumb[] = array( Url::internal( 'app=core&module=clubs&controller=directory', 'front', 'clubs_list' ), Member::loggedIn()->language()->addToStack('module__core_clubs') );
Output::i()->breadcrumb[] = array( $club->url(), $club->name );
if ( \IPS\Settings::i()->clubs_header == 'sidebar' )
if ( Settings::i()->clubs_header == 'sidebar' )
{
\IPS\Output::i()->sidebar['contextual'] = \IPS\Theme::i()->getTemplate( 'clubs', 'core' )->header( $club, $this->blog, 'sidebar' );
Output::i()->sidebar['contextual'] = Theme::i()->getTemplate( 'clubs', 'core' )->header( $club, $this->blog, 'sidebar' );
}
}
\IPS\Output::i()->breadcrumb[] = array( $this->blog->url(), $this->blog->_title );
Output::i()->breadcrumb[] = array( $this->blog->url(), $this->blog->_title );
if( !$this->blog->social_group )
{
\IPS\Session::i()->setLocation( $this->blog->url(), array(), 'loc_blog_adding_entry', array( $this->blog->_title => FALSE ) );
Session::i()->setLocation( $this->blog->url(), array(), 'loc_blog_adding_entry', array( $this->blog->_title => FALSE ) );
}
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'submit' )->submit( $formTemplate, $this->blog );
Output::i()->output = Theme::i()->getTemplate( 'submit' )->submit( $formTemplate, $this->blog );
}
catch ( \OutOfRangeException $e )
catch ( OutOfRangeException )
{
$form = new \IPS\Helpers\Form( 'select_blog', 'continue' );
$form->class = 'ipsForm_vertical ipsForm_noLabels';
$form->add( new \IPS\Helpers\Form\Node( 'blog_select', NULL, TRUE, array(
'url' => \IPS\Http\Url::internal( 'app=blog&module=blogs&controller=submit', 'front', 'blog_submit' ),
$form = new Form( 'select_blog', 'continue' );
$form->class = 'ipsForm--vertical ipsForm--manage-blog ipsForm--noLabels';
$form->add( new Node( 'blog_select', NULL, TRUE, array(
'url' => Url::internal( 'app=blog&module=blogs&controller=submit', 'front', 'blog_submit' ),
'class' => 'IPS\blog\Blog',
'permissionCheck' => 'add',
'forceOwner' => \IPS\Member::loggedIn(),
'clubs' => \IPS\Settings::i()->club_nodes_in_apps
'forceOwner' => Member::loggedIn(),
'clubs' => Settings::i()->club_nodes_in_apps
) ) );
if ( $values = $form->values() )
{
$url = \IPS\Http\Url::internal( 'app=blog&module=blogs&controller=submit', 'front', 'blog_submit' )->setQueryString( 'id', $values['blog_select']->_id );
\IPS\Output::i()->redirect( $url );
$url = Url::internal( 'app=blog&module=blogs&controller=submit', 'front', 'blog_submit' )->setQueryString( 'id', $values['blog_select']->_id );
Output::i()->redirect( $url );
}
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'submit' )->blogSelector( $form );
Output::i()->output = Theme::i()->getTemplate( 'submit' )->blogSelector( $form );
}
}
}
+231 -233
View File
@@ -12,43 +12,80 @@
namespace IPS\blog\modules\front\blogs;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use Exception;
use IPS\blog\Blog;
use IPS\blog\Entry;
use IPS\blog\Entry\Category;
use IPS\core\FrontNavigation;
use IPS\core\Rss\Import;
use IPS\Db;
use IPS\File;
use IPS\Helpers\CoverPhoto;
use IPS\Helpers\CoverPhoto\Controller;
use IPS\Helpers\Form;
use IPS\Helpers\Form\Text;
use IPS\Helpers\Form\Url;
use IPS\Helpers\Form\YesNo;
use IPS\Helpers\Table\Content;
use IPS\Http\Url\Friendly;
use IPS\Member;
use IPS\Member\Club;
use IPS\Output;
use IPS\Request;
use IPS\Session;
use IPS\Settings;
use IPS\Task;
use IPS\Theme;
use IPS\Xml\Atom;
use IPS\Xml\Rss;
use OutOfRangeException;
use UnderflowException;
use function defined;
use function in_array;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* View Blog Controller
*/
class _view extends \IPS\Helpers\CoverPhoto\Controller
class view extends Controller
{
/**
* [Content\Controller] Class
*/
protected static $contentModel = 'IPS\blog\Blog';
protected static string $contentModel = 'IPS\blog\Blog';
/**
* Blog object
*/
protected ?Blog $blog = NULL;
/**
* Execute
*
* @return void
*/
public function execute()
public function execute() : void
{
/* Load blog and check permissions */
try
{
$this->blog = \IPS\blog\Blog::loadAndCheckPerms( \IPS\Request::i()->id, 'read' );
$this->blog = Blog::loadAndCheckPerms( Request::i()->id, 'read' );
}
catch ( \OutOfRangeException $e )
catch ( OutOfRangeException )
{
\IPS\Output::i()->error( 'node_error', '2B201/1', 404, '' );
Output::i()->error( 'node_error', '2B201/1', 404, '' );
}
if ( $this->blog->cover_photo )
{
\IPS\Output::i()->metaTags['og:image'] = \IPS\File::get( $this->_coverPhotoStorageExtension(), $this->blog->cover_photo )->url;
Output::i()->metaTags['og:image'] = File::get( $this->_coverPhotoStorageExtension(), $this->blog->cover_photo )->url;
}
parent::execute();
@@ -59,16 +96,16 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
*
* @return void
*/
protected function manage()
protected function manage() : void
{
$this->blog->clubCheckRules();
/* Build table */
$tableUrl = $this->blog->url();
$where = array();
if ( !\in_array( $this->blog->id, array_keys( \IPS\blog\Blog::loadByOwner( \IPS\Member::loggedIn() ) ) ) AND !\IPS\blog\Entry::canViewHiddenItems( \IPS\Member::loggedIn(), $this->blog ) )
if ( !in_array( $this->blog->id, array_keys( Blog::loadByOwner( Member::loggedIn() ) ) ) AND !Entry::canViewHiddenItems( Member::loggedIn(), $this->blog ) )
{
if ( !( $club = $this->blog->club() AND \in_array( $club->memberStatus( \IPS\Member::loggedIn() ), array( \IPS\Member\Club::STATUS_LEADER, \IPS\Member\Club::STATUS_MODERATOR ) ) ) )
if ( !( $club = $this->blog->club() AND in_array( $club->memberStatus( Member::loggedIn() ), array( Club::STATUS_LEADER, Club::STATUS_MODERATOR ) ) ) )
{
$where[] = array( "entry_status!='draft'" );
}
@@ -77,10 +114,10 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
/* Are we limiting by category? */
try
{
$category = \IPS\blog\Entry\Category::load( \IPS\Request::i()->cat );
$category = Category::load( (int) Request::i()->cat );
$tableUrl = $tableUrl->setQueryString( [ 'cat' => $category->id ] );
}
catch( \OutOfRangeException $e )
catch( OutOfRangeException )
{
$category = NULL;
}
@@ -90,24 +127,27 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
$where[] = array( "entry_category_id=?", $category->id );
}
$table = new \IPS\Helpers\Table\Content( 'IPS\blog\Entry', $tableUrl, $where, $this->blog );
$table = new Content( 'IPS\blog\Entry', $tableUrl, $where, $this->blog );
$table->tableTemplate = array( \IPS\Theme::i()->getTemplate( 'view' ), 'blogTable' );
if ( \IPS\Settings::i()->blog_allow_grid )
{
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'grid.css', 'blog', 'front' ) );
$table->rowsTemplate = array( \IPS\Theme::i()->getTemplate( 'view' ), 'rowsGrid' );
}
else
{
$table->rowsTemplate = array( \IPS\Theme::i()->getTemplate( 'view' ), 'rows' );
}
$table->title = \IPS\Member::loggedIn()->language()->addToStack('entries_in_this_blog');
$table->sortBy = \IPS\Request::i()->sortby ?: 'date';
$table->tableTemplate = array( Theme::i()->getTemplate( 'view' ), 'blogTable' );
$viewMode = Member::loggedIn()->getLayoutValue( 'blog_view' );
$template = ( $viewMode == 'grid' ) ? 'rowsGrid' : 'rows';
$table->rowsTemplate = array( Theme::i()->getTemplate( 'view' ), $template );
$table->title = Member::loggedIn()->language()->addToStack('entries_in_this_blog');
$table->sortBy = Request::i()->sortby ?: 'date';
/* Update views */
if ( !\IPS\Request::i()->isAjax() )
Db::i()->update(
'blog_blogs',
"`blog_num_views`=`blog_num_views`+1",
array( "blog_id=?", $this->blog->id ),
array(),
NULL,
Db::LOW_PRIORITY
);
if ( ! Request::i()->isAjax() )
{
$this->blog->updateViews();
}
@@ -115,48 +155,48 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
/* Online User Location */
if( !$this->blog->social_group )
{
\IPS\Session::i()->setLocation( $this->blog->url(), array(), 'loc_blog_viewing_blog', array( "blogs_blog_{$this->blog->id}" => TRUE ) );
Session::i()->setLocation( $this->blog->url(), array(), 'loc_blog_viewing_blog', array( "blogs_blog_{$this->blog->id}" => TRUE ) );
}
if( \IPS\Settings::i()->blog_allow_rss and $this->blog->settings['allowrss'] )
if( Settings::i()->blog_allow_rss and $this->blog->settings['allowrss'] )
{
\IPS\Output::i()->rssFeeds['blog_rss_title'] = \IPS\Http\Url::internal( "app=blog&module=blogs&controller=view&id={$this->blog->_id}", 'front', 'blogs_rss', array( $this->blog->seo_name ) );
Output::i()->rssFeeds['blog_rss_title'] = \IPS\Http\Url::internal( "app=blog&module=blogs&controller=view&id={$this->blog->_id}", 'front', 'blogs_rss', array( $this->blog->seo_name ) );
if ( \IPS\Member::loggedIn()->member_id )
if ( Member::loggedIn()->member_id )
{
$key = \IPS\Member::loggedIn()->getUniqueMemberHash();
$key = Member::loggedIn()->getUniqueMemberHash();
\IPS\Output::i()->rssFeeds['blog_rss_title'] = \IPS\Output::i()->rssFeeds['blog_rss_title']->setQueryString( array( 'member' => \IPS\Member::loggedIn()->member_id , 'key' => $key ) );
Output::i()->rssFeeds['blog_rss_title'] = Output::i()->rssFeeds['blog_rss_title']->setQueryString( array( 'member' => Member::loggedIn()->member_id , 'key' => $key ) );
}
}
/* Add JSON-ld */
\IPS\Output::i()->jsonLd['blog'] = array(
'@context' => "http://schema.org",
Output::i()->jsonLd['blog'] = array(
'@context' => "https://schema.org",
'@type' => "Blog",
'url' => (string) $this->blog->url(),
'name' => $this->blog->_title,
'description' => $this->blog->member_id ? $this->blog->desc : \IPS\Member::loggedIn()->language()->addToStack( \IPS\blog\Blog::$titleLangPrefix . $this->blog->_id . \IPS\blog\Blog::$descriptionLangSuffix, TRUE, array( 'striptags' => TRUE, 'escape' => TRUE ) ),
'description' => $this->blog->member_id ? $this->blog->desc : Member::loggedIn()->language()->addToStack( Blog::$titleLangPrefix . $this->blog->_id . Blog::$descriptionLangSuffix, TRUE, array( 'striptags' => TRUE, 'escape' => TRUE ) ),
'commentCount' => $this->blog->_comments,
'interactionStatistic' => array(
array(
'@type' => 'InteractionCounter',
'interactionType' => "http://schema.org/ViewAction",
'interactionType' => "https://schema.org/ViewAction",
'userInteractionCount' => $this->blog->num_views
),
array(
'@type' => 'InteractionCounter',
'interactionType' => "http://schema.org/FollowAction",
'userInteractionCount' => \IPS\blog\Entry::containerFollowerCount( $this->blog )
'interactionType' => "https://schema.org/FollowAction",
'userInteractionCount' => Entry::containerFollowerCount( $this->blog )
),
array(
'@type' => 'InteractionCounter',
'interactionType' => "http://schema.org/CommentAction",
'interactionType' => "https://schema.org/CommentAction",
'userInteractionCount' => $this->blog->_comments
),
array(
'@type' => 'InteractionCounter',
'interactionType' => "http://schema.org/WriteAction",
'interactionType' => "https://schema.org/WriteAction",
'userInteractionCount' => $this->blog->_items
)
)
@@ -164,36 +204,36 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
if( $this->blog->coverPhoto()->file )
{
\IPS\Output::i()->jsonLd['blog']['image'] = (string) $this->blog->coverPhoto()->file->url;
Output::i()->jsonLd['blog']['image'] = (string) $this->blog->coverPhoto()->file->url;
}
if( $this->blog->member_id )
{
\IPS\Output::i()->jsonLd['blog']['author'] = array(
Output::i()->jsonLd['blog']['author'] = array(
'@type' => 'Person',
'name' => \IPS\Member::load( $this->blog->member_id )->name,
'url' => (string) \IPS\Member::load( $this->blog->member_id )->url(),
'image' => \IPS\Member::load( $this->blog->member_id )->get_photo( TRUE, TRUE )
'name' => Member::load( $this->blog->member_id )->name,
'url' => (string) Member::load( $this->blog->member_id )->url(),
'image' => Member::load( $this->blog->member_id )->get_photo( TRUE, TRUE )
);
}
if( \IPS\Settings::i()->blog_enable_sidebar and $this->blog->sidebar )
if( Settings::i()->blog_enable_sidebar and $this->blog->sidebar )
{
\IPS\Output::i()->sidebar['contextual'] = \IPS\Theme::i()->getTemplate('view')->blogSidebar( $this->blog->sidebar );
Output::i()->sidebar['contextual'] = Theme::i()->getTemplate('view')->blogSidebar( $this->blog->sidebar );
}
\IPS\Output::i()->breadcrumb = array();
Output::i()->breadcrumb = array();
if ( $club = $this->blog->club() )
{
\IPS\core\FrontNavigation::$clubTabActive = TRUE;
\IPS\Output::i()->breadcrumb = array();
\IPS\Output::i()->breadcrumb[] = array( \IPS\Http\Url::internal( 'app=core&module=clubs&controller=directory', 'front', 'clubs_list' ), \IPS\Member::loggedIn()->language()->addToStack('module__core_clubs') );
\IPS\Output::i()->breadcrumb[] = array( $club->url(), $club->name );
FrontNavigation::$clubTabActive = TRUE;
Output::i()->breadcrumb = array();
Output::i()->breadcrumb[] = array( \IPS\Http\Url::internal( 'app=core&module=clubs&controller=directory', 'front', 'clubs_list' ), Member::loggedIn()->language()->addToStack('module__core_clubs') );
Output::i()->breadcrumb[] = array( $club->url(), $club->name );
}
else
{
\IPS\Output::i()->breadcrumb['module'] = array( \IPS\Http\Url::internal( 'app=blog', 'front', 'blogs' ), \IPS\Member::loggedIn()->language()->addToStack( '__app_blog' ) );
Output::i()->breadcrumb['module'] = array( \IPS\Http\Url::internal( 'app=blog', 'front', 'blogs' ), Member::loggedIn()->language()->addToStack( '__app_blog' ) );
}
@@ -201,23 +241,23 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
{
foreach( $this->blog->category()->parents() as $parent )
{
\IPS\Output::i()->breadcrumb[] = array( $parent->url(), $parent->_title );
Output::i()->breadcrumb[] = array( $parent->url(), $parent->_title );
}
\IPS\Output::i()->breadcrumb[] = array( $this->blog->category()->url(), $this->blog->category()->_title );
Output::i()->breadcrumb[] = array( $this->blog->category()->url(), $this->blog->category()->_title );
}
catch (\OutOfRangeException $e) {}
catch (OutOfRangeException ) {}
\IPS\Output::i()->breadcrumb[] = array( $this->blog->url(), $this->blog->_title );
Output::i()->breadcrumb[] = array( $this->blog->url(), $this->blog->_title );
/* Categories */
$categories = \IPS\blog\Entry\Category::roots( NULL, NULL, array( 'entry_category_blog_id=?', $this->blog->id ) );
$categories = Category::roots( NULL, NULL, array( 'entry_category_blog_id=?', $this->blog->id ) );
/* Set default search option */
\IPS\Output::i()->defaultSearchOption = array( 'blog_entry', 'blog_entry_pl' );
Output::i()->defaultSearchOption = array( 'blog_entry', 'blog_entry_pl' );
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'front_browse.js', 'blog', 'front' ) );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'view' )->view( $this->blog, (string) $table, $category );
\IPS\Output::i()->contextualSearchOptions[ \IPS\Member::loggedIn()->language()->addToStack( 'search_contextual_item_blogs' ) ] = array( 'type' => 'blog_entry', 'nodes' => $this->blog->_id );
Output::i()->jsFiles = array_merge( Output::i()->jsFiles, Output::i()->js( 'front_browse.js', 'blog', 'front' ) );
Output::i()->output = Theme::i()->getTemplate( 'view' )->view( $this->blog, (string) $table, $category );
Output::i()->contextualSearchOptions[ Member::loggedIn()->language()->addToStack( 'search_contextual_item_blogs' ) ] = array( 'type' => 'blog_entry', 'nodes' => $this->blog->_id );
}
/**
@@ -225,18 +265,18 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
*
* @return void
*/
protected function editBlog()
protected function editBlog() : void
{
if( !$this->blog->canEdit() OR $this->blog->groupblog_ids or $this->blog->club_id )
{
\IPS\Output::i()->error( 'no_module_permission', '2B201/2', 403, '' );
Output::i()->error( 'no_module_permission', '2B201/2', 403, '' );
}
\IPS\Session::i()->csrfCheck();
Session::i()->csrfCheck();
/* Build form */
$form = new \IPS\Helpers\Form( 'form', 'save', $this->blog->url()->setQueryString( array( 'do' => 'editBlog' ) )->csrf() );
$form->class .= 'ipsForm_vertical';
$form = new Form( 'form', 'save', $this->blog->url()->setQueryString( array( 'do' => 'editBlog' ) )->csrf() );
$form->class .= 'ipsForm--vertical ipsForm--edit-blog';
$this->blog->form( $form, TRUE );
@@ -245,22 +285,22 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
{
if( !$values['blog_name'] )
{
$form->elements['']['blog_name']->error = \IPS\Member::loggedIn()->language()->addToStack('form_required');
$form->elements['']['blog_name']->error = Member::loggedIn()->language()->addToStack('form_required');
\IPS\Output::i()->output = $form->customTemplate( array( \IPS\Theme::i()->getTemplate( 'forms', 'core' ), 'popupTemplate' ) );
Output::i()->output = $form->customTemplate( array( Theme::i()->getTemplate( 'forms', 'core' ), 'popupTemplate' ) );
return;
}
$this->blog->saveForm( $this->blog->formatFormValues( $values ) );
\IPS\Output::i()->redirect( $this->blog->url() );
Output::i()->redirect( $this->blog->url() );
}
/* Display form */
\IPS\Output::i()->title = $this->blog->_title;
\IPS\Output::i()->breadcrumb[] = array( $this->blog->url(), $this->blog->_title );
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'front_view.js', 'blog', 'front' ) );
\IPS\Output::i()->output = $form->customTemplate( array( \IPS\Theme::i()->getTemplate( 'forms', 'core' ), 'popupTemplate' ) );
Output::i()->title = $this->blog->_title;
Output::i()->breadcrumb[] = array( $this->blog->url(), $this->blog->_title );
Output::i()->jsFiles = array_merge( Output::i()->jsFiles, Output::i()->js( 'front_view.js', 'blog', 'front' ) );
Output::i()->output = $form->customTemplate( array( Theme::i()->getTemplate( 'forms', 'core' ), 'popupTemplate' ) );
}
/**
@@ -268,26 +308,26 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
*
* @return void
*/
protected function deleteBlog()
protected function deleteBlog() : void
{
\IPS\Session::i()->csrfCheck();
Session::i()->csrfCheck();
if( !$this->blog->canDelete() or $this->blog->club_id )
{
\IPS\Output::i()->error( 'no_module_permission', '2B201/3', 403, '' );
Output::i()->error( 'no_module_permission', '2B201/3', 403, '' );
}
/* Make sure the user confirmed the deletion */
\IPS\Request::i()->confirmedDelete();
Request::i()->confirmedDelete();
$this->blog->disabled = TRUE;
$this->blog->save();
/* Log */
\IPS\Session::i()->modLog( 'modlog__action_delete_blog', array( $this->blog->name => FALSE ) );
Session::i()->modLog( 'modlog__action_delete_blog', array( $this->blog->name => FALSE ) );
\IPS\Task::queue( 'core', 'DeleteOrMoveContent', array( 'class' => 'IPS\blog\Blog', 'id' => $this->blog->id, 'deleteWhenDone' => TRUE ) );
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=blog&module=blogs&controller=browse', 'front', 'blogs' ) );
Task::queue( 'core', 'DeleteOrMoveContent', array( 'class' => 'IPS\blog\Blog', 'id' => $this->blog->id, 'deleteWhenDone' => TRUE ) );
Output::i()->redirect( \IPS\Http\Url::internal( 'app=blog&module=blogs&controller=browse', 'front', 'blogs' ) );
}
/**
@@ -295,27 +335,27 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
*
* @return void
*/
protected function changePin()
protected function changePin() : void
{
\IPS\Session::i()->csrfCheck();
Session::i()->csrfCheck();
/* Do we have permission */
if ( ( $this->blog->pinned and !\IPS\Member::loggedIn()->modPermission('can_unpin_content') ) or ( !$this->blog->pinned and !\IPS\Member::loggedIn()->modPermission('can_pin_content') ) or $this->blog->club_id )
if ( ( $this->blog->pinned and !Member::loggedIn()->modPermission('can_unpin_content') ) or ( !$this->blog->pinned and !Member::loggedIn()->modPermission('can_pin_content') ) or $this->blog->club_id )
{
\IPS\Output::i()->error( 'no_module_permission', '2B201/4', 403, '' );
Output::i()->error( 'no_module_permission', '2B201/4', 403, '' );
}
$this->blog->pinned = $this->blog->pinned ? FALSE : TRUE;
$this->blog->pinned = !$this->blog->pinned;
$this->blog->save();
/* Respond or redirect */
if ( \IPS\Request::i()->isAjax() )
if ( Request::i()->isAjax() )
{
\IPS\Output::i()->json( 'OK' );
Output::i()->json( 'OK' );
}
else
{
\IPS\Output::i()->redirect( $this->blog->url() );
Output::i()->redirect( $this->blog->url() );
}
}
@@ -324,107 +364,65 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
*
* @return void
*/
protected function rssImport()
protected function rssImport() : void
{
if( !\IPS\Settings::i()->blog_allow_rssimport )
if( !Settings::i()->blog_allow_rssimport )
{
\IPS\Output::i()->error( 'rss_import_disabled', '2B201/7', 403, '' );
Output::i()->error( 'rss_import_disabled', '2B201/7', 403, '' );
}
if( !$this->blog->canEdit() )
{
\IPS\Output::i()->error( 'no_module_permission', '2B201/6', 403, '' );
Output::i()->error( 'no_module_permission', '2B201/6', 403, '' );
}
/* Check for existing feed */
try
{
$existing = \IPS\Db::i()->select( '*', 'core_rss_import', array( 'rss_import_class=? AND rss_import_node_id=?', 'IPS\\blog\\Entry', $this->blog->id ) )->first();
$feed = \IPS\core\Rss\Import::constructFromData( $existing );
$existing = Db::i()->select( '*', 'core_rss_import', array( 'rss_import_class=? AND rss_import_node_id=?', 'IPS\\blog\\Entry', $this->blog->id ) )->first();
$feed = Import::constructFromData( $existing );
}
catch ( \UnderflowException $e )
catch ( UnderflowException )
{
$feed = new \IPS\core\Rss\Import;
$feed = new Import;
$feed->class = 'IPS\\blog\\Entry';
}
$form = new \IPS\Helpers\Form;
$form = new Form;
$form->add( new \IPS\Helpers\Form\YesNo( 'blog_enable_rss_import', $feed->url ? TRUE : FALSE, FALSE, array( 'togglesOn' => array( 'blog_rss_import_url', 'blog_rss_import_auth_user', 'blog_rss_import_auth_pass', 'blog_rss_import_show_link', 'blog_rss_import_tags' ) ) ) );
$form->add( new YesNo( 'blog_enable_rss_import', (bool)$feed->url, FALSE, array( 'togglesOn' => array( 'blog_rss_import_url', 'blog_rss_import_auth_user', 'blog_rss_import_auth_pass', 'blog_rss_import_show_link', 'blog_rss_import_tags' ) ) ) );
$form->add( new \IPS\Helpers\Form\Url( 'blog_rss_import_url', $feed ? $feed->url : NULL, TRUE, array(), NULL, NULL, NULL, 'blog_rss_import_url' ) );
$form->add( new \IPS\Helpers\Form\Text( 'blog_rss_import_auth_user', $feed ? $feed->auth_user : NULL, FALSE, array(), NULL, NULL, NULL, 'blog_rss_import_auth_user' ) );
$form->add( new \IPS\Helpers\Form\Text( 'blog_rss_import_auth_pass', $feed ? $feed->auth_pass : NULL, FALSE, array(), NULL, NULL, NULL, 'blog_rss_import_auth_pass' ) );
$form->add( new \IPS\Helpers\Form\Text( 'blog_rss_import_show_link', $feed->showlink ?: \IPS\Member::loggedIn()->language()->addToStack('blog_rss_import_show_link_default' ), FALSE, array(), NULL, NULL, NULL, 'blog_rss_import_show_link' ) );
$form->add( new Url( 'blog_rss_import_url', $feed->url, TRUE, array(), NULL, NULL, NULL, 'blog_rss_import_url' ) );
$form->add( new Text( 'blog_rss_import_auth_user', $feed->auth_user ?: null, FALSE, array(), NULL, NULL, NULL, 'blog_rss_import_auth_user' ) );
$form->add( new Text( 'blog_rss_import_auth_pass', $feed->auth_pass ?: null, FALSE, array(), NULL, NULL, NULL, 'blog_rss_import_auth_pass' ) );
$form->add( new Text( 'blog_rss_import_show_link', $feed->showlink ?: Member::loggedIn()->language()->addToStack('blog_rss_import_show_link_default' ), FALSE, array(), NULL, NULL, NULL, 'blog_rss_import_show_link' ) );
$options = array( 'autocomplete' => array( 'unique' => TRUE, 'minimized' => FALSE, 'source' => \IPS\Content\Item::definedTags( $this->blog ), 'freeChoice' => ( \IPS\Settings::i()->tags_open_system ? TRUE : FALSE ) ) );
if ( \IPS\Settings::i()->tags_force_lower )
$options = array(
'autocomplete' => array(
'unique' => TRUE,
'minimized' => FALSE,
'source' => Entry::definedTags(),
'freeChoice' => false
)
);
if ( Settings::i()->tags_force_lower )
{
$options['autocomplete']['forceLower'] = TRUE;
}
if ( \IPS\Settings::i()->tags_min )
if ( Settings::i()->tags_min )
{
$options['autocomplete']['minItems'] = \IPS\Settings::i()->tags_min;
$options['autocomplete']['minItems'] = Settings::i()->tags_min;
}
if ( \IPS\Settings::i()->tags_max )
if ( Settings::i()->tags_max )
{
$options['autocomplete']['maxItems'] = \IPS\Settings::i()->tags_max;
$options['autocomplete']['maxItems'] = Settings::i()->tags_max;
}
if ( \IPS\Settings::i()->tags_len_min )
{
$options['autocomplete']['minLength'] = \IPS\Settings::i()->tags_len_min;
}
if ( \IPS\Settings::i()->tags_len_max )
{
$options['autocomplete']['maxLength'] = \IPS\Settings::i()->tags_len_max;
}
if ( \IPS\Settings::i()->tags_clean )
{
$options['autocomplete']['filterProfanity'] = TRUE;
}
if ( \IPS\Settings::i()->tags_alphabetical )
{
$options['autocomplete']['alphabetical'] = TRUE;
}
$options['autocomplete']['prefix'] = \IPS\Content\Item::canPrefix( NULL, $this->blog );
$options['autocomplete']['prefix'] = Entry::canPrefix( NULL, $this->blog );
$options['autocomplete']['disallowedCharacters'] = array( '#' ); // @todo Pending \IPS\Http\Url rework, hashes cannot be used in URLs
/* Language strings for tags description */
if ( \IPS\Settings::i()->tags_open_system )
{
$extralang = array();
if ( \IPS\Settings::i()->tags_min && \IPS\Settings::i()->tags_max )
{
$extralang[] = \IPS\Member::loggedIn()->language()->addToStack( 'tags_desc_min_max', FALSE, array( 'sprintf' => array( \IPS\Settings::i()->tags_max ), 'pluralize' => array( \IPS\Settings::i()->tags_min ) ) );
}
else if( \IPS\Settings::i()->tags_min )
{
$extralang[] = \IPS\Member::loggedIn()->language()->addToStack( 'tags_desc_min', FALSE, array( 'pluralize' => array( \IPS\Settings::i()->tags_min ) ) );
}
else if( \IPS\Settings::i()->tags_min )
{
$extralang[] = \IPS\Member::loggedIn()->language()->addToStack( 'tags_desc_max', FALSE, array( 'pluralize' => array( \IPS\Settings::i()->tags_max ) ) );
}
if( \IPS\Settings::i()->tags_len_min && \IPS\Settings::i()->tags_len_max )
{
$extralang[] = \IPS\Member::loggedIn()->language()->addToStack( 'tags_desc_len_min_max', FALSE, array( 'sprintf' => array( \IPS\Settings::i()->tags_len_min, \IPS\Settings::i()->tags_len_max ) ) );
}
else if( \IPS\Settings::i()->tags_len_min )
{
$extralang[] = \IPS\Member::loggedIn()->language()->addToStack( 'tags_desc_len_min', FALSE, array( 'pluralize' => array( \IPS\Settings::i()->tags_len_min ) ) );
}
else if( \IPS\Settings::i()->tags_len_max )
{
$extralang[] = \IPS\Member::loggedIn()->language()->addToStack( 'tags_desc_len_max', FALSE, array( 'sprintf' => array( \IPS\Settings::i()->tags_len_max ) ) );
}
$options['autocomplete']['desc'] = \IPS\Member::loggedIn()->language()->addToStack('tags_desc') . ( ( \count( $extralang ) ) ? '<br>' . implode( ' ', $extralang ) : '' );
}
$form->add( new \IPS\Helpers\Form\Text( 'blog_rss_import_tags', $feed ? json_decode( $feed->tags, TRUE ) : array(), \IPS\Settings::i()->tags_min and \IPS\Settings::i()->tags_min_req, $options, NULL, NULL, NULL, 'blog_rss_import_tags' ) );
$form->add( new Text( 'blog_rss_import_tags', $feed->tags ? json_decode( $feed->tags, TRUE ) : array(), Settings::i()->tags_min and Settings::i()->tags_min_req, $options, NULL, NULL, NULL, 'blog_rss_import_tags' ) );
if ( $values = $form->values() )
{
@@ -443,14 +441,14 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
if ( $response->httpResponseCode == 401 )
{
$form->error = \IPS\Member::loggedIn()->language()->addToStack( 'rss_import_auth' );
$form->error = Member::loggedIn()->language()->addToStack( 'rss_import_auth' );
}
$response = $response->decodeXml();
if ( !( $response instanceof \IPS\Xml\Rss ) and !( $response instanceof \IPS\Xml\Atom ) )
if ( !( $response instanceof Rss ) and !( $response instanceof Atom ) )
{
$form->error = \IPS\Member::loggedIn()->language()->addToStack( 'rss_import_invalid' );
$form->error = Member::loggedIn()->language()->addToStack( 'rss_import_invalid' );
}
if( !$form->error )
@@ -460,7 +458,7 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
$feed->showlink = $values['blog_rss_import_show_link'];
$feed->auth_user = $values['blog_rss_import_auth_user'];
$feed->auth_pass = $values['blog_rss_import_auth_pass'];
$feed->member = $this->blog->owner() ? $this->blog->owner()->member_id : \IPS\Member::loggedIn()->member_id;
$feed->member = $this->blog->owner() ? $this->blog->owner()->member_id : Member::loggedIn()->member_id;
$feed->settings = json_encode( array( 'tags' => $values['blog_rss_import_tags'] ) );
$feed->save();
@@ -468,33 +466,33 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
{
$feed->run();
}
catch ( \Exception $e ) { }
catch ( Exception ) { }
/* Redirect */
\IPS\Output::i()->redirect( $this->blog->url() );
Output::i()->redirect( $this->blog->url() );
}
}
catch ( \IPS\Http\Request\Exception $e )
catch ( \IPS\Http\Request\Exception )
{
$form->error = \IPS\Member::loggedIn()->language()->addToStack( 'form_url_bad' );
$form->error = Member::loggedIn()->language()->addToStack( 'form_url_bad' );
}
catch ( \Exception $e )
catch ( Exception )
{
$form->error = \IPS\Member::loggedIn()->language()->addToStack( 'rss_import_invalid' );
$form->error = Member::loggedIn()->language()->addToStack( 'rss_import_invalid' );
}
}
else
{
\IPS\Db::i()->delete( 'core_rss_import', array( 'rss_import_class=? AND rss_import_node_id=?', 'IPS\\blog\\Entry', $this->blog->id ) );
Db::i()->delete( 'core_rss_import', array( 'rss_import_class=? AND rss_import_node_id=?', 'IPS\\blog\\Entry', $this->blog->id ) );
/* Redirect */
\IPS\Output::i()->redirect( $this->blog->url() );
Output::i()->redirect( $this->blog->url() );
}
}
/* Display */
\IPS\Output::i()->output = $form->error ? $form : \IPS\Theme::i()->getTemplate( 'view', 'blog', 'front' )->rssImport( $form->customTemplate( array( \IPS\Theme::i()->getTemplate( 'forms', 'core' ), 'popupTemplate' ) ) );
Output::i()->output = $form->error ? $form : Theme::i()->getTemplate( 'view', 'blog', 'front' )->rssImport( $form->customTemplate( array( Theme::i()->getTemplate( 'forms', 'core' ), 'popupTemplate' ) ) );
}
/**
@@ -502,7 +500,7 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
*
* @return string
*/
protected function _coverPhotoStorageExtension()
protected function _coverPhotoStorageExtension(): string
{
return 'blog_Blogs';
}
@@ -510,22 +508,22 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
/**
* Set Cover Photo
*
* @param \IPS\Helpers\CoverPhoto $photo New Photo
* @param CoverPhoto $photo New Photo
* @return void
*/
protected function _coverPhotoSet( \IPS\Helpers\CoverPhoto $photo )
protected function _coverPhotoSet( CoverPhoto $photo ) : void
{
$this->blog->cover_photo = (string) $photo->file;
$this->blog->cover_photo_offset = (int) $photo->offset;
$this->blog->cover_photo_offset = $photo->offset;
$this->blog->save();
}
/**
* Get Cover Photo
*
* @return \IPS\Helpers\CoverPhoto
* @return CoverPhoto
*/
protected function _coverPhotoGet()
protected function _coverPhotoGet(): CoverPhoto
{
return $this->blog->coverPhoto();
}
@@ -535,10 +533,10 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
*
* @return void
*/
protected function categoriesJson()
protected function categoriesJson() : void
{
$cats = array();
foreach( \IPS\blog\Entry\Category::roots( NULL, NULL, array( 'entry_category_blog_id=?', $this->blog->id ) ) as $meow )
foreach( Category::roots( NULL, NULL, array( 'entry_category_blog_id=?', $this->blog->id ) ) as $meow )
{
$cats[] = array(
'id' => $meow->id,
@@ -546,7 +544,7 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
);
}
\IPS\Output::i()->json( array( 'categories' => $cats ) );
Output::i()->json( array( 'categories' => $cats ) );
}
/**
@@ -554,54 +552,54 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
*
* @return void
*/
protected function manageCategories()
protected function manageCategories() : void
{
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'front_view.js', 'blog', 'front' ) );
Output::i()->jsFiles = array_merge( Output::i()->jsFiles, Output::i()->js( 'front_view.js', 'blog', 'front' ) );
if( !$this->blog->canEdit() )
{
\IPS\Output::i()->error( 'no_module_permission', '2B201/A', 403, '' );
Output::i()->error( 'no_module_permission', '2B201/A', 403, '' );
}
$form = new \IPS\Helpers\Form;
$form->addHtml( \IPS\Theme::i()->getTemplate( 'view', 'blog', 'front' )->manageCategories( $this->blog ) );
$form = new Form;
$form->addHtml( Theme::i()->getTemplate( 'view', 'blog', 'front' )->manageCategories( $this->blog ) );
$form->hiddenValues['submitted'] = 1;
if( $values = $form->values() )
{
\IPS\Output::i()->redirect( $this->blog->url() );
Output::i()->redirect( $this->blog->url() );
}
/* Display */
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('blog_manage_entry_categories');
\IPS\Output::i()->output = $form->error ? $form : \IPS\Theme::i()->getTemplate( 'view', 'blog', 'front' )->rssImport( $form->customTemplate( array( \IPS\Theme::i()->getTemplate( 'forms', 'core' ), 'popupTemplate' ) ) );
Output::i()->title = Member::loggedIn()->language()->addToStack('blog_manage_entry_categories');
Output::i()->output = $form->error ? $form : Theme::i()->getTemplate( 'view', 'blog', 'front' )->rssImport( $form->customTemplate( array( Theme::i()->getTemplate( 'forms', 'core' ), 'popupTemplate' ) ) );
}
/**
* Edit a category name
*
* @return string
* @return void
*/
protected function editCategoryName()
protected function editCategoryName(): void
{
\IPS\Session::i()->csrfCheck();
Session::i()->csrfCheck();
if( !$this->blog->canEdit() )
{
\IPS\Output::i()->error( 'no_module_permission', '2B201/C', 403, '' );
Output::i()->error( 'no_module_permission', '2B201/C', 403, '' );
}
if( ! \IPS\Request::i()->name )
if( ! Request::i()->name )
{
\IPS\Output::i()->error( 'blog_error_missing_name', '1B201/B', 403, '' );
Output::i()->error( 'blog_error_missing_name', '1B201/B', 403, '' );
}
/* New category? */
if ( \IPS\Request::i()->cat === 'new' )
if ( Request::i()->cat === 'new' )
{
$newCategory = new \IPS\blog\Entry\Category;
$newCategory->name = \IPS\Request::i()->name;
$newCategory->seo_name = \IPS\Http\Url\Friendly::seoTitle( \IPS\Request::i()->name );
$newCategory = new Category;
$newCategory->name = Request::i()->name;
$newCategory->seo_name = Friendly::seoTitle( Request::i()->name );
$newCategory->blog_id = $this->blog->id;
$newCategory->save();
@@ -610,23 +608,23 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
{
try
{
$category = \IPS\blog\Entry\Category::load( \IPS\Request::i()->cat );
$category = Category::load( Request::i()->cat );
}
catch ( \OutOfRangeException $e )
catch ( OutOfRangeException )
{
\IPS\Output::i()->error( 'blog_error_not_find_category', '2B201/D', 403, '' );
Output::i()->error( 'blog_error_not_find_category', '2B201/D', 403, '' );
}
if( $category->blog_id !== $this->blog->id )
{
\IPS\Output::i()->error( 'blog_error_not_find_category', '2B201/E', 403, '' );
Output::i()->error( 'blog_error_not_find_category', '2B201/E', 403, '' );
}
$category->name = \IPS\Request::i()->name;
$category->name = Request::i()->name;
$category->save();
}
\IPS\Output::i()->json( 'OK' );
Output::i()->json( 'OK' );
}
/**
@@ -634,42 +632,42 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
*
* @return void
*/
protected function deleteCategory()
protected function deleteCategory() : void
{
\IPS\Session::i()->csrfCheck();
Session::i()->csrfCheck();
if( !$this->blog->canEdit() )
{
\IPS\Output::i()->error( 'no_module_permission', '2B201/8', 403, '' );
Output::i()->error( 'no_module_permission', '2B201/8', 403, '' );
}
try
{
$category = \IPS\blog\Entry\Category::load( \IPS\Request::i()->cat );
$category = Category::load( Request::i()->cat );
}
catch ( \OutOfRangeException $e )
catch ( OutOfRangeException )
{
\IPS\Output::i()->redirect( $this->blog->url() );
Output::i()->redirect( $this->blog->url() );
}
if( $category->blog_id !== $this->blog->id )
{
\IPS\Output::i()->error( 'no_module_permission', '2B201/9', 403, '' );
Output::i()->error( 'no_module_permission', '2B201/9', 403, '' );
}
/* Update Entries */
\IPS\Db::i()->update( 'blog_entries', array( 'entry_category_id' => NULL ), array( 'entry_category_id=?', $category->id ) );
Db::i()->update( 'blog_entries', array( 'entry_category_id' => NULL ), array( 'entry_category_id=?', $category->id ) );
$category->delete();
/* Redirect */
if ( \IPS\Request::i()->isAjax() )
if ( Request::i()->isAjax() )
{
\IPS\Output::i()->json( 'OK' );
Output::i()->json( 'OK' );
}
else
{
\IPS\Output::i()->redirect( $this->blog->url(), 'deleted' );
Output::i()->redirect( $this->blog->url(), 'deleted' );
}
}
@@ -678,26 +676,26 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
*
* @return void
*/
public function categoriesReorder()
public function categoriesReorder() : void
{
\IPS\Session::i()->csrfCheck();
Session::i()->csrfCheck();
if( !$this->blog->canEdit() )
{
\IPS\Output::i()->error( 'no_module_permission', '2B201/F', 403, '' );
Output::i()->error( 'no_module_permission', '2B201/F', 403, '' );
}
/* Set order */
$position = 1;
if( !\IPS\Request::i()->isAjax() )
if( !Request::i()->isAjax() )
{
\IPS\Request::i()->ajax_order = explode( ',', \IPS\Request::i()->ajax_order );
Request::i()->ajax_order = explode( ',', Request::i()->ajax_order );
}
foreach( \IPS\Request::i()->ajax_order as $category )
foreach( Request::i()->ajax_order as $category )
{
$node = \IPS\blog\Entry\Category::load( $category );
$node = Category::load( $category );
/* No funny business trying to reorder another blog's categories */
if( $node->blog_id !== $this->blog->id )
@@ -711,13 +709,13 @@ class _view extends \IPS\Helpers\CoverPhoto\Controller
$position++;
}
if( \IPS\Request::i()->isAjax() )
if( Request::i()->isAjax() )
{
\IPS\Output::i()->json( 'ok' );
Output::i()->json( 'ok' );
}
else
{
\IPS\Output::i()->redirect( $this->blog->url(), 'saved' );
Output::i()->redirect( $this->blog->url(), 'saved' );
}
}
}
Whitespace-only changes.
@@ -1,23 +0,0 @@
{
"1": {
"method": "changeColumn",
"params": [
"blog_entries",
"entry_name_seo",
{
"allow_null": true,
"auto_increment": false,
"binary": false,
"comment": "",
"decimals": null,
"default": null,
"length": 255,
"name": "entry_name_seo",
"type": "VARCHAR",
"unsigned": false,
"values": [],
"zerofill": false
}
]
}
}
@@ -1,216 +0,0 @@
<?php
/**
* @brief 4.0.0 Upgrade Code
* @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 Blog
* @since 30 Oct 2014
*/
namespace IPS\blog\setup\upg_100002;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* 4.0.0 Upgrade Code
*/
class _Upgrade
{
/**
* Fix SEO titles
*
* @return array If returns TRUE, upgrader will proceed to next step. If it returns any other value, it will set this as the value of the 'extra' GET parameter and rerun this step (useful for loops)
*/
public function step1()
{
\IPS\Db::i()->update( 'blog_blogs', array( 'blog_seo_name' => NULL ) );
\IPS\Db::i()->update( 'blog_entries', array( 'entry_name_seo' => NULL ) );
return true;
}
/**
* Custom title for this step
*
* @return string
*/
public function step1CustomTitle()
{
return "Resetting blog friendly URL titles";
}
/**
* Fix Polls
*
* @return array If returns TRUE, upgrader will proceed to next step. If it returns any other value, it will set this as the value of the 'extra' GET parameter and rerun this step (useful for loops)
*/
public function step2()
{
$limit = isset( \IPS\Request::i()->extra ) ? \intval( \IPS\Request::i()->extra ) : 0;
$select = \IPS\Db::i()->select( '*', 'blog_polls', NULL, 'poll_id ASC', array( $limit, 1000 ) );
if ( !$select->count() )
{
return TRUE;
}
foreach ( $select as $poll )
{
/* Sometimes data from 3.4.x isn't always as well formed as we'd like, especially when non-latin chars are involved */
$data = unserialize( $poll['choices'] );
if( !\is_array( $data ) )
{
$poll['choices'] = str_replace( '\\"', '"', $poll['choices'] );
$data = unserialize( $poll['choices'] );
}
$_decoded = FALSE;
if( !\is_array( $data ) )
{
$data = unserialize( utf8_decode( $poll['choices'] ) );
if( \is_array( $data ) )
{
$_decoded = TRUE;
}
}
if( \is_array( $data ) AND $_decoded )
{
foreach( $data as $_key => $_data )
{
$data[ $_key ]['question'] = utf8_encode( $_data[ $_key ]['question'] );
if( \is_array( $_data['choice'] ) )
{
foreach( $_data['choice'] as $_idx => $_choice )
{
$data[ $_key ]['choice'][ $_idx ] = utf8_encode( $_choice );
}
}
}
}
$result = @json_encode( $data );
/* Sometimes the array unserializes fine but there are still "bad" characters in there */
if( $result === FALSE )
{
$data = unserialize( $poll['choices'] );
if( !\is_array( $data ) )
{
$poll['choices'] = str_replace( '\\"', '"', $poll['choices'] );
$data = unserialize( $poll['choices'] );
}
if( !\is_array( $data ) )
{
$data = unserialize( utf8_decode( $poll['choices'] ) );
}
if( \is_array( $data ) )
{
foreach( $data as $_key => $_data )
{
$data[ $_key ]['question'] = utf8_encode( $_data['question'] );
if( \is_array( $_data['choice'] ) )
{
foreach( $_data['choice'] as $_idx => $_choice )
{
$data[ $_key ]['choice'][ $_idx ] = utf8_encode( $_choice );
}
}
else
{
/* No choices, no poll */
\IPS\Db::i()->delete( 'core_polls', array( 'pid=?', $poll['pid'] ) );
continue;
}
}
}
$result = @json_encode( $data );
}
unset( $poll['poll_id'] );
$poll['choices'] = $result;
$poll['poll_only'] = 0;
$poll['poll_view_voters'] = 0;
$entryId = $poll['entry_id'];
unset( $poll['entry_id'] );
$pollId = \IPS\Db::i()->insert( 'core_polls', $poll );
\IPS\Db::i()->update( 'blog_entries', array( 'entry_poll_state' => $pollId ), array( 'entry_id=?', $entryId ) );
}
return $limit + 1000;
}
/**
* Custom title for this step
*
* @return string
*/
public function step2CustomTitle()
{
return "Upgrading polls";
}
/**
* Fix Voters
*
* @return array If returns TRUE, upgrader will proceed to next step. If it returns any other value, it will set this as the value of the 'extra' GET parameter and rerun this step (useful for loops)
*/
public function step3()
{
$limit = isset( \IPS\Request::i()->extra ) ? \intval( \IPS\Request::i()->extra ) : 0;
$select = \IPS\Db::i()->select( '*', 'blog_voters', NULL, 'vote_id ASC', array( $limit, 1000 ) );
if ( !$select->count() )
{
return TRUE;
}
foreach ( $select as $vote )
{
try
{
$pollId = \IPS\Db::i()->select( 'entry_poll_state', 'blog_entries', array( 'entry_id=?', $vote['entry_id'] ) )->first();
unset( $vote['vote_id'] );
unset( $vote['entry_id'] );
$vote['member_choices'] = null;
$vote['poll'] = $pollId;
\IPS\Db::i()->insert( 'core_voters', $vote );
}
catch( \UnderflowException $ex ) { }
}
return $limit + 1000;
}
/**
* Custom title for this step
*
* @return string
*/
public function step3CustomTitle()
{
return "Upgrading poll voters";
}
}
Whitespace-only changes.
@@ -1,205 +0,0 @@
{
"1": {
"method": "dropIndex",
"params": [
"blog_comments",
"comment_text"
]
},
"2": {
"method": "dropIndex",
"params": [
"blog_entries",
"entry_name"
]
},
"3": {
"method": "dropIndex",
"params": [
"blog_entries",
"entry_content"
]
},
"4": {
"method": "dropTable",
"params": [
"blog_akismet_logs",
true
]
},
"5": {
"method": "dropTable",
"params": [
"blog_bookmarks",
true
]
},
"6": {
"method": "dropTable",
"params": [
"blog_categories",
true
]
},
"7": {
"method": "dropTable",
"params": [
"blog_category_mapping",
true
]
},
"8": {
"method": "dropTable",
"params": [
"blog_cblock_cache",
true
]
},
"9": {
"method": "dropTable",
"params": [
"blog_cblocks",
true
]
},
"10": {
"method": "dropTable",
"params": [
"blog_custom_cblocks",
true
]
},
"11": {
"method": "dropTable",
"params": [
"blog_default_cblocks",
true
]
},
"12": {
"method": "dropTable",
"params": [
"blog_editors_map",
true
]
},
"13": {
"method": "dropTable",
"params": [
"blog_lastinfo",
true
]
},
"14": {
"method": "dropTable",
"params": [
"blog_mediatag",
true
]
},
"15": {
"method": "dropTable",
"params": [
"blog_moderators",
true
]
},
"16": {
"method": "dropTable",
"params": [
"blog_pingservices",
true
]
},
"17": {
"method": "dropTable",
"params": [
"blog_polls",
true
]
},
"18": {
"method": "dropTable",
"params": [
"blog_ratings",
true
]
},
"19": {
"method": "dropTable",
"params": [
"blog_rsscache",
true
]
},
"20": {
"method": "dropTable",
"params": [
"blog_themes",
true
]
},
"21": {
"method": "dropTable",
"params": [
"blog_this",
true
]
},
"22": {
"method": "dropTable",
"params": [
"blog_trackback",
true
]
},
"23": {
"method": "dropTable",
"params": [
"blog_trackback_spamlogs",
true
]
},
"24": {
"method": "dropTable",
"params": [
"blog_tracker",
true
]
},
"25": {
"method": "dropTable",
"params": [
"blog_tracker_queue",
true
]
},
"26": {
"method": "dropTable",
"params": [
"blog_updatepings",
true
]
},
"27": {
"method": "dropTable",
"params": [
"blog_upgrade_history",
true
]
},
"28": {
"method": "dropTable",
"params": [
"blog_views",
true
]
},
"29": {
"method": "dropTable",
"params": [
"blog_voters",
true
]
}
}
Whitespace-only changes.
@@ -1,38 +0,0 @@
<?php
/**
* @brief 4.0.0 Upgrade Code
* @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 Blog
* @since 15 Jan 2015
*/
namespace IPS\blog\setup\upg_100015;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* 4.0.0 RC 2 Upgrade Code
*/
class _Upgrade
{
/**
* Finish - This is run after all apps have been upgraded
*
* @return mixed If returns TRUE, upgrader will proceed to next step. If it returns any other value, it will set this as the value of the 'extra' GET parameter and rerun this step (useful for loops)
* @note We opted not to let users run this immediately during the upgrade because of potential issues (it taking a long time and users stopping it or getting frustrated) but we can revisit later
*/
public function finish()
{
\IPS\Task::queue( 'core', 'RebuildItems', array( 'class' => 'IPS\blog\Entry' ), 3, array( 'class' ) );
\IPS\Task::queue( 'core', 'RebuildItemCounts', array( 'class' => 'IPS\blog\Entry', 'count' => 0 ), 4, array( 'class' ) );
\IPS\Task::queue( 'core', 'RebuildContainerCounts', array( 'class' => 'IPS\blog\Blog', 'count' => 0 ), 5, array( 'class' ) );
}
}
Whitespace-only changes.
@@ -1,55 +0,0 @@
<?php
/**
* @brief 4.0.0 Upgrade Code
* @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 Blog
* @since 24 Feb 2015
*/
namespace IPS\blog\setup\upg_100016;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* 4.0.0 Upgrade Code
*/
class _Upgrade
{
/**
* Convert RSS tags
*
* @return array If returns TRUE, upgrader will proceed to next step. If it returns any other value, it will set this as the value of the 'extra' GET parameter and rerun this step (useful for loops)
*/
public function step1()
{
foreach( \IPS\Db::i()->select( 'rss_id, rss_tags', 'blog_rss_import' ) as $feed )
{
$update = array();
if( @unserialize( $feed['rss_tags'] ) !== FALSE )
{
$update['rss_tags'] = json_encode( unserialize( $feed['rss_tags'] ) );
\IPS\Db::i()->update( 'blog_rss_import', $update, array( 'rss_id=?', $feed['rss_id'] ) );
}
}
return TRUE;
}
/**
* Custom title for this step
*
* @return string
*/
public function step1CustomTitle()
{
return "Converting RSS feeds";
}
}
Whitespace-only changes.
@@ -1,41 +0,0 @@
<?php
/**
* @brief 4.0.0 RC 5 Upgrade Code
* @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 Blog
* @since 5 May 2015
*/
namespace IPS\blog\setup\upg_100018;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* 4.0.0 RC 5 Upgrade Code
*/
class _Upgrade
{
/**
* Make sure all theme settings are applied to every theme.
*
* @return array If returns TRUE, upgrader will proceed to next step. If it returns any other value, it will set this as the value of the 'extra' GET parameter and rerun this step (useful for loops)
*/
public function finish()
{
\IPS\Task::queue( 'core', 'RebuildReputationIndex', array( 'class' => 'IPS\blog\Entry' ), 4 );
\IPS\Task::queue( 'core', 'RebuildReputationIndex', array( 'class' => 'IPS\blog\Entry\Comment' ), 4 );
\IPS\Task::queue( 'core', 'RebuildContainerCounts', array( 'class' => 'IPS\blog\Blog', 'count' => 0 ), 5, array( 'class' ) );
return TRUE;
}
}
Whitespace-only changes.
@@ -1,71 +0,0 @@
{
"1": {
"method": "changeColumn",
"params": [
"blog_entries",
"entry_poll_state",
{
"name": "entry_poll_state",
"type": "INT",
"length": 8,
"decimals": null,
"values": [],
"allow_null": true,
"default": null,
"comment": "",
"unsigned": true,
"zerofill": false,
"auto_increment": false,
"binary": false
}
]
},
"2": {
"method": "addIndex",
"params": [
"blog_comments",
{
"type": "key",
"name": "ip_lookup",
"columns": [
"comment_ip_address"
],
"length": [
null
]
}
]
},
"3": {
"method": "addIndex",
"params": [
"blog_entries",
{
"type": "key",
"name": "ip_lookup",
"columns": [
"entry_ip_address"
],
"length": [
null
]
}
]
},
"4": {
"method": "addIndex",
"params": [
"blog_comments",
{
"type": "key",
"name": "comment_approved",
"columns": [
"comment_approved"
],
"length": [
null
]
}
]
}
}
@@ -1,120 +0,0 @@
<?php
/**
* @brief 4.0.0 Upgrade Code
* @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 Blog
* @since 15 Mar 2015
*/
namespace IPS\blog\setup\upg_100021;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* 4.0.0 Upgrade Code
*/
class _Upgrade
{
/**
* Convert blog view levels
*
* @return array If returns TRUE, upgrader will proceed to next step. If it returns any other value, it will set this as the value of the 'extra' GET parameter and rerun this step (useful for loops)
*/
public function step1()
{
/* Some init */
$did = 0;
$limit = 0;
if( isset( \IPS\Request::i()->extra ) )
{
$limit = \IPS\Request::i()->extra;
}
/* Try to prevent timeouts to the extent possible */
$cutOff = \IPS\core\Setup\Upgrade::determineCutoff();
foreach( \IPS\Db::i()->select( '*', 'blog_blogs', "blog_view_level IN('private','friends','privateclub')", 'blog_id ASC', array( $limit, 50 ) ) as $blog )
{
if( $cutOff !== null AND time() >= $cutOff )
{
return ( $limit + $did );
}
$did++;
$blog = \IPS\blog\Blog::constructFromData( $blog );
/* Figure out type of blog and act accordingly */
switch( $blog->view_level )
{
case 'private':
$group = \IPS\Db::i()->insert( 'core_sys_social_groups', array( 'owner_id' => $blog->member_id ) );
\IPS\Db::i()->insert( 'core_sys_social_group_members', array( 'group_id' => $group, 'member_id' => $blog->member_id ) );
$blog->social_group = $group;
break;
case 'friends':
case 'privateclub':
$group = \IPS\Db::i()->insert( 'core_sys_social_groups', array( 'owner_id' => $blog->member_id ) );
if( $blog->authorized_users )
{
$users = explode( ',', trim( $blog->authorized_users, ',' ) );
foreach( $users as $user )
{
\IPS\Db::i()->replace( 'core_sys_social_group_members', array( 'group_id' => $group, 'member_id' => $user ) );
}
\IPS\Db::i()->replace( 'core_sys_social_group_members', array( 'group_id' => $group, 'member_id' => $blog->member_id ) );
}
else
{
\IPS\Db::i()->insert( 'core_sys_social_group_members', array( 'group_id' => $group, 'member_id' => $blog->member_id ) );
}
$blog->social_group = $group;
break;
}
$blog->save();
}
if( $did )
{
return $limit + $did;
}
else
{
unset( $_SESSION['_step1Count'] );
return TRUE;
}
}
/**
* Custom title for this step
*
* @return string
*/
public function step1CustomTitle()
{
$limit = isset( \IPS\Request::i()->extra ) ? \IPS\Request::i()->extra : 0;
if( !isset( $_SESSION['_step1Count'] ) )
{
$_SESSION['_step1Count'] = \IPS\Db::i()->select( 'COUNT(*)', 'blog_blogs', "blog_view_level IN('private','friends','privateclub')" )->first();
}
return "Upgrading blogs (Updated so far: " . ( ( $limit > $_SESSION['_step1Count'] ) ? $_SESSION['_step1Count'] : $limit ) . ' out of ' . $_SESSION['_step1Count'] . ')';
}
}
Whitespace-only changes.
@@ -1,22 +0,0 @@
{
"1": {
"method": "addColumn",
"params": [
"blog_entries",
{
"name": "entry_hidden_comments",
"type": "INT",
"length": 10,
"decimals": null,
"values": [],
"allow_null": true,
"default": null,
"comment": "",
"unsigned": true,
"zerofill": false,
"auto_increment": false,
"binary": false
}
]
}
}
Whitespace-only changes.
@@ -1,39 +0,0 @@
<?php
/**
* @brief 4.0.4 Upgrade Code
* @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 Blog
* @since 5 May 2015
*/
namespace IPS\blog\setup\upg_100027;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* 4.0.4 Upgrade Code
*/
class _Upgrade
{
/**
* Finish - This is run after all apps have been upgraded
*
* @return mixed If returns TRUE, upgrader will proceed to next step. If it returns any other value, it will set this as the value of the 'extra' GET parameter and rerun this step (useful for loops)
* @note We opted not to let users run this immediately during the upgrade because of potential issues (it taking a long time and users stopping it or getting frustrated) but we can revisit later
*/
public function finish()
{
/* Rebuild old blog entry images as attachments */
\IPS\Task::queue( 'blog', 'RebuildEntryImages', NULL, 2 );
return TRUE;
}
}
Whitespace-only changes.
@@ -1,42 +0,0 @@
<?php
/**
* @brief 4.0.5 Upgrade Code
* @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 Blog
* @since 5 May 2015
*/
namespace IPS\blog\setup\upg_100028;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* 4.0.5 Upgrade Code
*/
class _Upgrade
{
/**
* Make sure all theme settings are applied to every theme.
*
* @return array If returns TRUE, upgrader will proceed to next step. If it returns any other value, it will set this as the value of the 'extra' GET parameter and rerun this step (useful for loops)
*/
public function finish()
{
\IPS\core\Setup\Upgrade::repairFileUrls('blog');
\IPS\Task::queue( 'core', 'RebuildContentImages', array( 'class' => 'IPS\blog\Entry' ), 3, array( 'class' ) );
\IPS\Task::queue( 'core', 'RebuildContentImages', array( 'class' => 'IPS\blog\Entry\Comment' ), 3, array( 'class' ) );
\IPS\Task::queue( 'core', 'RebuildNonContentImages', array( 'extension' => 'blog_Blogs' ), 3, array( 'extension' ) );
return TRUE;
}
}
Whitespace-only changes.
@@ -1,73 +0,0 @@
<?php
/**
* @brief 4.0.9 Upgrade Code
* @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 Blog
* @since 19 Jun 2015
*/
namespace IPS\blog\setup\upg_100035;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* 4.0.9 Upgrade Code
*/
class _Upgrade
{
/**
* Update widgets
*
* @return array If returns TRUE, upgrader will proceed to next step. If it returns any other value, it will set this as the value of the 'extra' GET parameter and rerun this step (useful for loops)
*/
public function finish()
{
$areas = array( 'core_widget_areas' );
if ( \IPS\Application::appIsEnabled('cms') )
{
$areas[] = 'cms_page_widget_areas';
}
foreach ( $areas as $table )
{
foreach ( \IPS\Db::i()->select( '*', $table ) as $area )
{
$widgetsColumn = $table == 'core_widget_areas' ? 'widgets' : 'area_widgets';
$whereClause = $table == 'core_widget_areas' ? array( 'id=? AND area=?', $area['id'], $area['area'] ) : array( 'area_page_id=? AND area_area=?', $area['area_page_id'], $area['area_area'] );
$widgets = json_decode( $area[ $widgetsColumn ], TRUE );
$update = FALSE;
foreach ( $widgets as $k => $widget )
{
if ( $widget['key'] == 'recentEntries' )
{
$widgets[ $k ]['key'] = 'entryFeed';
if ( isset( $widgets[ $k ]['configuration']['number_to_show'] ) )
{
$widgets[ $k ]['configuration']['widget_feed_show'] = $widgets[ $k ]['configuration']['number_to_show'];
unset( $widgets[ $k ]['configuration']['number_to_show'] );
}
$update = TRUE;
}
if ( $update )
{
\IPS\Db::i()->update( $table, array( $widgetsColumn => json_encode( $widgets ) ), $whereClause );
}
}
}
}
return TRUE;
}
}
Whitespace-only changes.
@@ -1,13 +0,0 @@
{
"1": {
"method": "delete",
"params": [
"core_widgets",
[
"app=? AND `key`=?",
"blog",
"recentEntries"
]
]
}
}
Whitespace-only changes.
@@ -1,60 +0,0 @@
<?php
/**
* @brief 4.0.10 Upgrade Code
* @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 Blog
* @since 07 Jul 2015
*/
namespace IPS\blog\setup\upg_100038;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* 4.0.10 Upgrade Code
*/
class _Upgrade
{
/**
* Update future entry flag
*
* @return array If returns TRUE, upgrader will proceed to next step. If it returns any other value, it will set this as the value of the 'extra' GET parameter and rerun this step (useful for loops)
*/
public function step1()
{
if ( !\IPS\Db::i()->checkForColumn( 'blog_entries', 'entry_is_future_entry' ) )
{
\IPS\Db::i()->addColumn( 'blog_entries', array(
'name' => 'entry_is_future_entry',
'type' => "TINYINT",
'length' => 1,
'allow_null' => false,
'default' => "0",
'comment' => "Flag to show if an entry is set to be published in the future via the task",
'unsigned' => true,
) );
\IPS\Db::i()->update( 'blog_entries', array( 'entry_is_future_entry' => 1 ), array( "entry_date>? AND entry_status=?", time(), 'draft' ) );
}
return TRUE;
}
/**
* Custom title for this step
*
* @return string
*/
public function step1CustomTitle()
{
return "Updating blog future entry flag";
}
}
Whitespace-only changes.
@@ -1,26 +0,0 @@
{
"1": {
"method": "dropColumn",
"params": [
"blog_blogs",
"blog_view_level"
]
},
"2": {
"method": "changeIndex",
"params": [
"blog_blogs",
"blog_grabber",
{
"type": "key",
"name": "blog_grabber",
"length": [
null
],
"columns": [
"blog_disabled"
]
}
]
}
}
Whitespace-only changes.
@@ -1,70 +0,0 @@
{
"1": {
"method": "addColumn",
"params": [
"blog_blogs",
{
"name": "blog_name",
"type": "TEXT",
"length": null,
"decimals": null,
"values": [],
"allow_null": true,
"default": null,
"comment": "",
"unsigned": false,
"zerofill": false,
"auto_increment": false,
"binary": false
}
]
},
"2": {
"method": "addColumn",
"params": [
"blog_blogs",
{
"name": "blog_desc",
"type": "TEXT",
"length": null,
"decimals": null,
"values": [],
"allow_null": true,
"default": null,
"comment": "",
"unsigned": false,
"zerofill": false,
"auto_increment": false,
"binary": false
}
]
},
"3": {
"method": "dropColumn",
"params": [
"blog_blogs",
"blog_groupblog"
]
},
"4": {
"method": "dropIndex",
"params": [
"blog_blogs",
"auth_user"
]
},
"5": {
"method": "dropColumn",
"params": [
"blog_blogs",
"blog_authorized_users"
]
},
"6": {
"method": "dropColumn",
"params": [
"blog_blogs",
"blog_owner_only"
]
}
}
@@ -1,104 +0,0 @@
<?php
/**
* @brief 4.1.4 Upgrade Code
* @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 Blog
* @since 05 Nov 2015
*/
namespace IPS\blog\setup\upg_101016;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* 4.1.4 Upgrade Code
*/
class _Upgrade
{
/**
* Convert user blog name/desc to database
*
* @return array If returns TRUE, upgrader will proceed to next step. If it returns any other value, it will set this as the value of the 'extra' GET parameter and rerun this step (useful for loops)
*/
public function step1()
{
/* Some init */
$did = 0;
$limit = 0;
if( isset( \IPS\Request::i()->extra ) )
{
$limit = \IPS\Request::i()->extra;
}
/* Try to prevent timeouts to the extent possible */
$cutOff = \IPS\core\Setup\Upgrade::determineCutoff();
/* Get owned blogs - group blogs are still translatable */
foreach( \IPS\Db::i()->select( '*', 'blog_blogs', "blog_member_id > 0", 'blog_id ASC', array( $limit, 500 ) ) as $blog )
{
if( $cutOff !== null AND time() >= $cutOff )
{
return ( $limit + $did );
}
$did++;
$blog = \IPS\blog\Blog::constructFromData( $blog );
try
{
$language = \IPS\Lang::load( \IPS\Member::load( $blog->member_id )->language ?: \IPS\Lang::defaultLanguage() );
}
catch( \Exception $e )
{
$language = \IPS\Lang::load( \IPS\Lang::defaultLanguage() );
}
/* We will now store the name and desc in the blog_blogs table */
$blog->name = $language->get( 'blogs_blog_' . $blog->_id );
$blog->desc = $language->get( 'blogs_blog_' . $blog->_id . '_desc' );
$blog->save();
/* Remove the translatable language strings */
\IPS\Lang::deleteCustom( 'blog', 'blogs_blog_' . $blog->_id );
\IPS\Lang::deleteCustom( 'blog', 'blogs_blog_' . $blog->_id . '_desc' );
}
if( $did )
{
return $limit + $did;
}
else
{
unset( $_SESSION['_step1Count'] );
return TRUE;
}
}
/**
* Custom title for this step
*
* @return string
*/
public function step1CustomTitle()
{
$limit = isset( \IPS\Request::i()->extra ) ? \IPS\Request::i()->extra : 0;
if( !isset( $_SESSION['_step1Count'] ) )
{
$_SESSION['_step1Count'] = \IPS\Db::i()->select( 'COUNT(*)', 'blog_blogs', "blog_member_id > 0" )->first();
}
return "Converting blog names (Updated so far: " . ( ( $limit > $_SESSION['_step1Count'] ) ? $_SESSION['_step1Count'] : $limit ) . ' out of ' . $_SESSION['_step1Count'] . ')';
}
}
Whitespace-only changes.
@@ -1,23 +0,0 @@
{
"1": {
"method": "changeColumn",
"params": [
"blog_entries",
"entry_content",
{
"name": "entry_content",
"type": "MEDIUMTEXT",
"length": 0,
"decimals": null,
"values": [],
"allow_null": true,
"default": null,
"comment": "",
"unsigned": false,
"zerofill": false,
"auto_increment": false,
"binary": false
}
]
}
}
@@ -1,86 +0,0 @@
<?php
/**
* @brief 4.1.6 Upgrade Code
* @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 Blog
* @since 14 Dec 2015
*/
namespace IPS\blog\setup\upg_101021;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* 4.1.6 Upgrade Code
*/
class _Upgrade
{
/**
* Fix Blog RSS Feed Imports
*
* @return array If returns TRUE, upgrader will proceed to next step. If it returns any other value, it will set this as the value of the 'extra' GET parameter and rerun this step (useful for loops)
*/
public function step1()
{
$perCycle = 1000;
$did = 0;
$limit = \intval( \IPS\Request::i()->extra );
/* Try to prevent timeouts to the extent possible */
$cutOff = \IPS\core\Setup\Upgrade::determineCutoff();
foreach( \IPS\Db::i()->select( '*', 'blog_rss_import', array( "rss_member=?", 0 ), 'rss_id ASC', array( $limit, $perCycle ) ) as $rss )
{
if( $cutOff !== null AND time() >= $cutOff )
{
return ( $limit + $did );
}
$did++;
try
{
$blog = \IPS\blog\Blog::load( $rss['rss_blog_id'] );
\IPS\Db::i()->update( 'blog_rss_import', array( 'rss_member' => $blog->member_id ), array( "rss_id=?", $rss['rss_id'] ) );
}
catch( \Exception $e ){}
}
if ( $did )
{
return ( $limit + $did );
}
else
{
unset( $_SESSION['_step1Count'] );
return TRUE;
}
}
/**
* Custom title for this step
*
* @return string
*/
public function step1CustomTitle()
{
$limit = isset( \IPS\Request::i()->extra ) ? \IPS\Request::i()->extra : 0;
if( !isset( $_SESSION['_step1Count'] ) )
{
$_SESSION['_step1Count'] = \IPS\Db::i()->select( 'COUNT(*)', 'blog_rss_import', array( "rss_member=?", 0 ) )->first();
}
return "Fixing blog RSS imports (Upgraded so far: " . ( ( $limit > $_SESSION['_step1Count'] ) ? $_SESSION['_step1Count'] : $limit ) . ' out of ' . $_SESSION['_step1Count'] . ')';
}
}
Whitespace-only changes.
@@ -1,23 +0,0 @@
{
"1": {
"method": "changeColumn",
"params": [
"blog_blogs",
"blog_rating_average",
{
"name": "blog_rating_average",
"type": "DECIMAL",
"length": 11,
"decimals": 1,
"values": [],
"allow_null": false,
"default": "0",
"comment": "",
"unsigned": true,
"zerofill": false,
"auto_increment": false,
"binary": false
}
]
}
}
Whitespace-only changes.
@@ -1,9 +0,0 @@
{
"1": {
"method": "delete",
"params": [
"core_sys_lang_words",
"word_app='blog' AND word_key='immediately'"
]
}
}
Whitespace-only changes.
@@ -1,83 +0,0 @@
{
"1": {
"method": "addColumn",
"params": [
"blog_blogs",
{
"name": "blog_club_id",
"type": "BIGINT",
"length": 20,
"decimals": null,
"values": null,
"allow_null": true,
"default": null,
"comment": "The club ID if this blog belongs to a club, or NULL",
"unsigned": true,
"zerofill": false,
"auto_increment": false,
"binary": false
}
]
},
"2": {
"method": "addColumn",
"params": [
"blog_entries",
{
"name": "entry_meta_data",
"type": "BIT",
"length": 1,
"decimals": null,
"values": null,
"allow_null": false,
"default": "0",
"comment": "",
"unsigned": false,
"zerofill": false,
"auto_increment": false,
"binary": false
}
]
},
"3": {
"method": "addColumn",
"params": [
"blog_blogs",
{
"name": "blog_sidebar",
"type": "TEXT",
"length": null,
"decimals": null,
"values": null,
"allow_null": true,
"default": null,
"comment": "",
"unsigned": false,
"zerofill": false,
"auto_increment": false,
"binary": false
}
]
},
"4": {
"method": "changeColumn",
"params": [
"blog_entries",
"entry_name",
{
"name": "entry_name",
"type": "VARCHAR",
"length": 255,
"decimals": null,
"values": [],
"allow_null": true,
"default": null,
"comment": "",
"unsigned": false,
"zerofill": false,
"auto_increment": false,
"binary": false
}
]
}
}
Whitespace-only changes.
@@ -1,37 +0,0 @@
{
"1": {
"method": "addIndex",
"params": [
"blog_entries",
{
"type": "key",
"name": "entry_author_id",
"columns": [
"entry_author_id"
],
"length": [
null
]
}
]
},
"2": {
"method": "changeIndex",
"params": [
"blog_entries",
"entry_author_id",
{
"type": "key",
"name": "entry_author_id",
"columns": [
"entry_author_id",
"entry_last_update"
],
"length": [
null,
null
]
}
]
}
}
Loaded 100 of 6736 files, more files were not shown because too many files have changed in this diff. Show more