Version 4.5.0

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

No files matched your search

@@ -0,0 +1,65 @@
<?php
/**
* @brief GraphQL: ActiveUsers query
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Community Suite
* @since 10 May 2017
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\api\GraphQL\Queries;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\TypeRegistry;
/* 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;
}
/**
* OurPicks query for GraphQL API
*/
class _ActiveUsers
{
/*
* @brief Query description
*/
public static $description = "Returns active user information";
/*
* Query arguments
*/
public function args()
{
return array();
}
/**
* Return the query return type
*/
public function type()
{
return \IPS\core\api\GraphQL\TypeRegistry::activeUsers();
}
/**
* Resolves this query
*
* @param mixed Value passed into this resolver
* @return \IPS\core\Stream
*/
public function resolve($val)
{
if ( !\IPS\Member::loggedIn()->canAccessModule( \IPS\Application\Module::get( 'core', 'online', 'front' ) ) )
{
return NULL;
}
// There's no real value here, we're just passing on to the next resolver in the chain
return $val;
}
}
@@ -0,0 +1,62 @@
<?php
/**
* @brief GraphQL: Club query
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Community Suite
* @since 10 May 2017
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\api\GraphQL\Queries;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\TypeRegistry;
/* 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;
}
/**
* Club query for GraphQL API
*/
class _Club
{
/*
* @brief Query description
*/
public static $description = "Returns a club";
/*
* Query arguments
*/
public function args() {
return array(
'id' => TypeRegistry::nonNull( TypeRegistry::id() )
);
}
/**
* Return the query return type
*/
public function type()
{
return \IPS\core\api\GraphQL\TypeRegistry::club();
}
/**
* Resolves this query
*
* @param mixed Value passed into this resolver
* @param array Arguments
* @param array Context values
* @return \IPS\Member\Club
*/
public function resolve($val, $args, $context)
{
return \IPS\Member\Club::loadAndCheckPerms( $args['id'] );
}
}
@@ -0,0 +1,103 @@
<?php
/**
* @brief GraphQL: Content query
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Community Suite
* @since 10 May 2017
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\api\GraphQL\Queries;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\TypeRegistry;
/* 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;
}
/**
* Me query for GraphQL API
*/
class _Content
{
/*
* @brief Query description
*/
public static $description = "Return a generic piece of content";
/*
* Query arguments
*/
public function args()
{
return array(
'url' => TypeRegistry::nonNull( TypeRegistry::string() )
);
}
/**
* Return the query return type
*/
public function type()
{
return \IPS\Content\Api\GraphQL\TypeRegistry::content();
}
/**
* Resolves this query
*
* @param mixed Value passed into this resolver
* @param array Arguments
* @param array Context values
* @return \IPS\Member|null
*/
public function resolve($val, $args)
{
$url = \IPS\Http\Url::createFromString( $args['url'] );
if ( !isset( $url->hiddenQueryString['app'] ) )
{
throw new Exception('Not a valid URL');
}
foreach ( \IPS\Application::load( $url->hiddenQueryString['app'] )->extensions( 'core', 'ContentRouter' ) as $ext )
{
foreach ( $ext->classes as $class )
{
try
{
$object = $class::loadFromUrl( $url );
if ( isset( $url->queryString['do'] ) and $url->queryString['do'] === 'findComment' )
{
$commentClass = $object::$commentClass;
$object = $commentClass::load( $url->queryString['comment'] );
}
elseif ( isset( $url->queryString['do'] ) and $url->queryString['do'] === 'findReview' )
{
$reviewClass = $object::$reviewClass;
$object = $reviewClass::load( $url->queryString['review'] );
}
if ( !$object->canView( \IPS\Member::loggedIn() ) )
{
// No permission
return NULL;
}
return $object;
}
catch (\Exception $e)
{}
}
}
return NULL;
}
}
@@ -0,0 +1,64 @@
<?php
/**
* @brief GraphQL: Group query
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Community Suite
* @since 10 May 2017
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\api\GraphQL\Queries;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\TypeRegistry;
/* 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;
}
/**
* Group query for GraphQL API
*/
class _Group
{
/*
* @brief Query description
*/
public static $description = "Returns a member group";
/*
* @brief Query arguments
*/
public function args()
{
return array(
'id' => TypeRegistry::nonNull( TypeRegistry::id() )
);
}
/**
* Return the query return type
*/
public function type()
{
return \IPS\core\api\GraphQL\TypeRegistry::group();
}
/**
* Resolves this query
*
* @param mixed Value passed into this resolver
* @param array Arguments
* @param array Context values
* @return \IPS\Member\Group
*/
public function resolve($val, $args, $context)
{
return \IPS\Member\Group::load( $args['id'] );
}
}
@@ -0,0 +1,68 @@
<?php
/**
* @brief GraphQL: Language query
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Community Suite
* @since 10 May 2017
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\api\GraphQL\Queries;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\TypeRegistry;
/* 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;
}
/**
* Me query for GraphQL API
*/
class _Language
{
/*
* @brief Query description
*/
public static $description = "Return language data";
/*
* Query arguments
*/
public function args()
{
return array(
'id' => TypeRegistry::id()
);
}
/**
* Return the query return type
*/
public function type()
{
return \IPS\core\api\GraphQL\TypeRegistry::language();
}
/**
* Resolves this query
*
* @param mixed Value passed into this resolver
* @param array Arguments
* @param array Context values
* @return \IPS\Member|null
*/
public function resolve($val, $args)
{
if( isset( $args['id'] ) ){
return \IPS\Lang::load( $args['id'] );
}
return \IPS\Member::loggedIn()->language();
}
}
@@ -0,0 +1,65 @@
<?php
/**
* @brief GraphQL: Login handler query
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Community Suite
* @since 30 Oct 2018
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\api\GraphQL\Queries;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\TypeRegistry;
/* 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;
}
/**
* Login handler query for GraphQL API
*/
class _LoginHandlers
{
/*
* @brief Query description
*/
public static $description = "Return login handler data";
/*
* Query arguments
*/
public function args()
{
return array(
);
}
/**
* Return the query return type
*/
public function type()
{
return TypeRegistry::listOf( \IPS\core\api\GraphQL\TypeRegistry::login() );
}
/**
* Resolves this query
*
* @param mixed Value passed into this resolver
* @param array Arguments
* @param array Context values
* @return \IPS\Member|null
*/
public function resolve($val, $args)
{
$login = new \IPS\Login;
return $login->buttonMethods();
}
}
@@ -0,0 +1,62 @@
<?php
/**
* @brief GraphQL: 'Me' query
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Community Suite
* @since 10 May 2017
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\api\GraphQL\Queries;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\TypeRegistry;
/* 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;
}
/**
* Me query for GraphQL API
*/
class _Me
{
/*
* @brief Query description
*/
public static $description = "Return the logged-in member";
/*
* Query arguments
*/
public function args()
{
return array();
}
/**
* Return the query return type
*/
public function type()
{
return \IPS\core\api\GraphQL\TypeRegistry::member();
}
/**
* Resolves this query
*
* @param mixed Value passed into this resolver
* @param array Arguments
* @param array Context values
* @return \IPS\Member|null
*/
public function resolve($val, $args, $context)
{
return \IPS\Member::loggedIn();
}
}
@@ -0,0 +1,69 @@
<?php
/**
* @brief GraphQL: Member query
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Community Suite
* @since 10 May 2017
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\api\GraphQL\Queries;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\TypeRegistry;
/* 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 query for GraphQL API
*/
class _Member
{
/*
* @brief Query description
*/
public static $description = "Return a member";
/*
* Query arguments
*/
public function args()
{
return array(
'id' => TypeRegistry::id(),
'loggedIn' => TypeRegistry::boolean()
);
}
/**
* Return the query return type
*/
public function type()
{
return \IPS\core\api\GraphQL\TypeRegistry::member();
}
/**
* Resolves this query
*
* @param mixed Value passed into this resolver
* @param array Arguments
* @param array Context values
* @return \IPS\Member|null
*/
public function resolve($val, $args, $context)
{
if( isset( $args['loggedIn'] ) ){
return \IPS\Member::loggedIn();
} elseif ( isset( $args['id'] ) ){
return \IPS\Member::load( $args['id'] );
}
}
}
@@ -0,0 +1,72 @@
<?php
/**
* @brief GraphQL: Messenger conversation query
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Community Suite
* @since 25 Sep 2019
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\api\GraphQL\Queries;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\TypeRegistry;
/* 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;
}
/**
* Messenger conversation query for GraphQL API
*/
class _MessengerConversation
{
/*
* @brief Query description
*/
public static $description = "Returns a messenger conversation";
/*
* Query arguments
*/
public function args()
{
return array(
'id' => TypeRegistry::nonNull( TypeRegistry::id() )
);
}
/**
* Return the query return type
*/
public function type()
{
return \IPS\core\api\GraphQL\TypeRegistry::messengerConversation();
}
/**
* Resolves this query
*
* @param mixed Value passed into this resolver
* @param array Arguments
* @param array Context values
* @return \IPS\core\Messenger\Conversation
*/
public function resolve($val, $args, $context, $info)
{
try
{
$conversation = \IPS\core\Messenger\Conversation::loadAndCheckPerms( $args['id'] );
}
catch ( \OutOfRangeException $e )
{
throw new \IPS\Api\GraphQL\SafeException( 'NO_MESSAGE', '1F294/2', 400 );
}
return $conversation;
}
}
@@ -0,0 +1,245 @@
<?php
/**
* @brief GraphQL: Messenger conversation squery
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Community Suite
* @since 25 Sep 2019
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\api\GraphQL\Queries;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\TypeRegistry;
/* 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;
}
/**
* Messenger conversations query for GraphQL API
*/
class _MessengerConversations
{
/*
* @brief Query description
*/
public static $description = "Returns a list of messenger conversations";
/*
* Query arguments
*/
public function args()
{
return array(
'folder' => TypeRegistry::id(),
'filter' => [
'type' => TypeRegistry::eNum([
'name' => 'core_messengerConversations_filter',
'values' => ['MINE', 'NOT_MINE', 'READ', 'NOT_READ']
]),
'defaultValue' => NULL
],
'search' => TypeRegistry::string(),
'searchIn' => [
'type' => TypeRegistry::listOf(
TypeRegistry::eNum([
'name' => 'core_messengerConversations_searchIn',
'description' => 'Fields on which a conversation search can be applied',
'values' => ['TOPIC', 'POST', 'SENDER', 'RECIPIENT']
])
)
],
'offset' => [
'type' => TypeRegistry::int(),
'defaultValue' => 0
],
'limit' => [
'type' => TypeRegistry::int(),
'defaultValue' => 25
],
'orderBy' => [
'type' => TypeRegistry::eNum([
'name' => 'core_messengerConversations_orderBy',
'description' => 'Fields on which conversations can be sorted',
'values' => \IPS\core\api\GraphQL\Types\MessengerConversationType::getOrderByOptions()
]),
'defaultValue' => 'last_post_time'
],
'orderDir' => [
'type' => TypeRegistry::eNum([
'name' => 'core_messengerConversations_orderDir',
'description' => 'Directions in which items can be sorted',
'values' => [ 'ASC', 'DESC' ]
]),
'defaultValue' => 'DESC'
],
);
}
/**
* Return the query return type
*/
public function type()
{
return TypeRegistry::listOf( \IPS\core\api\GraphQL\TypeRegistry::messengerConversation() );
}
/**
* Resolves this query
*
* @param mixed Value passed into this resolver
* @param array Arguments
* @param array Context values
* @return \IPS\core\Messenger\Conversation
*/
public function resolve($val, $args, $context, $info)
{
// Start to build the query to fetch messages
$where = array( array( 'core_message_topic_user_map.map_user_id=? AND core_message_topic_user_map.map_user_active=1', \IPS\Member::loggedIn()->member_id ) );
$orderBy = 'mt_' . $args['orderBy'];
$offset = max( $args['limit'], 0 );
$limit = min( $args['limit'], 50 );
$iterator = NULL;
// Filters
if( !\is_null( $args['filter'] ) )
{
switch ($args['filter'] ) {
case "MINE":
$where[] = array( 'core_message_topic_user_map.map_is_starter=1' );
break;
case "NOT_MINE":
$where[] = array( 'core_message_topic_user_map.map_is_starter=0' );
break;
case "READ":
$where[] = array( 'core_message_topic_user_map.map_has_unread=0' );
break;
case "NOT_READ":
$where[] = array( 'core_message_topic_user_map.map_has_unread=1' );
break;
}
}
// Folder
if ( !\is_null( $args['folder'] ) )
{
$folderObj = \IPS\core\api\GraphQL\TypeRegistry::messengerFolder();
$folders = $folderObj->getMemberFolders();
if( isset( $folders[ $args['folder'] ] ) )
{
$where[] = array( 'core_message_topic_user_map.map_folder_id=?', $args['folder'] );
}
}
// Search
if( !\is_null( $args['search'] ) )
{
$subQuery = \IPS\Db::i()->select( 'map_topic_id', array( 'core_message_topic_user_map', 'core_message_topic_user_map' ), $where );
$where = array( array( 'core_message_posts.msg_topic_id IN (?)', $subQuery ) );
$query = array();
$prefix = \IPS\Db::i()->prefix;
if ( !\is_null( $args['searchIn'] ) )
{
if ( \in_array( 'TOPIC', $args['searchIn'] ) )
{
$query[] = \IPS\Content\Search\Mysql\Query::matchClause( "core_message_topics.mt_title", $args['search'], '+', FALSE );
}
if ( \in_array( 'POST', $args['searchIn'] ) )
{
$query[] = \IPS\Content\Search\Mysql\Query::matchClause( "core_message_posts.msg_post", $args['search'], '+', FALSE );
}
if ( \in_array( 'RECIPIENT', $args['searchIn'] ) )
{
$query[] = "core_message_posts.msg_topic_id IN ( SELECT sender_map.map_topic_id FROM {$prefix}core_message_topic_user_map AS sender_map WHERE sender_map.map_is_starter=1 AND sender_map.map_user_id IN ( SELECT member_id FROM {$prefix}core_members AS sm WHERE name LIKE '" . \IPS\Db::i()->escape_string( $args['search'] ) . "%' ) )";
}
if ( \in_array( 'SENDER', $args['searchIn'] ) )
{
$query[] = "core_message_posts.msg_topic_id IN ( SELECT receiver_map.map_topic_id FROM {$prefix}core_message_topic_user_map AS receiver_map WHERE receiver_map.map_is_starter=0 AND receiver_map.map_user_id IN ( SELECT member_id FROM {$prefix}core_members AS rm WHERE name LIKE '" . \IPS\Db::i()->escape_string( $args['search'] ) . "%') )";
}
if ( \count( $query ) )
{
$where[] = array( '(' . implode( ' OR ', $query ) . ')' );
}
}
/* Get a count */
try
{
$count = \IPS\Db::i()->select( 'COUNT(*)', 'core_message_posts', $where, NULL, NULL, 'msg_topic_id' )
->join(
'core_message_topics',
'core_message_posts.msg_topic_id=core_message_topics.mt_id'
)
->join(
'core_message_topic_user_map',
'core_message_topic_user_map.map_topic_id=core_message_topics.mt_id'
)
->first();
}
catch( \UnderflowException $e )
{
$count = 0;
}
/* Performance: if count is 0, don't bother selecting ... it's a wasted query */
if( $count )
{
/* Because of strict group by, we first need to select the ids, then grab those topics */
$iterator = \IPS\Db::i()->select(
'core_message_posts.msg_topic_id',
'core_message_posts',
$where,
$orderBy . ' ' . $args['orderDir'],
array( $offset, $limit ),
array( 'msg_topic_id', $orderBy )
)->join(
'core_message_topics',
'core_message_posts.msg_topic_id=core_message_topics.mt_id'
)->join(
'core_message_topic_user_map',
'core_message_topic_user_map.map_topic_id=core_message_topics.mt_id'
);
/* Get iterator */
$iterator = \IPS\Db::i()->select(
'core_message_topic_user_map.*, core_message_topics.*',
'core_message_topic_user_map',
array( 'map_topic_id IN(' . implode( ',', iterator_to_array( $iterator ) ) . ')' ),
$orderBy . ' ' . $args['orderDir']
)->join(
'core_message_topics',
'core_message_topic_user_map.map_topic_id=core_message_topics.mt_id'
);
}
}
else
{
/* Get iterator */
$iterator = \IPS\Db::i()->select(
'core_message_topic_user_map.*, core_message_topics.*',
'core_message_topic_user_map',
$where,
$orderBy . ' ' . $args['orderDir'],
array( $offset, $limit )
)->join(
'core_message_topics',
'core_message_topic_user_map.map_topic_id=core_message_topics.mt_id'
);
}
if( $iterator )
{
return new \IPS\Patterns\ActiveRecordIterator( $iterator, 'IPS\core\Messenger\Conversation' );
}
return array();
}
}
@@ -0,0 +1,69 @@
<?php
/**
* @brief GraphQL: Messenger conversation query
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Community Suite
* @since 25 Sep 2019
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\api\GraphQL\Queries;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\TypeRegistry;
/* 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;
}
/**
* Messenger folders query for GraphQL API
*/
class _MessengerFolders
{
/*
* @brief Query description
*/
public static $description = "Returns the member's messenger folders";
/*
* Query arguments
*/
public function args()
{
return array(
);
}
/**
* Return the query return type
*/
public function type()
{
return TypeRegistry::listOf( \IPS\core\api\GraphQL\TypeRegistry::messengerFolder() );
}
/**
* Resolves this query
*
* @param mixed Value passed into this resolver
* @param array Arguments
* @param array Context values
* @return \IPS\core\Messenger\Conversation
*/
public function resolve($val, $args, $context, $info)
{
if( !\IPS\Member::loggedIn()->member_id || \IPS\Member::loggedIn()->members_disable_pm )
{
return NULL;
}
$folderObj = \IPS\core\api\GraphQL\TypeRegistry::messengerFolder();
return $folderObj->getMemberFolders();
}
}
@@ -0,0 +1,81 @@
<?php
/**
* @brief GraphQL: Mobile menu query
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Community Suite
* @since 12 June 2019
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\api\GraphQL\Queries;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\TypeRegistry;
/* 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;
}
/**
* Mobile menu query for GraphQL API
*/
class _MobileMenu
{
/*
* @brief Query description
*/
public static $description = "Returns details of the mobile app menu";
/*
* Query arguments
*/
public function args()
{
return array();
}
/**
* Return the query return type
*/
public function type()
{
return TypeRegistry::listOf( \IPS\core\api\GraphQL\TypeRegistry::mobileMenu() );
}
/**
* Resolves this query
*
* @param mixed Value passed into this resolver
* @param array Arguments
* @param array Context values
* @return array
*/
public function resolve($val, $args, $context)
{
$return = array();
foreach ( \IPS\Db::i()->select( '*', 'core_mobileapp_menu', NULL, 'position' ) as $item )
{
if ( \IPS\Application::appIsEnabled( $item['app'] ) )
{
$class = 'IPS\\' . $item['app'] . '\extensions\core\MobileNavigation\\' . $item['extension'];
if ( class_exists( $class ) )
{
$object = new $class( json_decode( $item['config'], TRUE ), $item['id'], $item['permissions'] );
if ( $object->canView() )
{
$return[ $item['id'] ] = $object;
}
}
}
}
return $return;
}
}
@@ -0,0 +1,107 @@
<?php
/**
* @brief GraphQL: Notification types query
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Community Suite
* @since 30 Jan 2019
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\api\GraphQL\Queries;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\TypeRegistry;
/* 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;
}
/**
* NotificationTypes query for GraphQL API
*/
class _NotificationTypes
{
/*
* @brief Query description
*/
public static $description = "Returns available notification types";
/*
* Query arguments
*/
public function args()
{
return array();
}
/**
* Return the query return type
*/
public function type()
{
return TypeRegistry::listOf( \IPS\core\api\GraphQL\TypeRegistry::notificationType() );
}
/**
* Resolves this query
*
* @param mixed Value passed into this resolver
* @param array Arguments
* @param array Context values
* @return \IPS\core\Stream
*/
public function resolve($val, $args, $context)
{
//$defaultConfiguration = \IPS\Notification::defaultConfiguration();
//$memberConfiguration = $member->notificationsConfiguration();
$notificationTypes = array();
$extensions = \IPS\Application::allExtensions( 'core', 'Notifications' );
$availableOptions = array();
foreach( $extensions as $extensionKey => $extension )
{
$extensionOptions = \IPS\Notification::availableOptions( \IPS\Member::loggedIn(), $extension );
foreach( $extensionOptions as $key => $option )
{
// For now, only return 'standard' types, which are the email/inline/push options
if( $option['type'] !== 'standard' )
{
continue;
}
$methods = array('inline' => array(), 'email' => array(), 'push' => array());
foreach( $methods as $method => $methodData )
{
if( !isset( $option['options'][ $method ] ) )
{
continue;
}
$methods[ $method ]['default'] = isset( $option['default'] ) && \in_array( $method, $option['default'] );
$methods[ $method ]['disabled'] = isset( $option['disabled'] ) && \in_array( $method, $option['disabled'] );
$methods[ $method ]['member'] = isset( $option['options'][ $method ] ) && $option['options'][ $method ]['value'] == TRUE;
}
$notificationTypes[] = array(
'id' => $extensionKey === $key ? $extensionKey : $extensionKey . '_' . $key,
'extension' => $extensionKey,
'type' => $key,
'name' => $option['title'],
'description' => $option['description'],
'inline' => $methods['inline'],
'email' => $methods['email'],
'push' => $methods['push']
);
}
}
return $notificationTypes;
}
}
@@ -0,0 +1,75 @@
<?php
/**
* @brief GraphQL: OurPicks query
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Community Suite
* @since 10 May 2017
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\api\GraphQL\Queries;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\TypeRegistry;
/* 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;
}
/**
* OurPicks query for GraphQL API
*/
class _OurPicks
{
/*
* @brief Query description
*/
public static $description = "Returns promoted items";
/*
* Query arguments
*/
public function args()
{
return array(
'count' => TypeRegistry::int()
);
}
/**
* Return the query return type
*/
public function type()
{
return TypeRegistry::listOf( \IPS\core\api\GraphQL\TypeRegistry::promotedItem() );
}
/**
* Resolves this query
*
* @param mixed Value passed into this resolver
* @param array Arguments
* @param array Context values
* @return \IPS\core\Stream
*/
public function resolve($val, $args, $context)
{
$limit = 7;
if( isset( $args['count'] ) && \is_int( $args['count'] ) )
{
$limit = $args['count'];
}
$items = \IPS\core\Promote::internalStream( $limit );
if( !\count( $items ) )
{
return NULL;
}
return $items;
}
}
@@ -0,0 +1,119 @@
<?php
/**
* @brief GraphQL: PopularContributors query
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Community Suite
* @since 11 Feb 2019
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\api\GraphQL\Queries;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\TypeRegistry;
/* 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;
}
/**
* PopularContributors query for GraphQL API
*/
class _PopularContributors
{
/*
* @brief Query description
*/
public static $description = "Returns popular contributors";
/*
* Query arguments
*/
public function args()
{
return array(
'limit' => [
'type' => TypeRegistry::int(),
'defaultValue' => 5
],
'period' => [
'type' => TypeRegistry::eNum([
'name' => 'core_PopularContributors_period',
'values' => ['WEEK', 'MONTH', 'YEAR', 'ALL']
]),
'defaultValue' => 'WEEK'
]
);
}
/**
* Return the query return type
*/
public function type()
{
return TypeRegistry::listOf( \IPS\core\api\GraphQL\TypeRegistry::popularContributor() );
}
/**
* Resolves this query
*
* @param mixed Value passed into this resolver
* @param array Arguments
* @param array Context values
* @return \IPS\core\Stream
*/
public function resolve($val, $args, $context)
{
/* How many? */
$limit = min( $args['limit'], 25 );
/* What timeframe? */
$where = array( array( 'member_received > 0' ) );
$timeframe = 'all';
if ( $args['period'] !== 'ALL' )
{
switch ( $args['period'] )
{
case 'WEEK':
$where[] = array( 'rep_date>' . \IPS\DateTime::create()->sub( new \DateInterval( 'P1W' ) )->getTimestamp() );
break;
case 'MONTH':
$where[] = array( 'rep_date>' . \IPS\DateTime::create()->sub( new \DateInterval( 'P1M' ) )->getTimestamp() );
break;
case 'YEAR':
$where[] = array( 'rep_date>' . \IPS\DateTime::create()->sub( new \DateInterval( 'P1Y' ) )->getTimestamp() );
break;
}
$innerQuery = \IPS\Db::i()->select( 'core_reputation_index.member_received as member, SUM(rep_rating) as rep', 'core_reputation_index', $where, NULL, NULL, 'member' );
$topContributors = iterator_to_array( \IPS\Db::i()->select( 'member, rep', array( $innerQuery, 'in' ), NULL, 'rep DESC', $limit )->setKeyField('member')->setValueField('rep') );
}
else
{
$topContributors = iterator_to_array( \IPS\Db::i()->select( 'member_id as member, pp_reputation_points as rep', 'core_members', array( 'pp_reputation_points > 0' ), 'rep DESC', $limit )->setKeyField('member')->setValueField('rep') );
}
/* Contruct their data */
/* The PopularContributorsType will call ::load on the member ID to get the object */
foreach ( \IPS\Db::i()->select( '*', 'core_members', \IPS\Db::i()->in( 'member_id', array_keys( $topContributors ) ) ) as $member )
{
\IPS\Member::constructFromData( $member );
}
$output = array();
foreach ( $topContributors as $memberID => $rep )
{
$output[] = array(
'rep' => $rep,
'member_id' => $memberID
);
}
return $output;
}
}
@@ -0,0 +1,189 @@
<?php
/**
* @brief GraphQL: Search query
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Community Suite
* @since 22 Sep 2018
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\api\GraphQL\Queries;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\TypeRegistry;
/* 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;
}
/**
* Search query for GraphQL API
*/
class _Search
{
/*
* @brief Query description
*/
public static $description = "Returns search results";
/*
* Query arguments
*/
public function args()
{
return array(
'term' => TypeRegistry::string(),
'type' => [
'type' => TypeRegistry::eNum([
'name' => 'core_search_types_input',
'description' => "The available search types",
'values' => array_merge( array('core_members'), array_keys( \IPS\core\modules\front\search\search::contentTypes() ) )
]),
],
'offset' => [
'type' => TypeRegistry::int(),
'defaultValue' => 0
],
'limit' => [
'type' => TypeRegistry::int(),
'defaultValue' => 25
],
'orderBy' => [
'type' => TypeRegistry::eNum([
'name' => 'core_search_order_by',
'description' => 'Fields on which reuslts can be sorted',
'values' => [ 'newest', 'relevancy', 'joined', 'name', 'member_posts', 'pp_reputation_points' ]
])
],
'orderDir' => [
'type' => TypeRegistry::eNum([
'name' => 'core_search_order_dir',
'description' => 'Directions in which reuslts can be sorted',
'values' => [ 'ASC', 'DESC' ]
]),
'defaultValue' => 'DESC'
],
);
}
/**
* Return the query return type
*/
public function type()
{
return \IPS\core\api\GraphQL\TypeRegistry::search();
}
/**
* Resolves this query
*
* @param mixed Value passed into this resolver
* @param array Arguments
* @param array Context values
* @return \IPS\core\Stream
*/
public function resolve($val, $args, $context)
{
$where = array();
$returnObject = array();
$offset = max( $args['offset'], 0 );
$limit = min( $args['limit'], 50 );
// Member search
if ( isset( $args['type'] ) and $args['type'] === 'core_members' and \IPS\Member::loggedIn()->canAccessModule( \IPS\Application\Module::get( 'core', 'members', 'front' ) ) )
{
if ( $args['term'] )
{
$where = array( array( 'LOWER(core_members.name) LIKE ?', '%' . mb_strtolower( trim( $args['term'] ) ) . '%' ) );
}
else
{
$where = array( array( 'core_members.name<>?', '' ) );
}
// Ordering
$orderDir = isset( $args['orderDir'] ) ? $args['orderDir'] : 'DESC';
$orderBy = 'name';
if( isset( $args['orderBy'] ) && \in_array( $args['orderBy'], array( 'joined', 'name', 'member_posts', 'pp_reputation_points' ) ) )
{
$orderBy = $args['orderBy'];
}
$order = $orderBy . ' ' . $orderDir;
// Get results
$select = \IPS\Db::i()->select( 'COUNT(*)', 'core_members', $where );
$select->join( 'core_pfields_content', 'core_pfields_content.member_id=core_members.member_id' );
$returnObject['count'] = $select->first();
$select = \IPS\Db::i()->select( 'core_members.*', 'core_members', $where, $order, array( $offset, $limit ) );
$select->join( 'core_pfields_content', 'core_pfields_content.member_id=core_members.member_id' );
$returnObject['results'] = new \IPS\Patterns\ActiveRecordIterator( $select, 'IPS\Member' );
return $returnObject;
}
// Content search
$query = \IPS\Content\Search\Query::init();
$types = \IPS\core\modules\front\search\search::contentTypes();
if( isset( $args['type'] ) && !empty( $args['type'] ) )
{
$class = $types[ $args['type'] ];
$filter = \IPS\Content\Search\ContentFilter::init( $class );
$query->filterByContent( array( $filter ) );
}
$orderBy = $query->getDefaultSortMethod();
// Ordering
if( isset( $args['orderBy'] ) )
{
switch( $args['orderBy'] )
{
case 'newest':
$query->setOrder( \IPS\Content\Search\Query::ORDER_NEWEST_CREATED );
break;
case 'relevancy':
$query->setOrder( \IPS\Content\Search\Query::ORDER_RELEVANCY );
break;
default:
$query->setOrder( $orderBy );
break;
}
}
else
{
$query->setOrder( $orderBy );
}
// Get page
// We don't know the count at this stage, so figure out the page number from
// our offset/limit
$page = 1;
if( $offset > 0 )
{
$page = floor( $offset / $limit ) + 1;
}
$query->setLimit( $limit )->setPage( $page );
/* Run query */
$returnObject['results'] = $query->search(
isset( $args['term'] ) ? ( $args['term'] ) : NULL,
NULL,
\IPS\Content\Search\Query::TERM_AND_TAGS + \IPS\Content\Search\Query::TAGS_MATCH_ITEMS_ONLY,
NULL
);
$returnObject['count'] = $returnObject['results']->count( TRUE );
return $returnObject;
}
}
@@ -0,0 +1,62 @@
<?php
/**
* @brief GraphQL: Settings query
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Community Suite
* @since 10 May 2017
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\api\GraphQL\Queries;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\TypeRegistry;
/* 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;
}
/**
* Settings query for GraphQL API
*/
class _Settings
{
/*
* @brief Query description
*/
public static $description = "Returns values of system settings (subject to the setting being exposed by the API)";
/*
* Query arguments
*/
public function args()
{
return array();
}
/**
* Return the query return type
*/
public function type()
{
return \IPS\core\api\GraphQL\TypeRegistry::settings();
}
/**
* Resolves this query
*
* @param mixed Value passed into this resolver
* @param array Arguments
* @param array Context values
* @return \IPS\Settings
*/
public function resolve($val, $args, $context)
{
return \IPS\Settings::i();
}
}
@@ -0,0 +1,86 @@
<?php
/**
* @brief GraphQL: Stream query
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Community Suite
* @since 10 May 2017
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\api\GraphQL\Queries;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\TypeRegistry;
/* 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;
}
/**
* Stream query for GraphQL API
*/
class _Stream
{
/*
* @brief Query description
*/
public static $description = "Returns an activity stream";
/*
* Query arguments
*/
public function args()
{
return array(
'id' => TypeRegistry::id()
);
}
/**
* Return the query return type
*/
public function type()
{
return \IPS\core\api\GraphQL\TypeRegistry::stream();
}
/**
* Resolves this query
*
* @param mixed Value passed into this resolver
* @param array Arguments
* @param array Context values
* @return \IPS\core\Stream
*/
public function resolve($val, $args, $context)
{
if( isset( $args['id'] ) && \intval( $args['id'] ) )
{
try
{
$stream = \IPS\core\Stream::load( $args['id'] );
}
catch ( \OutOfRangeException $e )
{
return NULL;
}
/* Suitable for guests? */
if ( !\IPS\Member::loggedIn()->member_id and !( ( $stream->ownership == 'all' or $stream->ownership == 'custom' ) and $stream->read == 'all' and $stream->follow == 'all' and $stream->date_type != 'last_visit' ) )
{
throw new \IPS\Api\GraphQL\SafeException( 'INVALID_STREAM', 'GQL/0003/1', 403 );
}
}
else
{
/* Start with a blank stream */
$stream = \IPS\core\Stream::allActivityStream();
}
return $stream;
}
}
@@ -0,0 +1,80 @@
<?php
/**
* @brief GraphQL: Streams query
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Community Suite
* @since 10 May 2017
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\api\GraphQL\Queries;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\TypeRegistry;
/* 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;
}
/**
* Streams query for GraphQL API
*/
class _Streams
{
/*
* @brief Query description
*/
public static $description = "Returns a list of user's activity streams";
/*
* @brief Query arguments
*/
public function args()
{
return array();
}
/**
* Return the query return type
*/
public function type()
{
return TypeRegistry::listOf( \IPS\core\api\GraphQL\TypeRegistry::stream() );
}
/**
* Resolves this query
*
* @param mixed Value passed into this resolver
* @param array Arguments
* @param array Context values
* @return array
*/
public function resolve($val, $args, $context)
{
$streams = array();
foreach ( new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'core_streams', '`member` IS NULL', 'position ASC' ), 'IPS\core\Stream' ) as $stream )
{
if( \IPS\Member::loggedIn()->member_id || ( !\IPS\Member::loggedIn()->member_id && ( $stream->ownership == 'all' and $stream->read == 'all' and $stream->follow == 'all' and $stream->date_type != 'last_visit' ) ) )
{
$streams[ $stream->id ] = $stream;
}
}
if ( \IPS\Member::loggedIn()->member_id )
{
foreach ( new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'core_streams', array( '`member`=?', \IPS\Member::loggedIn()->member_id ), 'position ASC' ), 'IPS\core\Stream' ) as $stream )
{
$streams[ $stream->id ] = $stream;
}
}
return $streams;
}
}