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

+25 -16
View File
@@ -10,39 +10,48 @@
*/
namespace IPS\core\api\GraphQL;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\Types;
use IPS\core\api\GraphQL\Mutations\ChangeNotificationSetting;
use IPS\core\api\GraphQL\Mutations\DeleteAttachment;
use IPS\core\api\GraphQL\Mutations\Follow;
use IPS\core\api\GraphQL\Mutations\IgnoreUser;
use IPS\core\api\GraphQL\Mutations\MarkNotificationRead;
use IPS\core\api\GraphQL\Mutations\Messenger\AddConversationUser;
use IPS\core\api\GraphQL\Mutations\Messenger\LeaveConversation;
use IPS\core\api\GraphQL\Mutations\Messenger\RemoveConversationUser;
use IPS\core\api\GraphQL\Mutations\Unfollow;
use IPS\core\api\GraphQL\Mutations\UploadAttachment;
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;
}
/**
* Core mutationss GraphQL API
*/
abstract class _Mutation
abstract class Mutation
{
/**
* Get the supported query types in this app
*
* @return array
*/
public static function mutations()
public static function mutations() : array
{
return [
'follow' => new \IPS\core\api\GraphQL\Mutations\Follow(),
'unfollow' => new \IPS\core\api\GraphQL\Mutations\Unfollow(),
'markNotificationRead' => new \IPS\core\api\GraphQL\Mutations\MarkNotificationRead(),
'uploadAttachment' => new \IPS\core\api\GraphQL\Mutations\UploadAttachment(),
'deleteAttachment' => new \IPS\core\api\GraphQL\Mutations\DeleteAttachment(),
'ignoreMember' => new \IPS\core\api\GraphQL\Mutations\IgnoreUser(),
'changeNotificationSetting' => new \IPS\core\api\GraphQL\Mutations\ChangeNotificationSetting(),
'leaveConversation' => new \IPS\core\api\GraphQL\Mutations\Messenger\LeaveConversation(),
'removeConversationUser' => new \IPS\core\api\GraphQL\Mutations\Messenger\RemoveConversationUser(),
'addConversationUser' => new \IPS\core\api\GraphQL\Mutations\Messenger\AddConversationUser(),
'follow' => new Follow(),
'unfollow' => new Unfollow(),
'markNotificationRead' => new MarkNotificationRead(),
'uploadAttachment' => new UploadAttachment(),
'deleteAttachment' => new DeleteAttachment(),
'ignoreMember' => new IgnoreUser(),
'changeNotificationSetting' => new ChangeNotificationSetting(),
'leaveConversation' => new LeaveConversation(),
'removeConversationUser' => new RemoveConversationUser(),
'addConversationUser' => new AddConversationUser(),
];
}
}
@@ -10,25 +10,33 @@
*/
namespace IPS\core\api\GraphQL\Mutations;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\SafeException;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\Application;
use IPS\core\api\GraphQL\Types\NotificationTypeType;
use IPS\Db;
use IPS\Member;
use IPS\Notification;
use function count;
use function defined;
use function in_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;
}
/**
* Change notification setting mutation for GraphQL API
*/
class _ChangeNotificationSetting
class ChangeNotificationSetting
{
/*
* @brief Query description
*/
public static $description = "Change a notification setting";
public static string $description = "Change a notification setting";
/*
* Mutation arguments
@@ -47,46 +55,47 @@ class _ChangeNotificationSetting
/**
* Return the mutation return type
*
* @return NotificationTypeType
*/
public function type()
public function type() : NotificationTypeType
{
return \IPS\core\Api\GraphQL\TypeRegistry::notificationType();
}
/**
* Resolves this mutation
* 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
* @return array
*/
public function resolve($val, $args)
public function resolve( mixed $val, array $args ) : array
{
if( !\IPS\Member::loggedIn()->member_id )
if( !Member::loggedIn()->member_id )
{
throw new \IPS\Api\GraphQL\SafeException( 'NOT_LOGGED_IN', 'GQL/0003/1', 403 );
throw new SafeException( 'NOT_LOGGED_IN', 'GQL/0003/1', 403 );
}
$pieces = explode('_', $args['extension']);
if( \count( $pieces ) !== 2 )
if( count( $pieces ) !== 2 )
{
throw new \IPS\Api\GraphQL\SafeException( 'INVALID_EXTENSION', 'GQL/0003/1', 403 );
throw new SafeException( 'INVALID_EXTENSION', 'GQL/0003/1', 403 );
}
$extensions = \IPS\Application::load( $pieces[0] )->extensions('core', 'Notifications');
$extensions = Application::load( $pieces[0] )->extensions('core', 'Notifications');
if( !isset( $extensions[ $pieces[1] ] ) )
{
throw new \IPS\Api\GraphQL\SafeException( 'INVALID_EXTENSION', 'GQL/0003/1', 403 );
throw new SafeException( 'INVALID_EXTENSION', 'GQL/0003/1', 403 );
}
$extensionOptions = \IPS\Notification::availableOptions( \IPS\Member::loggedIn(), $extensions[ $pieces[1] ] );
$extensionOptions = Notification::availableOptions( Member::loggedIn(), $extensions[ $pieces[1] ] );
if( !isset( $extensionOptions[ $args['type'] ] ) || $extensionOptions[ $args['type'] ]['type'] !== 'standard' ) // Only standard types supported right now
{
throw new \IPS\Api\GraphQL\SafeException( 'INVALID_TYPE', 'GQL/0003/1', 403 );
throw new SafeException( 'INVALID_TYPE', 'GQL/0003/1', 403 );
}
$value = array();
@@ -98,7 +107,7 @@ class _ChangeNotificationSetting
// If the mutation is trying to change a setting...
if( isset( $args[ $type ] ) )
{
if( $args[ $type ] === TRUE && $typeSettings['editable'] == TRUE && !\in_array( $type, $extensionType['disabled'] ) )
if( $args[ $type ] === TRUE && $typeSettings['editable'] == TRUE && !in_array( $type, $extensionType['disabled'] ) )
{
$value[ $type ] = $type;
}
@@ -118,8 +127,8 @@ class _ChangeNotificationSetting
foreach ( $extensionType['notificationTypes'] as $notificationKey )
{
\IPS\Db::i()->insert( 'core_notification_preferences', array(
'member_id' => \IPS\Member::loggedIn()->member_id,
Db::i()->insert( 'core_notification_preferences', array(
'member_id' => Member::loggedIn()->member_id,
'notification_key' => $notificationKey,
'preference' => implode( ',', $value )
), TRUE );
@@ -136,8 +145,8 @@ class _ChangeNotificationSetting
}
$option = $options[ $method ];
$methods[ $method ]['default'] = isset( $option['default'] ) && \in_array( $method, $option['default'] );
$methods[ $method ]['disabled'] = isset( $option['disabled'] ) && \in_array( $method, $option['disabled'] );
$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( $value[ $method ] );
}
@@ -10,25 +10,32 @@
*/
namespace IPS\core\api\GraphQL\Mutations;
use GraphQL\Type\Definition\ObjectType;
use Exception;
use GraphQL\Type\Definition\BooleanType;
use IPS\Api\GraphQL\SafeException;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\Db;
use IPS\File;
use IPS\Member;
use UnderflowException;
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;
}
/**
* Delete attachment mutation for GraphQL API
*/
class _DeleteAttachment
class DeleteAttachment
{
/*
* @brief Query description
*/
public static $description = "Delete an attachment";
public static string $description = "Delete an attachment";
/*
* Mutation arguments
@@ -46,8 +53,10 @@ class _DeleteAttachment
/**
* Return the mutation return type
*
* @return BooleanType
*/
public function type()
public function type() : BooleanType
{
return TypeRegistry::boolean();
}
@@ -55,21 +64,22 @@ class _DeleteAttachment
/**
* Resolves this mutation
*
* @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 bool
*/
public function resolve($val, $args, $context, $info)
public function resolve( mixed $val, array $args, array $context, array $info ) : bool
{
/* Get the attachment */
try
{
$attachment = \IPS\Db::i()->select( '*', 'core_attachments', array( 'attach_id=?', $args['id'] ) )->first();
$attachment = Db::i()->select( '*', 'core_attachments', array( 'attach_id=?', $args['id'] ) )->first();
}
catch ( \UnderflowException $e )
catch ( UnderflowException $e )
{
throw new \IPS\Api\GraphQL\SafeException( 'NO_ATTACHMENT', 'GQL/0004/1', 404 );
throw new SafeException( 'NO_ATTACHMENT', 'GQL/0004/1', 404 );
}
/* Delete the maps - Only do this for attachments that have actually been saved (if they haven't been saved, there's nothing in core_attachments_map for us to delete */
@@ -85,34 +95,34 @@ class _DeleteAttachment
}
}
\IPS\Db::i()->delete( 'core_attachments_map', $where );
Db::i()->delete( 'core_attachments_map', $where );
}
else
{
/* If the attachment hasn't been claimed yet, it should only be deletable by the person who uploaded it */
if( $attachment['attach_member_id'] != \IPS\Member::loggedIn()->member_id )
if( $attachment['attach_member_id'] != Member::loggedIn()->member_id )
{
throw new \IPS\Api\GraphQL\SafeException( 'CANNOT_DELETE_OTHERS_ATTACHMENTS', 'GQL/0004/2', 403 );
throw new SafeException( 'CANNOT_DELETE_OTHERS_ATTACHMENTS', 'GQL/0004/2', 403 );
}
}
/* If there's no other maps, we can delete the attachment itself */
$otherMaps = \IPS\Db::i()->select( 'COUNT(*)', 'core_attachments_map', array( 'attachment_id=?', $attachment['attach_id'] ) )->first();
$otherMaps = Db::i()->select( 'COUNT(*)', 'core_attachments_map', array( 'attachment_id=?', $attachment['attach_id'] ) )->first();
if ( !$otherMaps )
{
\IPS\Db::i()->delete( 'core_attachments', array( 'attach_id=?', $attachment['attach_id'] ) );
Db::i()->delete( 'core_attachments', array( 'attach_id=?', $attachment['attach_id'] ) );
try
{
\IPS\File::get( 'core_Attachment', $attachment['attach_location'] )->delete();
File::get( 'core_Attachment', $attachment['attach_location'] )->delete();
}
catch ( \Exception $e ) { }
catch ( Exception $e ) { }
if ( $attachment['attach_thumb_location'] )
{
try
{
\IPS\File::get( 'core_Attachment', $attachment['attach_thumb_location'] )->delete();
File::get( 'core_Attachment', $attachment['attach_thumb_location'] )->delete();
}
catch ( \Exception $e ) { }
catch ( Exception $e ) { }
}
}
@@ -10,25 +10,40 @@
*/
namespace IPS\core\api\GraphQL\Mutations;
use GraphQL\Type\Definition\ObjectType;
use InvalidArgumentException;
use IPS\Api\GraphQL\SafeException;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\Api\GraphQL\Types\FollowType;
use IPS\Application;
use IPS\Content;
use IPS\core\Followed\Follow as FollowClass;
use IPS\Db;
use IPS\IPS;
use IPS\Member;
use IPS\Node\Model;
use IPS\Notification;
use OutOfRangeException;
use UnderflowException;
use function defined;
use function get_class;
use function in_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;
}
/**
* Follow something mutation for GraphQL API
*/
class _Follow
class Follow
{
/*
* @brief Query description
*/
public static $description = "Follow a node, item or member";
public static string $description = "Follow a node, item or member";
/*
* Mutation arguments
@@ -50,8 +65,10 @@ class _Follow
/**
* Return the mutation return type
*
* @return FollowType
*/
public function type()
public function type() : FollowType
{
return TypeRegistry::follow();
}
@@ -61,46 +78,45 @@ class _Follow
* @todo this is basically copied and pasted from notifications.php which isn't ideal, so we
* might want to consider refactoring to abstract this functionality.
*
* @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
* @return array
*/
public function resolve($val, $args)
public function resolve( mixed $val, array $args ) : array
{
if( !\IPS\Member::loggedIn()->member_id )
if( !Member::loggedIn()->member_id )
{
throw new \IPS\Api\GraphQL\SafeException( 'NOT_LOGGED_IN', 'GQL/0001/6', 403 );
throw new SafeException( 'NOT_LOGGED_IN', 'GQL/0001/6', 403 );
}
/* Get class */
try
{
$class = \IPS\core\Followed\Follow::getClassToFollow( $args['app'], $args['area'] );
$class = FollowClass::getClassToFollow( $args['app'], $args['area'] );
}
catch( \InvalidArgumentException $e )
catch( InvalidArgumentException $e )
{
throw new \IPS\Api\GraphQL\SafeException( 'NOT_FOUND', 'GQL/0001/4', 404 );
throw new SafeException( 'NOT_FOUND', 'GQL/0001/4', 404 );
}
if( $args['app'] == 'core' and $args['area'] == 'member' )
{
/* You can't follow yourself */
if( $args['id'] == \IPS\Member::loggedIn()->member_id )
if( $args['id'] == Member::loggedIn()->member_id )
{
throw new \IPS\Api\GraphQL\SafeException( 'CANT_FOLLOW_SELF', 'GQL/0001/1', 403 );
throw new SafeException( 'CANT_FOLLOW_SELF', 'GQL/0001/1', 403 );
}
/* Following disabled */
$member = \IPS\Member::load( $args['id'] );
$member = Member::load( $args['id'] );
if( !$member->member_id )
{
throw new \IPS\Api\GraphQL\SafeException( 'CANT_FOLLOW_MEMBER', 'GQL/0001/2', 403 );
throw new SafeException( 'CANT_FOLLOW_MEMBER', 'GQL/0001/2', 403 );
}
if( $member->members_bitoptions['pp_setting_moderate_followers'] and !\IPS\Member::loggedIn()->following( 'core', 'member', $member->member_id ) )
if( $member->members_bitoptions['pp_setting_moderate_followers'] and !Member::loggedIn()->following( 'core', 'member', $member->member_id ) )
{
throw new \IPS\Api\GraphQL\SafeException( 'CANT_FOLLOW_MEMBER', 'GQL/0001/3', 403 );
throw new SafeException( 'CANT_FOLLOW_MEMBER', 'GQL/0001/3', 403 );
}
}
@@ -115,49 +131,54 @@ class _Follow
$thing = NULL;
try
{
if ( \in_array( 'IPS\Node\Model', class_parents( $class ) ) )
if ( in_array( 'IPS\Node\Model', class_parents( $class ) ) )
{
/* @var Model $class */
$thing = $class::loadAndCheckPerms( (int) $args['id'] );
}
elseif ( $class == 'IPS\Member\Club' )
{
/* @var Member\Club $class */
$thing = $class::loadAndCheckPerms( (int) $args['id'] );
}
elseif ( $class != "IPS\Member" )
{
/* @var Content $class */
$thing = $class::loadAndCheckPerms( (int) $args['id'] );
}
else
{
if( !$class instanceof \IPS\Content\Followable )
if( !IPS::classUsesTrait( $class, 'IPS\Content\Followable' ) )
{
throw new \OutOfRangeException;
throw new OutOfRangeException;
}
/* @var Member $class */
$thing = $class::load( (int) $args['id'] );
}
}
catch ( \OutOfRangeException $e )
catch ( OutOfRangeException $e )
{
throw new \IPS\Api\GraphQL\SafeException( 'NOT_FOUND', 'GQL/0001/5', 404 );
throw new SafeException( 'NOT_FOUND', 'GQL/0001/5', 404 );
}
/* Do we follow it? */
try
{
$current = \IPS\Db::i()->select( '*', 'core_follow', array( 'follow_app=? AND follow_area=? AND follow_rel_id=? AND follow_member_id=?', $args['app'], $args['area'], $args['id'], \IPS\Member::loggedIn()->member_id ) )->first();
$current = Db::i()->select( '*', 'core_follow', array( 'follow_app=? AND follow_area=? AND follow_rel_id=? AND follow_member_id=?', $args['app'], $args['area'], $args['id'], Member::loggedIn()->member_id ) )->first();
}
catch ( \UnderflowException $e )
catch ( UnderflowException $e )
{
$current = FALSE;
}
/* Insert */
$save = array(
'follow_id' => md5( $args['app'] . ';' . $args['area'] . ';' . $args['id'] . ';' . \IPS\Member::loggedIn()->member_id ),
'follow_id' => md5( $args['app'] . ';' . $args['area'] . ';' . $args['id'] . ';' . Member::loggedIn()->member_id ),
'follow_app' => $args['app'],
'follow_area' => $args['area'],
'follow_rel_id' => $args['id'],
'follow_member_id' => \IPS\Member::loggedIn()->member_id,
'follow_member_id' => Member::loggedIn()->member_id,
'follow_is_anon' => $args['anonymous'],
'follow_added' => time(),
'follow_notify_do' => $args['type'] == 'NONE' ? 0 : 1,
@@ -168,11 +189,11 @@ class _Follow
);
if ( $current )
{
\IPS\Db::i()->update( 'core_follow', $save, array( 'follow_id=?', $current['follow_id'] ) );
Db::i()->update( 'core_follow', $save, array( 'follow_id=?', $current['follow_id'] ) );
}
else
{
\IPS\Db::i()->insert( 'core_follow', $save );
Db::i()->insert( 'core_follow', $save );
}
/* Also follow all nodes if following club */
@@ -185,11 +206,11 @@ class _Follow
$followArea = mb_strtolower( mb_substr( $node['node_class'], mb_strrpos( $node['node_class'], '\\' ) + 1 ) );
$save = array(
'follow_id' => md5( $followApp . ';' . $followArea . ';' . $node['node_id'] . ';' . \IPS\Member::loggedIn()->member_id ),
'follow_id' => md5( $followApp . ';' . $followArea . ';' . $node['node_id'] . ';' . Member::loggedIn()->member_id ),
'follow_app' => $followApp,
'follow_area' => $followArea,
'follow_rel_id' => $node['node_id'],
'follow_member_id' => \IPS\Member::loggedIn()->member_id,
'follow_member_id' => Member::loggedIn()->member_id,
'follow_is_anon' => $args['anonymous'],
'follow_added' => time(),
'follow_notify_do' => $args['type'] == 'NONE' ? 0 : 1,
@@ -198,25 +219,25 @@ class _Follow
'follow_notify_sent' => 0,
'follow_visible' => 1,
);
\IPS\Db::i()->insert( 'core_follow', $save, TRUE );
Db::i()->insert( 'core_follow', $save, TRUE );
}
}
/* Send notification if following member */
if( $class == "IPS\Member" )
{
$notification = new \IPS\Notification( \IPS\Application::load( 'core' ), 'member_follow', \IPS\Member::loggedIn(), array( \IPS\Member::loggedIn() ) );
$notification = new Notification( Application::load( 'core' ), 'member_follow', Member::loggedIn(), array( Member::loggedIn() ) );
$notification->recipients->attach( $thing );
$notification->send();
}
if ( \in_array( 'IPS\Node\Model', class_parents( $class ) ) )
if ( in_array( 'IPS\Node\Model', class_parents( $class ) ) )
{
$return = array_merge($return, array(
'node' => $thing,
'nodeClass' => \get_class( $thing )
'nodeClass' => get_class( $thing )
));
}
else if( $class == 'IPS\Member' )
@@ -233,7 +254,7 @@ class _Follow
{
$return = array_merge($return, array(
'item' => $thing,
'itemClass' => \get_class( $thing )
'itemClass' => get_class( $thing )
));
}
@@ -10,25 +10,31 @@
*/
namespace IPS\core\api\GraphQL\Mutations;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\SafeException;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\core\api\GraphQL\Types\IgnoreOptionType;
use IPS\core\Ignore;
use IPS\Member;
use OutOfRangeException;
use function defined;
use function in_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;
}
/**
* Ignore user mutation for GraphQL API
*/
class _IgnoreUser
class IgnoreUser
{
/*
* @brief Query description
*/
public static $description = "Ignore a member";
public static string $description = "Ignore a member";
/*
* Mutation arguments
@@ -45,7 +51,7 @@ class _IgnoreUser
/**
* Return the mutation return type
*/
public function type()
public function type() : IgnoreOptionType
{
return \IPS\core\api\GraphQL\TypeRegistry::ignoreOption();
}
@@ -53,47 +59,46 @@ class _IgnoreUser
/**
* Resolves this mutation
*
* @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
* @return array
*/
public function resolve($val, $args)
public function resolve( mixed $val, array $args ) : array
{
if ( !\in_array( $args['type'], \IPS\core\Ignore::types() ) )
if ( !in_array( $args['type'], Ignore::types() ) )
{
throw new \IPS\Api\GraphQL\SafeException( 'INVALID_TYPE', 'GQL/0006/1', 404 );
throw new SafeException( 'INVALID_TYPE', 'GQL/0006/1', 404 );
}
$type = $args['type'];
$member = \IPS\Member::load( $args['member'] );
$member = Member::load( $args['member'] );
if( !$member->member_id )
{
throw new \IPS\Api\GraphQL\SafeException( 'INVALID_MEMBER', 'GQL/0006/2', 403 );
throw new SafeException( 'INVALID_MEMBER', 'GQL/0006/2', 403 );
}
if ( $member->member_id == \IPS\Member::loggedIn()->member_id )
if ( $member->member_id == Member::loggedIn()->member_id )
{
throw new \IPS\Api\GraphQL\SafeException( 'NO_IGNORE_SELF', 'GQL/0006/3', 403 );
throw new SafeException( 'NO_IGNORE_SELF', 'GQL/0006/3', 403 );
}
if ( !$member->canBeIgnored() )
{
throw new \IPS\Api\GraphQL\SafeException( 'NO_IGNORE_MEMBER', 'GQL/0006/4', 403 );
throw new SafeException( 'NO_IGNORE_MEMBER', 'GQL/0006/4', 403 );
}
try
{
$ignore = \IPS\core\Ignore::load( $member->member_id, 'ignore_ignore_id', array( 'ignore_owner_id=?', \IPS\Member::loggedIn()->member_id ) );
$ignore = Ignore::load( $member->member_id, 'ignore_ignore_id', array( 'ignore_owner_id=?', Member::loggedIn()->member_id ) );
$ignore->$type = $args['isIgnoring'];
$ignore->save();
}
catch( \OutOfRangeException $e )
catch( OutOfRangeException $e )
{
$ignore = new \IPS\core\Ignore;
$ignore = new Ignore;
$ignore->$type = $args['isIgnoring'];
$ignore->owner_id = \IPS\Member::loggedIn()->member_id;
$ignore->owner_id = Member::loggedIn()->member_id;
$ignore->ignore_id = $member->member_id;
$ignore->save();
}
@@ -103,8 +108,8 @@ class _IgnoreUser
'is_being_ignored' => $args['isIgnoring']
);
\IPS\Member::loggedIn()->members_bitoptions['has_no_ignored_users'] = FALSE;
\IPS\Member::loggedIn()->save();
Member::loggedIn()->members_bitoptions['has_no_ignored_users'] = FALSE;
Member::loggedIn()->save();
return $return;
}
@@ -10,25 +10,33 @@
*/
namespace IPS\core\api\GraphQL\Mutations;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\SafeException;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\Application;
use IPS\core\api\GraphQL\Types\NotificationType;
use IPS\Db;
use IPS\Member;
use IPS\Notification\Api;
use UnderflowException;
use function defined;
use function intval;
/* 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;
}
/**
* Mark notification read mutation for GraphQL API
*/
class _MarkNotificationRead
class MarkNotificationRead
{
/*
* @brief Query description
*/
public static $description = "Mark a notification as read";
public static string $description = "Mark a notification as read";
/*
* Mutation arguments
@@ -43,7 +51,7 @@ class _MarkNotificationRead
/**
* Return the mutation return type
*/
public function type()
public function type() : NotificationType
{
return \IPS\core\Api\GraphQL\TypeRegistry::notification();
}
@@ -51,45 +59,44 @@ class _MarkNotificationRead
/**
* Resolves this mutation
*
* @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
* @return array|NULL
*/
public function resolve($val, $args)
public function resolve( mixed $val, array $args ) : ?array
{
if( !\IPS\Member::loggedIn()->member_id )
if( !Member::loggedIn()->member_id )
{
throw new \IPS\Api\GraphQL\SafeException( 'NOT_LOGGED_IN', 'GQL/0003/1', 403 );
throw new SafeException( 'NOT_LOGGED_IN', 'GQL/0003/1', 403 );
}
$where = array();
$where[] = array( "notification_app IN('" . implode( "','", array_keys( \IPS\Application::enabledApplications() ) ) . "')" );
$where[] = array( "member = ?", \IPS\Member::loggedIn()->member_id );
$where[] = array( "notification_app IN('" . implode( "','", array_keys( Application::enabledApplications() ) ) . "')" );
$where[] = array( "member = ?", Member::loggedIn()->member_id );
if( isset( $args['id'] ) && $args['id'] !== NULL )
if( isset( $args['id'] ) )
{
$where[] = array( "id = ?", \intval( $args['id'] ) );
$where[] = array( "id = ?", intval( $args['id'] ) );
}
try
{
$row = \IPS\Db::i()->select( '*', 'core_notifications', $where )->first();
$notification = \IPS\Notification\Api::constructFromData( $row );
$row = Db::i()->select( '*', 'core_notifications', $where )->first();
$notification = Api::constructFromData( $row );
}
catch ( \UnderflowException $e )
catch ( UnderflowException $e )
{
if( isset( $args['id'] ) && $args['id'] !== NULL )
if( isset( $args['id'] ) )
{
// Only throw an error if we were trying to work on a specific notification
throw new \IPS\Api\GraphQL\SafeException( 'INVALID_NOTIFICATION', 'GQL/0003/2', 403 );
throw new SafeException( 'INVALID_NOTIFICATION', 'GQL/0003/2', 403 );
}
}
\IPS\Db::i()->update( 'core_notifications', array( 'read_time' => time() ), $where );
\IPS\Member::loggedIn()->recountNotifications();
Db::i()->update( 'core_notifications', array( 'read_time' => time() ), $where );
Member::loggedIn()->recountNotifications();
if( $notification )
if( isset( $notification ) )
{
return array( 'notification' => $notification, 'data' => $notification->getData() );
}
@@ -10,25 +10,33 @@
*/
namespace IPS\core\api\GraphQL\Mutations\Messenger;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\SafeException;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\Application;
use IPS\Application\Module;
use IPS\core\api\GraphQL\Types\MessengerConversationType;
use IPS\core\Messenger\Conversation;
use IPS\Member;
use IPS\Notification;
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;
}
/**
* Add user to conversation mutation for GraphQL API
*/
class _AddConversationUser
class AddConversationUser
{
/*
* @brief Query description
*/
public static $description = "Add a user to a PM conversation";
public static string $description = "Add a user to a PM conversation";
/*
* Mutation arguments
@@ -44,7 +52,7 @@ class _AddConversationUser
/**
* Return the mutation return type
*/
public function type()
public function type() : MessengerConversationType
{
return \IPS\core\Api\GraphQL\TypeRegistry::messengerConversation();
}
@@ -52,38 +60,37 @@ class _AddConversationUser
/**
* Resolves this mutation
*
* @param mixed Value passed into this resolver
* @param array Arguments
* @param array Context values
* @return \IPS\forums\Forum
* @param mixed $val Value passed into this resolver
* @param array $args Arguments
* @return Conversation
*/
public function resolve($val, $args)
public function resolve( mixed $val, array $args ) : Conversation
{
if( !\IPS\Member::loggedIn()->member_id )
if( !Member::loggedIn()->member_id )
{
throw new \IPS\Api\GraphQL\SafeException( 'NOT_LOGGED_IN', 'GQL/0003/1', 403 );
throw new SafeException( 'NOT_LOGGED_IN', 'GQL/0003/1', 403 );
}
try
{
$conversation = \IPS\core\Messenger\Conversation::loadAndCheckPerms( $args['id'] );
$conversation = Conversation::loadAndCheckPerms( $args['id'] );
}
catch ( \OutOfRangeException $e )
catch ( OutOfRangeException $e )
{
throw new \IPS\Api\GraphQL\SafeException( 'NO_MESSAGE', '1F294/2_graphql', 400 );
throw new SafeException( 'NO_MESSAGE', '1F294/2_graphql', 400 );
}
// Fetch our new member
$member = \IPS\Member::load( $args['memberId'] );
$member = Member::load( $args['memberId'] );
if( !$member->member_id ){
throw new \IPS\Api\GraphQL\SafeException( 'INVALID_MEMBER', '1F294/2_graphql', 403 );
throw new SafeException( 'INVALID_MEMBER', '1F294/2_graphql', 403 );
}
// Check member limit
if ( \IPS\Member::loggedIn()->group['g_max_mass_pm'] !== -1 AND $conversation->to_count + 1 > \IPS\Member::loggedIn()->group['g_max_mass_pm'] )
if ( Member::loggedIn()->group['g_max_mass_pm'] !== -1 AND $conversation->to_count + 1 > Member::loggedIn()->group['g_max_mass_pm'] )
{
throw new \IPS\Api\GraphQL\SafeException( 'TOO_MANY_RECIPIENTS', '1F294/2', 400 );
throw new SafeException( 'TOO_MANY_RECIPIENTS', '1F294/2', 400 );
}
$maps = $conversation->maps( TRUE );
@@ -91,12 +98,12 @@ class _AddConversationUser
// Authorize the member
if ( array_key_exists( $member->member_id, $maps ) and !$maps[ $member->member_id ]['map_user_active'] AND !$maps[ $member->member_id ]['map_user_banned'] )
{
throw new \IPS\Api\GraphQL\SafeException( 'MEMBER_LEFT', '1F294/2', 403 );
throw new SafeException( 'MEMBER_LEFT', '1F294/2', 403 );
}
if ( !$this->memberCanReceiveNewMessage( $member ) )
{
throw new \IPS\Api\GraphQL\SafeException( 'BAD_RECIPIENT', '1F294/2', 403 );
throw new SafeException( 'BAD_RECIPIENT', '1F294/2', 403 );
}
//echo 'here';
@@ -104,7 +111,7 @@ class _AddConversationUser
$conversation->authorize( $member );
$conversation->maps(TRUE); // Need to rebuild participant maps here to reflect this change
$notification = new \IPS\Notification( \IPS\Application::load('core'), 'private_message_added', $conversation, array( $conversation, \IPS\Member::loggedIn() ) );
$notification = new Notification( Application::load('core'), 'private_message_added', $conversation, array( $conversation, Member::loggedIn() ) );
$notification->recipients->attach( $member );
$notification->send();
@@ -114,10 +121,10 @@ class _AddConversationUser
/**
* Can the member recieve new messages?
*
* @param \IPS\Member The member to check
* @return boolean
* @param Member $member The member to check
* @return bool
*/
public function memberCanReceiveNewMessage( $member )
public function memberCanReceiveNewMessage( Member $member ) : bool
{
if ( $member->members_disable_pm )
{
@@ -125,19 +132,19 @@ class _AddConversationUser
}
/* Group can not use messenger */
if ( !$member->canAccessModule( \IPS\Application\Module::get( 'core', 'messaging', 'front' ) ) )
if ( !$member->canAccessModule( Module::get( 'core', 'messaging', 'front' ) ) )
{
return FALSE;
}
/* Inbox is full */
if ( ( $member->group['g_max_messages'] > 0 AND $member->msg_count_total >= $member->group['g_max_messages'] ) and !\IPS\Member::loggedIn()->group['gbw_pm_override_inbox_full'] )
if ( ( $member->group['g_max_messages'] > 0 AND $member->msg_count_total >= $member->group['g_max_messages'] ) and !Member::loggedIn()->group['gbw_pm_override_inbox_full'] )
{
return FALSE;
}
/* Is being ignored */
if ( $member->isIgnoring( \IPS\Member::loggedIn(), 'messages' ) )
if ( $member->isIgnoring( Member::loggedIn(), 'messages' ) )
{
return FALSE;
}
@@ -10,25 +10,30 @@
*/
namespace IPS\core\api\GraphQL\Mutations\Messenger;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\SafeException;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\core\api\GraphQL\Types\MessengerConversationType;
use IPS\core\Messenger\Conversation;
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;
}
/**
* Leave conversation mutation for GraphQL API
*/
class _LeaveConversation
class LeaveConversation
{
/*
* @brief Query description
*/
public static $description = "Leave a PM conversation";
public static string $description = "Leave a PM conversation";
/*
* Mutation arguments
@@ -43,7 +48,7 @@ class _LeaveConversation
/**
* Return the mutation return type
*/
public function type()
public function type() : MessengerConversationType
{
return \IPS\core\Api\GraphQL\TypeRegistry::messengerConversation();
}
@@ -51,26 +56,25 @@ class _LeaveConversation
/**
* Resolves this mutation
*
* @param mixed Value passed into this resolver
* @param array Arguments
* @param array Context values
* @return \IPS\forums\Forum
* @param mixed $val Value passed into this resolver
* @param array $args Arguments
* @return mixed
*/
public function resolve($val, $args)
public function resolve( mixed $val, array $args ) : mixed
{
if( !\IPS\Member::loggedIn()->member_id )
if( !Member::loggedIn()->member_id )
{
throw new \IPS\Api\GraphQL\SafeException( 'NOT_LOGGED_IN', 'GQL/0003/1', 403 );
throw new SafeException( 'NOT_LOGGED_IN', 'GQL/0003/1', 403 );
}
try
{
$conversation = \IPS\core\Messenger\Conversation::loadAndCheckPerms( $args['id'] );
$conversation->deauthorize( \IPS\Member::loggedIn() );
$conversation = Conversation::loadAndCheckPerms( $args['id'] );
$conversation->deauthorize( Member::loggedIn() );
}
catch ( \OutOfRangeException $e )
catch ( OutOfRangeException $e )
{
throw new \IPS\Api\GraphQL\SafeException( 'NO_MESSAGE', '1F294/2_graphl', 400 );
throw new SafeException( 'NO_MESSAGE', '1F294/2_graphl', 400 );
}
return NULL;
@@ -10,25 +10,30 @@
*/
namespace IPS\core\api\GraphQL\Mutations\Messenger;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\SafeException;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\core\api\GraphQL\Types\MessengerConversationType;
use IPS\core\Messenger\Conversation;
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;
}
/**
* Remove user from conversation mutation for GraphQL API
*/
class _RemoveConversationUser
class RemoveConversationUser
{
/*
* @brief Query description
*/
public static $description = "Leave a PM conversation";
public static string $description = "Leave a PM conversation";
/*
* Mutation arguments
@@ -44,7 +49,7 @@ class _RemoveConversationUser
/**
* Return the mutation return type
*/
public function type()
public function type() : MessengerConversationType
{
return \IPS\core\Api\GraphQL\TypeRegistry::messengerConversation();
}
@@ -52,33 +57,32 @@ class _RemoveConversationUser
/**
* Resolves this mutation
*
* @param mixed Value passed into this resolver
* @param array Arguments
* @param array Context values
* @return \IPS\forums\Forum
* @param mixed $val Value passed into this resolver
* @param array $args Arguments
* @return Conversation
*/
public function resolve($val, $args)
public function resolve( mixed $val, array $args ) : Conversation
{
if( !\IPS\Member::loggedIn()->member_id )
if( !Member::loggedIn()->member_id )
{
throw new \IPS\Api\GraphQL\SafeException( 'NOT_LOGGED_IN', 'GQL/0003/1', 403 );
throw new SafeException( 'NOT_LOGGED_IN', 'GQL/0003/1', 403 );
}
try
{
$conversation = \IPS\core\Messenger\Conversation::loadAndCheckPerms( $args['id'] );
$conversation = Conversation::loadAndCheckPerms( $args['id'] );
}
catch ( \OutOfRangeException $e )
catch ( OutOfRangeException $e )
{
throw new \IPS\Api\GraphQL\SafeException( 'NO_MESSAGE', '1F294/2_graphl', 400 );
throw new SafeException( 'NO_MESSAGE', '1F294/2_graphl', 400 );
}
if( $conversation->starter_id !== \IPS\Member::loggedIn()->member_id )
if( $conversation->starter_id !== Member::loggedIn()->member_id )
{
throw new \IPS\Api\GraphQL\SafeException( 'NOT_OWNER', 'GQL/0003/1', 403 );
throw new SafeException( 'NOT_OWNER', 'GQL/0003/1', 403 );
}
$conversation->deauthorize( \IPS\Member::load( $args['memberId'] ), TRUE );
$conversation->deauthorize( Member::load( $args['memberId'] ), TRUE );
$conversation->maps(TRUE); // Need to rebuild participant maps here to reflect this change
return $conversation;
@@ -10,25 +10,34 @@
*/
namespace IPS\core\api\GraphQL\Mutations;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\SafeException;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\Api\GraphQL\Types\FollowType;
use IPS\Application;
use IPS\Db;
use IPS\IPS;
use IPS\Member;
use OutOfRangeException;
use function defined;
use function get_class;
use function in_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;
}
/**
* Follow something mutation for GraphQL API
*/
class _Unfollow
class Unfollow
{
/*
* @brief Query description
*/
public static $description = "Unfollow a node, item or member";
public static string $description = "Unfollow a node, item or member";
/*
* Mutation arguments
@@ -46,7 +55,7 @@ class _Unfollow
/**
* Return the mutation return type
*/
public function type()
public function type() : FollowType
{
return TypeRegistry::follow();
}
@@ -56,25 +65,27 @@ class _Unfollow
* @todo this is basically copied and pasted from notifications.php which isn't ideal, so we
* might want to consider refactoring to abstract this functionality.
*
* @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
* @return array
*/
public function resolve($val, $args)
public function resolve( mixed $val, array $args ) : array
{
if( !\IPS\Member::loggedIn()->member_id )
if( !Member::loggedIn()->member_id )
{
throw new \IPS\Api\GraphQL\SafeException( 'NOT_LOGGED_IN', 'GQL/0002/6', 403 );
throw new SafeException( 'NOT_LOGGED_IN', 'GQL/0002/6', 403 );
}
try
{
$follow = \IPS\Db::i()->select( '*', 'core_follow', array( 'follow_id=? AND follow_member_id=?', $args['followID'], \IPS\Member::loggedIn()->member_id ) )->first();
$follow = Db::i()->select( '*', 'core_follow', array( 'follow_id=? AND follow_member_id=?', $args['followID'], Member::loggedIn()->member_id ) )->first();
}
catch ( OutOfRangeException $e )
{
throw new SafeException( 'NOT_FOUND', 'GQL/0002/7', 404 );
}
catch ( \OutOfRangeException $e ) {}
\IPS\Db::i()->delete( 'core_follow', array( 'follow_id=? AND follow_member_id=?', $args['followID'], \IPS\Member::loggedIn()->member_id ) );
Db::i()->delete( 'core_follow', array( 'follow_id=? AND follow_member_id=?', $args['followID'], Member::loggedIn()->member_id ) );
/* Get class */
if( $args['app'] == 'core' and $args['area'] == 'member' )
@@ -88,16 +99,16 @@ class _Unfollow
else
{
$class = NULL;
foreach ( \IPS\Application::load( $args['app'] )->extensions( 'core', 'ContentRouter' ) as $ext )
foreach ( Application::load( $args['app'] )->extensions( 'core', 'ContentRouter' ) as $ext )
{
foreach ( $ext->classes as $classname )
{
if ( $classname == 'IPS\\' . $args['app'] . '\\' . mb_ucfirst( $args['area'] ) )
if ( $classname == 'IPS\\' . $args['app'] . '\\' . IPS::mb_ucfirst( $args['area'] ) )
{
$class = $classname;
break;
}
if ( isset( $classname::$containerNodeClass ) and $classname::$containerNodeClass == 'IPS\\' . $args['app'] . '\\' . mb_ucfirst( $args['area'] ) )
if ( isset( $classname::$containerNodeClass ) and $classname::$containerNodeClass == 'IPS\\' . $args['app'] . '\\' . IPS::mb_ucfirst( $args['area'] ) )
{
$class = $classname::$containerNodeClass;
break;
@@ -106,7 +117,7 @@ class _Unfollow
{
foreach( $classname::$containerFollowClasses as $followClass )
{
if( $followClass == 'IPS\\' . $args['app'] . '\\' . mb_ucfirst( $args['area'] ) )
if( $followClass == 'IPS\\' . $args['app'] . '\\' . IPS::mb_ucfirst( $args['area'] ) )
{
$class = $followClass;
break;
@@ -117,9 +128,9 @@ class _Unfollow
}
}
if ( !$class or !array_key_exists( $args['app'], \IPS\Application::applications() ) )
if ( !$class or !array_key_exists( $args['app'], Application::applications() ) )
{
throw new \IPS\Api\GraphQL\SafeException( 'NOT_FOUND', 'GQL/0001/7', 404 );
throw new SafeException( 'NOT_FOUND', 'GQL/0001/7', 404 );
}
/* Get our return info ready */
@@ -152,15 +163,15 @@ class _Unfollow
$followApp = $itemClass::$application;
$followArea = mb_strtolower( mb_substr( $node['node_class'], mb_strrpos( $node['node_class'], '\\' ) + 1 ) );
\IPS\Db::i()->delete( 'core_follow', array( 'follow_id=? AND follow_member_id=?', md5( $followApp . ';' . $followArea . ';' . $node['node_id'] . ';' . \IPS\Member::loggedIn()->member_id ), \IPS\Member::loggedIn()->member_id ) );
Db::i()->delete( 'core_follow', array( 'follow_id=? AND follow_member_id=?', md5( $followApp . ';' . $followArea . ';' . $node['node_id'] . ';' . Member::loggedIn()->member_id ), Member::loggedIn()->member_id ) );
}
}
if ( \in_array( 'IPS\Node\Model', class_parents( $class ) ) )
if ( in_array( 'IPS\Node\Model', class_parents( $class ) ) )
{
$return = array_merge($return, array(
'node' => $thing,
'nodeClass' => \get_class( $thing )
'nodeClass' => get_class( $thing )
));
}
else if( $class == 'IPS\Member' )
@@ -177,11 +188,11 @@ class _Unfollow
{
$return = array_merge($return, array(
'item' => $thing,
'itemClass' => \get_class( $thing )
'itemClass' => get_class( $thing )
));
}
}
catch ( \OutOfRangeException $e )
catch ( OutOfRangeException $e )
{
}
@@ -10,26 +10,34 @@
*/
namespace IPS\core\api\GraphQL\Mutations;
use GraphQL\Type\Definition\ObjectType;
use Exception;
use GraphQL\Type\Definition\UnionType;
use InvalidArgumentException;
use IPS\Api\GraphQL\SafeException;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\File;
use IPS\Helpers\Form\Editor;
use IPS\Image;
use IPS\Member;
use function defined;
use function in_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;
}
/**
* Upload attachment mutation for GraphQL API
*/
class _UploadAttachment
class UploadAttachment
{
/*
* @brief Query description
*/
public static $description = "Upload a file to be an attachment";
public static string $description = "Upload a file to be an attachment";
/*
* Mutation arguments
@@ -49,7 +57,7 @@ class _UploadAttachment
/**
* Return the mutation return type
*/
public function type()
public function type() : UnionType
{
return new UnionType([
'name' => 'core_UploadAttachment',
@@ -73,23 +81,24 @@ class _UploadAttachment
/**
* Resolves this mutation
*
* @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
{
$storageClass = \IPS\File::getClass( 'core_Attachment' );
$storageClass = File::getClass( 'core_Attachment' );
$contents = base64_decode( $args['contents'] );
/* Check allowed types */
$ext = mb_substr( $args['name'], mb_strrpos( $args['name'], '.' ) + 1 );
if( $allowedFileTypes = \IPS\Helpers\Form\Editor::allowedFileExtensions() )
if( $allowedFileTypes = Editor::allowedFileExtensions() )
{
if( !\in_array( mb_strtolower( $ext ), array_map( 'mb_strtolower', $allowedFileTypes ) ) )
if( !in_array( mb_strtolower( $ext ), array_map( 'mb_strtolower', $allowedFileTypes ) ) )
{
throw new \IPS\Api\GraphQL\SafeException( 'FILE_TYPE_NOT_ALLOWED', '2C399/1_graphql', 403 );
throw new SafeException( 'FILE_TYPE_NOT_ALLOWED', '2C399/1_graphql', 403 );
}
}
@@ -115,15 +124,15 @@ class _UploadAttachment
$file = $storageClass->chunkFinish( $ref, 'core_Attachment' );
/* If it's got an image extension, check it's actually a valid image */
if ( \in_array( $ext, \IPS\Image::supportedExtensions() ) )
if ( in_array( $ext, Image::supportedExtensions() ) )
{
try
{
$file->getImageDimensions();
}
catch ( \Exception $e )
catch ( Exception $e )
{
throw new \IPS\Api\GraphQL\SafeException( 'NOT_VALID_IMAGE', '2C399/2_graphql', 403 );
throw new SafeException( 'NOT_VALID_IMAGE', '2C399/2_graphql', 403 );
}
}
}
@@ -141,31 +150,30 @@ class _UploadAttachment
else
{
/* If it's got an image extension, check it's actually a valid image */
if ( \in_array( $ext, \IPS\Image::supportedExtensions() ) )
if ( in_array( $ext, Image::supportedExtensions() ) )
{
try
{
$image = \IPS\Image::create( $contents );
$image = Image::create( $contents );
}
catch ( \InvalidArgumentException $e )
catch ( InvalidArgumentException $e )
{
throw new \IPS\Api\GraphQL\SafeException( $e->getMessage(), '2C399/2_graphql', 403 );
throw new SafeException( $e->getMessage(), '2C399/2_graphql', 403 );
}
}
/* Create the file */
try
{
$file = \IPS\File::create( 'core_Attachment', $args['name'], $contents );
$file = File::create( 'core_Attachment', $args['name'], $contents );
}
catch ( \Exception $e )
catch ( Exception $e )
{
throw new \IPS\Api\GraphQL\SafeException( 'FILE_CREATION_FAILED', '2C399/3_graphql', 403 );
throw new SafeException( 'FILE_CREATION_FAILED', '2C399/3_graphql', 403 );
}
}
/* Make it into an attachment */
$attachment = $file->makeAttachment( $args['postKey'], \IPS\Member::loggedIn() );
return $attachment;
return $file->makeAttachment( $args['postKey'], Member::loggedIn() );
}
}
@@ -10,25 +10,28 @@
*/
namespace IPS\core\api\GraphQL\Queries;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\Application\Module;
use IPS\core\api\GraphQL\TypeRegistry;
use IPS\core\api\GraphQL\Types\ActiveUsersType;
use IPS\Member;
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;
}
/**
* OurPicks query for GraphQL API
*/
class _ActiveUsers
class ActiveUsers
{
/*
* @brief Query description
*/
public static $description = "Returns active user information";
public static string $description = "Returns active user information";
/*
* Query arguments
@@ -41,20 +44,20 @@ class _ActiveUsers
/**
* Return the query return type
*/
public function type()
public function type() : ActiveUsersType
{
return \IPS\core\api\GraphQL\TypeRegistry::activeUsers();
return TypeRegistry::activeUsers();
}
/**
* Resolves this query
*
* @param mixed Value passed into this resolver
* @return \IPS\core\Stream
* @param mixed $val Value passed into this resolver
* @return mixed
*/
public function resolve($val)
public function resolve( mixed $val ) : mixed
{
if ( !\IPS\Member::loggedIn()->canAccessModule( \IPS\Application\Module::get( 'core', 'online', 'front' ) ) )
if ( !Member::loggedIn()->canAccessModule( Module::get( 'core', 'online', 'front' ) ) )
{
return NULL;
}
+14 -12
View File
@@ -10,25 +10,27 @@
*/
namespace IPS\core\api\GraphQL\Queries;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\core\api\GraphQL\Types\ClubType;
use IPS\Member\Club as ClubClass;
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;
}
/**
* Club query for GraphQL API
*/
class _Club
class Club
{
/*
* @brief Query description
*/
public static $description = "Returns a club";
public static string $description = "Returns a club";
/*
* Query arguments
@@ -42,7 +44,7 @@ class _Club
/**
* Return the query return type
*/
public function type()
public function type() : ClubType
{
return \IPS\core\api\GraphQL\TypeRegistry::club();
}
@@ -50,13 +52,13 @@ class _Club
/**
* Resolves this query
*
* @param mixed Value passed into this resolver
* @param array Arguments
* @param array Context values
* @return \IPS\Member\Club
* @param mixed $val Value passed into this resolver
* @param array $args Arguments
* @param array $context Context values
* @return ClubClass
*/
public function resolve($val, $args, $context)
public function resolve( mixed $val, array $args, array $context ) : ClubClass
{
return \IPS\Member\Club::loadAndCheckPerms( $args['id'] );
return ClubClass::loadAndCheckPerms( $args['id'] );
}
}
+22 -16
View File
@@ -10,20 +10,26 @@
namespace IPS\core\api\GraphQL\Queries;
use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\ListOfType;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\core\api\GraphQL\Types\ClubType;
use IPS\Db;
use IPS\Patterns\ActiveRecordIterator;
use function defined;
use function in_array;
use function is_int;
/* 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;
}
/**
* Club query for GraphQL API
*/
class _Clubs
class Clubs
{
/*
* @brief Query description
@@ -49,7 +55,7 @@ class _Clubs
'type' => TypeRegistry::eNum( [
'name' => 'clubs_order_by',
'description' => 'Fields on which topics can be sorted',
'values' => \IPS\core\api\GraphQL\Types\ClubType::getOrderByOptions()
'values' => ClubType::getOrderByOptions()
] ),
'defaultValue' => NULL // will use default sort option
],
@@ -70,7 +76,7 @@ class _Clubs
/**
* Return the query return type
*/
public function type(): \GraphQL\Type\Definition\ListOfType
public function type(): ListOfType
{
return TypeRegistry::listOf( \IPS\core\api\GraphQL\TypeRegistry::club() );
}
@@ -78,19 +84,19 @@ class _Clubs
/**
* Resolves this query
*
* @param mixed Value passed into this resolver
* @param array Arguments
* @param array Context values
* @return \IPS\Patterns\ActiveRecordIterator[\IPS\Member\Club]
* @param mixed $val Value passed into this resolver
* @param array $args Arguments
* @param array $context Context values
* @return ActiveRecordIterator[\IPS\Member\Club]
*/
public function resolve( mixed $val, array $args, array $context ): \IPS\Patterns\ActiveRecordIterator
public function resolve( mixed $val, array $args, array $context ): ActiveRecordIterator
{
$where = [];
$sortBy = ( isset( $args['orderBy'] ) and \in_array( $args['orderBy'], \IPS\core\api\GraphQL\Types\ClubType::getOrderByOptions() ) ) ? $args['orderBy'] : 'name';
$sortDir = ( isset( $args['orderDir'] ) and \in_array( mb_strtolower( $args['orderDir'] ), array( 'asc', 'desc' ) ) ) ? $args['orderDir'] : 'desc';
$limit =( isset( $args['orderDir'] ) and \is_int( $args['limit'] ) ) ? $args['limit'] : 25;
$sortBy = ( isset( $args['orderBy'] ) and in_array( $args['orderBy'], ClubType::getOrderByOptions() ) ) ? $args['orderBy'] : 'name';
$sortDir = ( isset( $args['orderDir'] ) and in_array( mb_strtolower( $args['orderDir'] ), array( 'asc', 'desc' ) ) ) ? $args['orderDir'] : 'desc';
$limit =( isset( $args['orderDir'] ) and is_int( $args['limit'] ) ) ? $args['limit'] : 25;
$query = \IPS\Db::i()->select( '*', 'core_clubs', $where, "{$sortBy} {$sortDir}", $limit );
return new \IPS\Patterns\ActiveRecordIterator( $query, '\IPS\Member\Club' );
$query = Db::i()->select( '*', 'core_clubs', $where, "{$sortBy} {$sortDir}", $limit );
return new ActiveRecordIterator( $query, '\IPS\Member\Club' );
}
}
@@ -10,26 +10,32 @@
*/
namespace IPS\core\api\GraphQL\Queries;
use GraphQL\Type\Definition\ObjectType;
use Exception;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\Application;
use IPS\Content as ContentClass;
use IPS\Content\Api\GraphQL\ContentType;
use IPS\Http\Url;
use IPS\Member;
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;
}
/**
* Me query for GraphQL API
*/
class _Content
class Content
{
/*
* @brief Query description
*/
public static $description = "Return a generic piece of content";
public static string $description = "Return a generic piece of content";
/*
* Query arguments
@@ -44,7 +50,7 @@ class _Content
/**
* Return the query return type
*/
public function type()
public function type() : ContentType
{
return \IPS\Content\Api\GraphQL\TypeRegistry::content();
}
@@ -52,21 +58,20 @@ class _Content
/**
* Resolves this query
*
* @param mixed Value passed into this resolver
* @param array Arguments
* @param array Context values
* @return \IPS\Member|null
* @param mixed $val Value passed into this resolver
* @param array $args Arguments
* @return ContentClass|null
*/
public function resolve($val, $args)
public function resolve( mixed $val, array $args ) : ?ContentClass
{
$url = \IPS\Http\Url::createFromString( $args['url'] );
$url = 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 ( Application::load( $url->hiddenQueryString['app'] )->extensions( 'core', 'ContentRouter' ) as $ext )
{
foreach ( $ext->classes as $class )
{
@@ -85,7 +90,7 @@ class _Content
$object = $reviewClass::load( $url->queryString['review'] );
}
if ( !$object->canView( \IPS\Member::loggedIn() ) )
if ( !$object->canView( Member::loggedIn() ) )
{
// No permission
return NULL;
@@ -93,7 +98,7 @@ class _Content
return $object;
}
catch (\Exception $e)
catch (Exception $e)
{}
}
}
+18 -14
View File
@@ -10,26 +10,30 @@
*/
namespace IPS\core\api\GraphQL\Queries;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\SafeException;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\core\api\GraphQL\Types\GroupType;
use IPS\Member\Group as GroupClass;
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;
}
/**
* Group query for GraphQL API
*/
class _Group
class Group
{
/*
* @brief Query description
*/
public static $description = "Returns a member group";
public static string $description = "Returns a member group";
/*
* @brief Query arguments
@@ -44,7 +48,7 @@ class _Group
/**
* Return the query return type
*/
public function type()
public function type() : GroupType
{
return \IPS\core\api\GraphQL\TypeRegistry::group();
}
@@ -52,20 +56,20 @@ class _Group
/**
* Resolves this query
*
* @param mixed Value passed into this resolver
* @param array Arguments
* @param array Context values
* @return \IPS\Member\Group
* @param mixed $val Value passed into this resolver
* @param array $args Arguments
* @param array $context Context values
* @return GroupClass
*/
public function resolve($val, $args, $context)
public function resolve( mixed $val, array $args, array $context ) : GroupClass
{
try
{
return \IPS\Member\Group::load( $args['id'] );
return GroupClass::load( $args['id'] );
}
catch ( \OutOfRangeException $e )
catch ( OutOfRangeException $e )
{
throw new \IPS\Api\GraphQL\SafeException( 'INVALID_GROUP', '1invalid_group_graph', 400 );
throw new SafeException( 'INVALID_GROUP', '1invalid_group_graph', 400 );
}
}
}
@@ -10,26 +10,29 @@
*/
namespace IPS\core\api\GraphQL\Queries;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\core\api\GraphQL\Types\LanguageType;
use IPS\Lang;
use IPS\Member;
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;
}
/**
* Me query for GraphQL API
*/
class _Language
class Language
{
/*
* @brief Query description
*/
public static $description = "Return language data";
public static string $description = "Return language data";
/*
* Query arguments
@@ -44,7 +47,7 @@ class _Language
/**
* Return the query return type
*/
public function type()
public function type() : LanguageType
{
return \IPS\core\api\GraphQL\TypeRegistry::language();
}
@@ -52,17 +55,16 @@ class _Language
/**
* Resolves this query
*
* @param mixed Value passed into this resolver
* @param array Arguments
* @param array Context values
* @return \IPS\Member|null
* @param mixed $val Value passed into this resolver
* @param array $args Arguments
* @return Lang
*/
public function resolve($val, $args)
public function resolve( mixed $val, array $args ) : Lang
{
if( isset( $args['id'] ) ){
return \IPS\Lang::load( $args['id'] );
return Lang::load( $args['id'] );
}
return \IPS\Member::loggedIn()->language();
return Member::loggedIn()->language();
}
}
@@ -10,26 +10,29 @@
*/
namespace IPS\core\api\GraphQL\Queries;
use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\ListOfType;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\core\api\GraphQL\Types\LoginType;
use IPS\Login;
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;
}
/**
* Login handler query for GraphQL API
*/
class _LoginHandlers
class LoginHandlers
{
/*
* @brief Query description
*/
public static $description = "Return login handler data";
public static string $description = "Return login handler data";
/*
* Query arguments
@@ -43,8 +46,10 @@ class _LoginHandlers
/**
* Return the query return type
*
* @return ListOfType<LoginType>
*/
public function type()
public function type() : ListOfType
{
return TypeRegistry::listOf( \IPS\core\api\GraphQL\TypeRegistry::login() );
}
@@ -52,14 +57,13 @@ class _LoginHandlers
/**
* Resolves this query
*
* @param mixed Value passed into this resolver
* @param array Arguments
* @param array Context values
* @return \IPS\Member|null
* @param mixed $val Value passed into this resolver
* @param array $args Arguments
* @return array
*/
public function resolve($val, $args)
public function resolve( mixed $val, array $args ) : array
{
$login = new \IPS\Login;
$login = new Login;
return $login->buttonMethods();
}
}
+16 -14
View File
@@ -10,26 +10,28 @@
*/
namespace IPS\core\api\GraphQL\Queries;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\core\api\GraphQL\TypeRegistry;
use IPS\core\api\GraphQL\Types\MemberType;
use IPS\Member;
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;
}
/**
* Me query for GraphQL API
*/
class _Me
class Me
{
/*
* @brief Query description
*/
public static $description = "Return the logged-in member";
public static string $description = "Return the logged-in member";
/*
* Query arguments
@@ -42,21 +44,21 @@ class _Me
/**
* Return the query return type
*/
public function type()
public function type() : MemberType
{
return \IPS\core\api\GraphQL\TypeRegistry::member();
return TypeRegistry::member();
}
/**
* Resolves this query
*
* @param mixed Value passed into this resolver
* @param array Arguments
* @param array Context values
* @return \IPS\Member|null
* @param mixed $val Value passed into this resolver
* @param array $args Arguments
* @param array $context Context values
* @return Member
*/
public function resolve($val, $args, $context)
public function resolve( mixed $val, array $args, array $context ) : Member
{
return \IPS\Member::loggedIn();
return Member::loggedIn();
}
}
@@ -10,26 +10,28 @@
*/
namespace IPS\core\api\GraphQL\Queries;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\core\api\GraphQL\Types\MemberType;
use IPS\Member as MemberClass;
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;
}
/**
* Member query for GraphQL API
*/
class _Member
class Member
{
/*
* @brief Query description
*/
public static $description = "Return a member";
public static string $description = "Return a member";
/*
* Query arguments
@@ -45,7 +47,7 @@ class _Member
/**
* Return the query return type
*/
public function type()
public function type() : MemberType
{
return \IPS\core\api\GraphQL\TypeRegistry::member();
}
@@ -53,17 +55,19 @@ class _Member
/**
* Resolves this query
*
* @param mixed Value passed into this resolver
* @param array Arguments
* @param array Context values
* @return \IPS\Member|null
* @param mixed $val Value passed into this resolver
* @param array $args Arguments
* @param array $context Context values
* @return MemberClass|null
*/
public function resolve($val, $args, $context)
public function resolve( mixed $val, array $args, array $context ) : ?MemberClass
{
if( isset( $args['loggedIn'] ) ){
return \IPS\Member::loggedIn();
return MemberClass::loggedIn();
} elseif ( isset( $args['id'] ) ){
return \IPS\Member::load( $args['id'] );
return MemberClass::load( $args['id'] );
}
return null;
}
}
@@ -11,25 +11,31 @@
namespace IPS\core\api\GraphQL\Queries;
use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\ListOfType;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\core\api\GraphQL\Types\MemberType;
use IPS\Db;
use IPS\Patterns\ActiveRecordIterator;
use function defined;
use function in_array;
use function is_int;
/* 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;
}
/**
* Members query for GraphQL API
*/
class _Members
class Members
{
/*
* @brief Query description
*/
public static $description = 'Returns a list of members';
public static string $description = 'Returns a list of members';
/*
* Query arguments
@@ -50,7 +56,7 @@ class _Members
'type' => TypeRegistry::eNum( [
'name' => 'member_order_by',
'description' => 'Fields on which topics can be sorted',
'values' => \IPS\core\api\GraphQL\Types\MemberType::getOrderByOptions()
'values' => MemberType::getOrderByOptions()
] ),
'defaultValue' => NULL // will use default sort option
],
@@ -68,8 +74,10 @@ class _Members
/**
* Return the query return type
*
* @return ListOfType<MemberType>
*/
public function type()
public function type() : ListOfType
{
return TypeRegistry::listOf( \IPS\core\api\GraphQL\TypeRegistry::member() );
}
@@ -77,19 +85,20 @@ class _Members
/**
* Resolves this query
*
* @param mixed Value passed into this resolver
* @param array Arguments
* @param array Context values
* @return [\IPS\Members]
* @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
{
$where = [];
$sortBy = ( isset( $args['orderBy'] ) and \in_array( $args['orderBy'], \IPS\core\api\GraphQL\Types\MemberType::getOrderByOptions() ) ) ? $args['orderBy'] : 'member_id';
$sortDir = ( isset( $args['orderDir'] ) and \in_array( mb_strtolower( $args['orderDir'] ), array( 'asc', 'desc' ) ) ) ? $args['orderDir'] : 'desc';
$limit =( isset( $args['orderDir'] ) and \is_int( $args['limit'] ) ) ? $args['limit'] : 25;
$sortBy = ( isset( $args['orderBy'] ) and in_array( $args['orderBy'], MemberType::getOrderByOptions() ) ) ? $args['orderBy'] : 'member_id';
$sortDir = ( isset( $args['orderDir'] ) and in_array( mb_strtolower( $args['orderDir'] ), array( 'asc', 'desc' ) ) ) ? $args['orderDir'] : 'desc';
$limit =( isset( $args['orderDir'] ) and is_int( $args['limit'] ) ) ? $args['limit'] : 25;
$query = \IPS\Db::i()->select( '*', 'core_members', $where, "{$sortBy} {$sortDir}", $limit );
return new \IPS\Patterns\ActiveRecordIterator( $query, 'IPS\Member' );
$query = Db::i()->select( '*', 'core_members', $where, "{$sortBy} {$sortDir}", $limit );
return new ActiveRecordIterator( $query, 'IPS\Member' );
}
}
@@ -10,25 +10,29 @@
*/
namespace IPS\core\api\GraphQL\Queries;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\SafeException;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\core\api\GraphQL\Types\MessengerConversationType;
use IPS\core\Messenger\Conversation;
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;
}
/**
* Messenger conversation query for GraphQL API
*/
class _MessengerConversation
class MessengerConversation
{
/*
* @brief Query description
*/
public static $description = "Returns a messenger conversation";
public static string $description = "Returns a messenger conversation";
/*
* Query arguments
@@ -43,7 +47,7 @@ class _MessengerConversation
/**
* Return the query return type
*/
public function type()
public function type() : MessengerConversationType
{
return \IPS\core\api\GraphQL\TypeRegistry::messengerConversation();
}
@@ -51,20 +55,21 @@ class _MessengerConversation
/**
* Resolves this query
*
* @param mixed Value passed into this resolver
* @param array Arguments
* @param array Context values
* @return \IPS\core\Messenger\Conversation
* @param mixed $val Value passed into this resolver
* @param array $args Arguments
* @param array $context Context values
* @param array $info
* @return Conversation
*/
public function resolve($val, $args, $context, $info)
public function resolve( mixed $val, array $args, array $context, array $info ) : Conversation
{
try
{
$conversation = \IPS\core\Messenger\Conversation::loadAndCheckPerms( $args['id'] );
$conversation = Conversation::loadAndCheckPerms( $args['id'] );
}
catch ( \OutOfRangeException $e )
catch ( OutOfRangeException $e )
{
throw new \IPS\Api\GraphQL\SafeException( 'NO_MESSAGE', '1F294/2', 400 );
throw new SafeException( 'NO_MESSAGE', '1F294/2', 400 );
}
return $conversation;
@@ -10,25 +10,35 @@
*/
namespace IPS\core\api\GraphQL\Queries;
use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\ListOfType;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\Content\Search\Mysql\Query;
use IPS\core\api\GraphQL\Types\MessengerConversationType;
use IPS\Db;
use IPS\Member;
use IPS\Patterns\ActiveRecordIterator;
use UnderflowException;
use function count;
use function defined;
use function in_array;
use function is_null;
/* 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;
}
/**
* Messenger conversations query for GraphQL API
*/
class _MessengerConversations
class MessengerConversations
{
/*
* @brief Query description
*/
public static $description = "Returns a list of messenger conversations";
public static string $description = "Returns a list of messenger conversations";
/*
* Query arguments
@@ -66,7 +76,7 @@ class _MessengerConversations
'type' => TypeRegistry::eNum([
'name' => 'core_messengerConversations_orderBy',
'description' => 'Fields on which conversations can be sorted',
'values' => \IPS\core\api\GraphQL\Types\MessengerConversationType::getOrderByOptions()
'values' => MessengerConversationType::getOrderByOptions()
]),
'defaultValue' => 'last_post_time'
],
@@ -83,8 +93,10 @@ class _MessengerConversations
/**
* Return the query return type
*
* @return ListOfType<MessengerConversationType>
*/
public function type()
public function type() : ListOfType
{
return TypeRegistry::listOf( \IPS\core\api\GraphQL\TypeRegistry::messengerConversation() );
}
@@ -92,22 +104,23 @@ class _MessengerConversations
/**
* Resolves this query
*
* @param mixed Value passed into this resolver
* @param array Arguments
* @param array Context values
* @return \IPS\core\Messenger\Conversation
* @param mixed $val Value passed into this resolver
* @param array $args Arguments
* @param array $context Context values
* @param array $info
* @return ActiveRecordIterator|array
*/
public function resolve($val, $args, $context, $info)
public function resolve( mixed $val, array $args, array $context, array $info ) : ActiveRecordIterator|array
{
// 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 ) );
$where = array( array( 'core_message_topic_user_map.map_user_id=? AND core_message_topic_user_map.map_user_active=1', Member::loggedIn()->member_id ) );
$orderBy = 'mt_' . $args['orderBy'];
$offset = max( $args['offset'], 0 );
$limit = min( $args['limit'], 50 );
$iterator = NULL;
// Filters
if( !\is_null( $args['filter'] ) )
if( !is_null( $args['filter'] ) )
{
switch ($args['filter'] ) {
case "MINE":
@@ -126,7 +139,7 @@ class _MessengerConversations
}
// Folder
if ( !\is_null( $args['folder'] ) )
if ( !is_null( $args['folder'] ) )
{
$folderObj = \IPS\core\api\GraphQL\TypeRegistry::messengerFolder();
$folders = $folderObj->getMemberFolders();
@@ -138,33 +151,33 @@ class _MessengerConversations
}
// Search
if( !\is_null( $args['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 );
$subQuery = 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;
$prefix = Db::i()->prefix;
if ( !\is_null( $args['searchIn'] ) )
if ( !is_null( $args['searchIn'] ) )
{
if ( \in_array( 'TOPIC', $args['searchIn'] ) )
if ( in_array( 'TOPIC', $args['searchIn'] ) )
{
$query[] = \IPS\Content\Search\Mysql\Query::matchClause( "core_message_topics.mt_title", $args['search'], '+', FALSE );
$query[] = Query::matchClause( "core_message_topics.mt_title", $args['search'], '+', FALSE );
}
if ( \in_array( 'POST', $args['searchIn'] ) )
if ( in_array( 'POST', $args['searchIn'] ) )
{
$query[] = \IPS\Content\Search\Mysql\Query::matchClause( "core_message_posts.msg_post", $args['search'], '+', FALSE );
$query[] = Query::matchClause( "core_message_posts.msg_post", $args['search'], '+', FALSE );
}
if ( \in_array( 'RECIPIENT', $args['searchIn'] ) )
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'] ) . "%' ) )";
$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 '" . Db::i()->escape_string( $args['search'] ) . "%' ) )";
}
if ( \in_array( 'SENDER', $args['searchIn'] ) )
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'] ) . "%') )";
$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 '" . Db::i()->escape_string( $args['search'] ) . "%') )";
}
if ( \count( $query ) )
if ( count( $query ) )
{
$where[] = array( '(' . implode( ' OR ', $query ) . ')' );
}
@@ -173,7 +186,7 @@ class _MessengerConversations
/* Get a count */
try
{
$count = \IPS\Db::i()->select( 'COUNT(*)', 'core_message_posts', $where, NULL, NULL, 'msg_topic_id' )
$count = 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'
@@ -184,7 +197,7 @@ class _MessengerConversations
)
->first();
}
catch( \UnderflowException $e )
catch( UnderflowException $e )
{
$count = 0;
}
@@ -193,7 +206,7 @@ class _MessengerConversations
if( $count )
{
/* Because of strict group by, we first need to select the ids, then grab those topics */
$iterator = \IPS\Db::i()->select(
$iterator = Db::i()->select(
'core_message_posts.msg_topic_id',
'core_message_posts',
$where,
@@ -209,7 +222,7 @@ class _MessengerConversations
);
/* Get iterator */
$iterator = \IPS\Db::i()->select(
$iterator = 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 ) ) . ')' ),
@@ -223,7 +236,7 @@ class _MessengerConversations
else
{
/* Get iterator */
$iterator = \IPS\Db::i()->select(
$iterator = Db::i()->select(
'core_message_topic_user_map.*, core_message_topics.*',
'core_message_topic_user_map',
$where,
@@ -237,7 +250,7 @@ class _MessengerConversations
if( $iterator )
{
return new \IPS\Patterns\ActiveRecordIterator( $iterator, 'IPS\core\Messenger\Conversation' );
return new ActiveRecordIterator( $iterator, 'IPS\core\Messenger\Conversation' );
}
return array();
@@ -10,25 +10,28 @@
*/
namespace IPS\core\api\GraphQL\Queries;
use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\ListOfType;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\core\api\GraphQL\Types\MessengerFolderType;
use IPS\Member;
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;
}
/**
* Messenger folders query for GraphQL API
*/
class _MessengerFolders
class MessengerFolders
{
/*
* @brief Query description
*/
public static $description = "Returns the member's messenger folders";
public static string $description = "Returns the member's messenger folders";
/*
* Query arguments
@@ -42,8 +45,10 @@ class _MessengerFolders
/**
* Return the query return type
*
* @return ListOfType<MessengerFolderType>
*/
public function type()
public function type() : ListOfType
{
return TypeRegistry::listOf( \IPS\core\api\GraphQL\TypeRegistry::messengerFolder() );
}
@@ -51,14 +56,15 @@ class _MessengerFolders
/**
* Resolves this query
*
* @param mixed Value passed into this resolver
* @param array Arguments
* @param array Context values
* @return \IPS\core\Messenger\Conversation
* @param mixed $val Value passed into this resolver
* @param array $args Arguments
* @param array $context Context values
* @param array $info
* @return array|null
*/
public function resolve($val, $args, $context, $info)
public function resolve( mixed $val, array $args, array $context, array $info ) : ?array
{
if( !\IPS\Member::loggedIn()->member_id || \IPS\Member::loggedIn()->members_disable_pm )
if( !Member::loggedIn()->member_id || Member::loggedIn()->members_disable_pm )
{
return NULL;
}
@@ -10,25 +10,31 @@
*/
namespace IPS\core\api\GraphQL\Queries;
use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\ListOfType;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\Application;
use IPS\core\api\GraphQL\Types\NotificationTypeType;
use IPS\Member;
use IPS\Notification;
use function defined;
use function in_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;
}
/**
* NotificationTypes query for GraphQL API
*/
class _NotificationTypes
class NotificationTypes
{
/*
* @brief Query description
*/
public static $description = "Returns available notification types";
public static string $description = "Returns available notification types";
/*
* Query arguments
@@ -40,8 +46,10 @@ class _NotificationTypes
/**
* Return the query return type
*
* @return ListOfType<NotificationTypeType>
*/
public function type()
public function type() : ListOfType
{
return TypeRegistry::listOf( \IPS\core\api\GraphQL\TypeRegistry::notificationType() );
}
@@ -49,23 +57,23 @@ class _NotificationTypes
/**
* Resolves this query
*
* @param mixed Value passed into this resolver
* @param array Arguments
* @param array Context values
* @return \IPS\core\Stream
* @param mixed $val Value passed into this resolver
* @param array $args Arguments
* @param array $context Context values
* @return array
*/
public function resolve($val, $args, $context)
public function resolve( mixed $val, array $args, array $context ) : array
{
//$defaultConfiguration = \IPS\Notification::defaultConfiguration();
//$memberConfiguration = $member->notificationsConfiguration();
$notificationTypes = array();
$extensions = \IPS\Application::allExtensions( 'core', 'Notifications' );
$extensions = Application::allExtensions( 'core', 'Notifications' );
$availableOptions = array();
foreach( $extensions as $extensionKey => $extension )
{
$extensionOptions = \IPS\Notification::availableOptions( \IPS\Member::loggedIn(), $extension );
$extensionOptions = Notification::availableOptions( Member::loggedIn(), $extension );
foreach( $extensionOptions as $key => $option )
{
@@ -84,9 +92,9 @@ class _NotificationTypes
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;
$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'] = ( $option['options'][ $method ]['value'] == TRUE );
}
$notificationTypes[] = array(
@@ -10,25 +10,30 @@
*/
namespace IPS\core\api\GraphQL\Queries;
use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\ListOfType;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\core\api\GraphQL\Types\PromotedItemType;
use IPS\core\Feature;
use function count;
use function defined;
use function is_int;
/* 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;
}
/**
* OurPicks query for GraphQL API
*/
class _OurPicks
class OurPicks
{
/*
* @brief Query description
*/
public static $description = "Returns promoted items";
public static string $description = "Returns promoted items";
/*
* Query arguments
@@ -42,8 +47,10 @@ class _OurPicks
/**
* Return the query return type
*
* @return ListOfType<PromotedItemType>
*/
public function type()
public function type() : ListOfType
{
return TypeRegistry::listOf( \IPS\core\api\GraphQL\TypeRegistry::promotedItem() );
}
@@ -51,21 +58,21 @@ class _OurPicks
/**
* Resolves this query
*
* @param mixed Value passed into this resolver
* @param array Arguments
* @param array Context values
* @return \IPS\core\Stream
* @param mixed $val Value passed into this resolver
* @param array $args Arguments
* @param array $context Context values
* @return array|null
*/
public function resolve($val, $args, $context)
public function resolve( mixed $val, array $args, array $context ) : ?array
{
$limit = 7;
if( isset( $args['count'] ) && \is_int( $args['count'] ) )
if( isset( $args['count'] ) && is_int( $args['count'] ) )
{
$limit = $args['count'];
}
$items = \IPS\core\Promote::internalStream( $limit );
if( !\count( $items ) )
$items = Feature::internalStream( $limit );
if( !count( $items ) )
{
return NULL;
}
@@ -10,25 +10,31 @@
*/
namespace IPS\core\api\GraphQL\Queries;
use GraphQL\Type\Definition\ObjectType;
use DateInterval;
use GraphQL\Type\Definition\ListOfType;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\core\api\GraphQL\Types\PopularContributorType;
use IPS\DateTime;
use IPS\Db;
use IPS\Member;
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;
}
/**
* PopularContributors query for GraphQL API
*/
class _PopularContributors
class PopularContributors
{
/*
* @brief Query description
*/
public static $description = "Returns popular contributors";
public static string $description = "Returns popular contributors";
/*
* Query arguments
@@ -52,8 +58,10 @@ class _PopularContributors
/**
* Return the query return type
*
* @return ListOfType<PopularContributorType>
*/
public function type()
public function type() : ListOfType
{
return TypeRegistry::listOf( \IPS\core\api\GraphQL\TypeRegistry::popularContributor() );
}
@@ -61,12 +69,12 @@ class _PopularContributors
/**
* Resolves this query
*
* @param mixed Value passed into this resolver
* @param array Arguments
* @param array Context values
* @return \IPS\core\Stream
* @param mixed $val Value passed into this resolver
* @param array $args Arguments
* @param array $context Context values
* @return array
*/
public function resolve($val, $args, $context)
public function resolve( mixed $val, array $args, array $context ) : array
{
/* How many? */
$limit = min( $args['limit'], 25 );
@@ -79,29 +87,29 @@ class _PopularContributors
switch ( $args['period'] )
{
case 'WEEK':
$where[] = array( 'rep_date>' . \IPS\DateTime::create()->sub( new \DateInterval( 'P1W' ) )->getTimestamp() );
$where[] = array( 'rep_date>' . DateTime::create()->sub( new DateInterval( 'P1W' ) )->getTimestamp() );
break;
case 'MONTH':
$where[] = array( 'rep_date>' . \IPS\DateTime::create()->sub( new \DateInterval( 'P1M' ) )->getTimestamp() );
$where[] = array( 'rep_date>' . DateTime::create()->sub( new DateInterval( 'P1M' ) )->getTimestamp() );
break;
case 'YEAR':
$where[] = array( 'rep_date>' . \IPS\DateTime::create()->sub( new \DateInterval( 'P1Y' ) )->getTimestamp() );
$where[] = array( 'rep_date>' . 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') );
$innerQuery = 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( 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') );
$topContributors = iterator_to_array( 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 )
foreach ( Db::i()->select( '*', 'core_members', Db::i()->in( 'member_id', array_keys( $topContributors ) ) ) as $member )
{
\IPS\Member::constructFromData( $member );
Member::constructFromData( $member );
}
$output = array();
@@ -10,25 +10,34 @@
*/
namespace IPS\core\api\GraphQL\Queries;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\Application\Module;
use IPS\Content\Search\ContentFilter;
use IPS\Content\Search\Query;
use IPS\core\api\GraphQL\Types\SearchType;
use IPS\core\modules\front\search\search as searchController;
use IPS\Db;
use IPS\Member;
use IPS\Patterns\ActiveRecordIterator;
use function defined;
use function in_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;
}
/**
* Search query for GraphQL API
*/
class _Search
class Search
{
/*
* @brief Query description
*/
public static $description = "Returns search results";
public static string $description = "Returns search results";
/*
* Query arguments
@@ -41,7 +50,7 @@ class _Search
'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() ) )
'values' => array_merge( array('core_members'), array_keys( searchController::contentTypes() ) )
]),
],
'offset' => [
@@ -73,7 +82,7 @@ class _Search
/**
* Return the query return type
*/
public function type()
public function type() : SearchType
{
return \IPS\core\api\GraphQL\TypeRegistry::search();
}
@@ -81,12 +90,12 @@ class _Search
/**
* Resolves this query
*
* @param mixed Value passed into this resolver
* @param array Arguments
* @param array Context values
* @return \IPS\core\Stream
* @param mixed $val Value passed into this resolver
* @param array $args Arguments
* @param array $context Context values
* @return array
*/
public function resolve($val, $args, $context)
public function resolve( mixed $val, array $args, array $context ) : array
{
$where = array();
$returnObject = array();
@@ -94,7 +103,7 @@ class _Search
$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 ( isset( $args['type'] ) and $args['type'] === 'core_members' and Member::loggedIn()->canAccessModule( Module::get( 'core', 'members', 'front' ) ) )
{
if ( $args['term'] )
{
@@ -106,10 +115,10 @@ class _Search
}
// Ordering
$orderDir = isset( $args['orderDir'] ) ? $args['orderDir'] : 'DESC';
$orderDir = $args['orderDir'] ?? 'DESC';
$orderBy = 'name';
if( isset( $args['orderBy'] ) && \in_array( $args['orderBy'], array( 'joined', 'name', 'member_posts', 'pp_reputation_points' ) ) )
if( isset( $args['orderBy'] ) && in_array( $args['orderBy'], array( 'joined', 'name', 'member_posts', 'pp_reputation_points' ) ) )
{
$orderBy = $args['orderBy'];
}
@@ -117,26 +126,26 @@ class _Search
$order = $orderBy . ' ' . $orderDir;
// Get results
$select = \IPS\Db::i()->select( 'COUNT(*)', 'core_members', $where );
$select = 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 = 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' );
$returnObject['results'] = new ActiveRecordIterator( $select, 'IPS\Member' );
return $returnObject;
}
// Content search
$query = \IPS\Content\Search\Query::init();
$types = \IPS\core\modules\front\search\search::contentTypes();
$query = Query::init();
$types = searchController::contentTypes();
if( isset( $args['type'] ) && !empty( $args['type'] ) )
if( !empty( $args['type'] ) )
{
$class = $types[ $args['type'] ];
$filter = \IPS\Content\Search\ContentFilter::init( $class );
$filter = ContentFilter::init( $class );
$query->filterByContent( array( $filter ) );
}
@@ -148,10 +157,10 @@ class _Search
switch( $args['orderBy'] )
{
case 'newest':
$query->setOrder( \IPS\Content\Search\Query::ORDER_NEWEST_CREATED );
$query->setOrder( Query::ORDER_NEWEST_CREATED );
break;
case 'relevancy':
$query->setOrder( \IPS\Content\Search\Query::ORDER_RELEVANCY );
$query->setOrder( Query::ORDER_RELEVANCY );
break;
default:
$query->setOrder( $orderBy );
@@ -179,7 +188,7 @@ class _Search
$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,
Query::TERM_AND_TAGS + Query::TAGS_MATCH_ITEMS_ONLY,
NULL
);
$returnObject['count'] = $returnObject['results']->count( TRUE );
@@ -10,26 +10,28 @@
*/
namespace IPS\core\api\GraphQL\Queries;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\core\api\GraphQL\TypeRegistry;
use IPS\core\api\GraphQL\Types\SettingsType;
use IPS\Settings as SettingsClass;
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;
}
/**
* Settings query for GraphQL API
*/
class _Settings
class Settings
{
/*
* @brief Query description
*/
public static $description = "Returns values of system settings (subject to the setting being exposed by the API)";
public static string $description = "Returns values of system settings (subject to the setting being exposed by the API)";
/*
* Query arguments
@@ -42,21 +44,21 @@ class _Settings
/**
* Return the query return type
*/
public function type()
public function type() : SettingsType
{
return \IPS\core\api\GraphQL\TypeRegistry::settings();
return TypeRegistry::settings();
}
/**
* Resolves this query
*
* @param mixed Value passed into this resolver
* @param array Arguments
* @param array Context values
* @return \IPS\Settings
* @param mixed $val Value passed into this resolver
* @param array $args Arguments
* @param array $context Context values
* @return SettingsClass
*/
public function resolve($val, $args, $context)
public function resolve( mixed $val, array $args, array $context ) : SettingsClass
{
return \IPS\Settings::i();
return SettingsClass::i();
}
}
+14 -13
View File
@@ -10,25 +10,26 @@
*/
namespace IPS\core\api\GraphQL\Queries;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\core\api\GraphQL\TypeRegistry;
use IPS\core\api\GraphQL\Types\StatsType;
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;
}
/**
* Stats query for GraphQL API
*/
class _Stats
class Stats
{
/*
* @brief Query description
*/
public static $description = "Returns community stats";
public static string $description = "Returns community stats";
/*
* Query arguments
@@ -41,20 +42,20 @@ class _Stats
/**
* Return the query return type
*/
public function type()
public function type() : StatsType
{
return \IPS\core\api\GraphQL\TypeRegistry::stats();
return TypeRegistry::stats();
}
/**
* Resolves this query
*
* @param mixed Value passed into this resolver
* @param array Arguments
* @param array Context values
* @return \IPS\core\Stream
* @param mixed $val Value passed into this resolver
* @param array $args Arguments
* @param array $context Context values
* @return mixed
*/
public function resolve($val, $args, $context)
public function resolve( mixed $val, array $args, array $context ) : mixed
{
return $val;
}
@@ -10,25 +10,31 @@
*/
namespace IPS\core\api\GraphQL\Queries;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\SafeException;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\core\api\GraphQL\Types\StreamType;
use IPS\core\Stream as StreamClass;
use IPS\Member;
use OutOfRangeException;
use function defined;
use function intval;
/* 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;
}
/**
* Stream query for GraphQL API
*/
class _Stream
class Stream
{
/*
* @brief Query description
*/
public static $description = "Returns an activity stream";
public static string $description = "Returns an activity stream";
/*
* Query arguments
@@ -43,7 +49,7 @@ class _Stream
/**
* Return the query return type
*/
public function type()
public function type() : StreamType
{
return \IPS\core\api\GraphQL\TypeRegistry::stream();
}
@@ -51,34 +57,34 @@ class _Stream
/**
* Resolves this query
*
* @param mixed Value passed into this resolver
* @param array Arguments
* @param array Context values
* @return \IPS\core\Stream
* @param mixed $val Value passed into this resolver
* @param array $args Arguments
* @param array $context Context values
* @return StreamClass|null
*/
public function resolve($val, $args, $context)
public function resolve( mixed $val, array $args, array $context ) : ?StreamClass
{
if( isset( $args['id'] ) && \intval( $args['id'] ) )
if( isset( $args['id'] ) && intval( $args['id'] ) )
{
try
{
$stream = \IPS\core\Stream::load( $args['id'] );
$stream = StreamClass::load( $args['id'] );
}
catch ( \OutOfRangeException $e )
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' ) )
if ( !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 );
throw new SafeException( 'INVALID_STREAM', 'GQL/0003/1', 403 );
}
}
else
{
/* Start with a blank stream */
$stream = \IPS\core\Stream::allActivityStream();
$stream = StreamClass::allActivityStream();
}
return $stream;
@@ -10,26 +10,31 @@
*/
namespace IPS\core\api\GraphQL\Queries;
use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\ListOfType;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\core\api\GraphQL\Types\StreamType;
use IPS\Db;
use IPS\Member;
use IPS\Patterns\ActiveRecordIterator;
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;
}
/**
* Streams query for GraphQL API
*/
class _Streams
class Streams
{
/*
* @brief Query description
*/
public static $description = "Returns a list of user's activity streams";
public static string $description = "Returns a list of user's activity streams";
/*
* @brief Query arguments
@@ -41,8 +46,10 @@ class _Streams
/**
* Return the query return type
*
* @return ListOfType<StreamType>
*/
public function type()
public function type() : ListOfType
{
return TypeRegistry::listOf( \IPS\core\api\GraphQL\TypeRegistry::stream() );
}
@@ -50,26 +57,26 @@ class _Streams
/**
* 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
* @return array
*/
public function resolve($val, $args, $context)
public function resolve( mixed $val, array $args, array $context ) : array
{
$streams = array();
foreach ( new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'core_streams', '`member` IS NULL', 'position ASC' ), 'IPS\core\Stream' ) as $stream )
foreach ( new ActiveRecordIterator( 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' ) ) )
if( Member::loggedIn()->member_id || ( !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 )
if ( 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 )
foreach ( new ActiveRecordIterator( Db::i()->select( '*', 'core_streams', array( '`member`=?', Member::loggedIn()->member_id ), 'position ASC' ), 'IPS\core\Stream' ) as $stream )
{
$streams[ $stream->id ] = $stream;
}
+46 -26
View File
@@ -10,13 +10,33 @@
*/
namespace IPS\core\api\GraphQL;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\core\api\GraphQL\Queries\ActiveUsers;
use IPS\core\api\GraphQL\Queries\Club;
use IPS\core\api\GraphQL\Queries\Clubs;
use IPS\core\api\GraphQL\Queries\Content;
use IPS\core\api\GraphQL\Queries\Group;
use IPS\core\api\GraphQL\Queries\Language;
use IPS\core\api\GraphQL\Queries\LoginHandlers;
use IPS\core\api\GraphQL\Queries\Me;
use IPS\core\api\GraphQL\Queries\Member;
use IPS\core\api\GraphQL\Queries\Members;
use IPS\core\api\GraphQL\Queries\MessengerConversation;
use IPS\core\api\GraphQL\Queries\MessengerConversations;
use IPS\core\api\GraphQL\Queries\MessengerFolders;
use IPS\core\api\GraphQL\Queries\NotificationTypes;
use IPS\core\api\GraphQL\Queries\OurPicks;
use IPS\core\api\GraphQL\Queries\PopularContributors;
use IPS\core\api\GraphQL\Queries\Search;
use IPS\core\api\GraphQL\Queries\Settings;
use IPS\core\api\GraphQL\Queries\Stats;
use IPS\core\api\GraphQL\Queries\Stream;
use IPS\core\api\GraphQL\Queries\Streams;
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;
}
@@ -24,7 +44,7 @@ if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
* Core controller for GraphQL API
* @todo maybe this shouldn't be a class since it only has a static method?
*/
abstract class _Query
abstract class Query
{
/**
@@ -35,27 +55,27 @@ abstract class _Query
public static function queries(): array
{
return [
'activeUsers' => new \IPS\core\api\GraphQL\Queries\ActiveUsers(),
'club' => new \IPS\core\api\GraphQL\Queries\Club(),
'clubs' => new \IPS\core\api\GraphQL\Queries\Clubs(),
'content' => new \IPS\core\api\GraphQL\Queries\Content(),
'group' => new \IPS\core\api\GraphQL\Queries\Group(),
'language' => new \IPS\core\api\GraphQL\Queries\Language(),
'loginHandlers' => new \IPS\core\api\GraphQL\Queries\LoginHandlers(),
'me' => new \IPS\core\api\GraphQL\Queries\Me(),
'member' => new \IPS\core\api\GraphQL\Queries\Member(),
'members' => new \IPS\core\api\GraphQL\Queries\Members(),
'messengerConversation' => new \IPS\core\api\GraphQL\Queries\MessengerConversation(),
'messengerConversations' => new \IPS\core\api\GraphQL\Queries\MessengerConversations(),
'messengerFolders' => new \IPS\core\api\GraphQL\Queries\MessengerFolders(),
'notificationTypes' => new \IPS\core\api\GraphQL\Queries\NotificationTypes(),
'ourPicks' => new \IPS\core\api\GraphQL\Queries\OurPicks(),
'popularContributors' => new \IPS\core\api\GraphQL\Queries\PopularContributors(),
'search' => new \IPS\core\api\GraphQL\Queries\Search(),
'settings' => new \IPS\core\api\GraphQL\Queries\Settings(),
'stats' => new \IPS\core\api\GraphQL\Queries\Stats(),
'stream' => new \IPS\core\api\GraphQL\Queries\Stream(),
'streams' => new \IPS\core\api\GraphQL\Queries\Streams(),
'activeUsers' => new ActiveUsers(),
'club' => new Club(),
'clubs' => new Clubs(),
'content' => new Content(),
'group' => new Group(),
'language' => new Language(),
'loginHandlers' => new LoginHandlers(),
'me' => new Me(),
'member' => new Member(),
'members' => new Members(),
'messengerConversation' => new MessengerConversation(),
'messengerConversations' => new MessengerConversations(),
'messengerFolders' => new MessengerFolders(),
'notificationTypes' => new NotificationTypes(),
'ourPicks' => new OurPicks(),
'popularContributors' => new PopularContributors(),
'search' => new Search(),
'settings' => new Settings(),
'stats' => new Stats(),
'stream' => new Stream(),
'streams' => new Streams(),
];
}
}
+179 -145
View File
@@ -10,13 +10,47 @@
*/
namespace IPS\core\api\GraphQL;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\Types;
use IPS\core\api\GraphQL\Types\ActiveUsersType;
use IPS\core\api\GraphQL\Types\ActiveUserType;
use IPS\core\api\GraphQL\Types\AttachmentPermissionsType;
use IPS\core\api\GraphQL\Types\AttachmentType;
use IPS\core\api\GraphQL\Types\ClubNodeType;
use IPS\core\api\GraphQL\Types\ClubType;
use IPS\core\api\GraphQL\Types\ContentReactionType;
use IPS\core\api\GraphQL\Types\ContentSearchResultType;
use IPS\core\api\GraphQL\Types\GroupType;
use IPS\core\api\GraphQL\Types\IgnoreOptionType;
use IPS\core\api\GraphQL\Types\LanguageType;
use IPS\core\api\GraphQL\Types\LoginType;
use IPS\core\api\GraphQL\Types\MemberType;
use IPS\core\api\GraphQL\Types\MessengerConversationType;
use IPS\core\api\GraphQL\Types\MessengerFolderType;
use IPS\core\api\GraphQL\Types\MessengerParticipantType;
use IPS\core\api\GraphQL\Types\MessengerReplyType;
use IPS\core\api\GraphQL\Types\NotificationMethodType;
use IPS\core\api\GraphQL\Types\NotificationType;
use IPS\core\api\GraphQL\Types\NotificationTypeType;
use IPS\core\api\GraphQL\Types\PollQuestionType;
use IPS\core\api\GraphQL\Types\PollType;
use IPS\core\api\GraphQL\Types\PopularContributorType;
use IPS\core\api\GraphQL\Types\ProfileFieldGroupType;
use IPS\core\api\GraphQL\Types\ProfileFieldType;
use IPS\core\api\GraphQL\Types\PromotedItemType;
use IPS\core\api\GraphQL\Types\ReportReasonType;
use IPS\core\api\GraphQL\Types\ReportType;
use IPS\core\api\GraphQL\Types\SearchResultType;
use IPS\core\api\GraphQL\Types\SearchType;
use IPS\core\api\GraphQL\Types\SettingsType;
use IPS\core\api\GraphQL\Types\StatsType;
use IPS\core\api\GraphQL\Types\StreamType;
use IPS\core\api\GraphQL\Types\TagType;
use IPS\core\api\GraphQL\Types\UploadProgressType;
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;
}
@@ -25,43 +59,43 @@ if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
* so we'll generate singletons here.
* @todo automate this somehow?
*/
class _TypeRegistry
class TypeRegistry
{
protected static $activeUsers;
protected static $activeUser;
protected static $attachment;
protected static $attachmentPermissions;
protected static $clubNode;
protected static $club;
protected static $contentReaction;
protected static $contentSearchResult;
protected static $group;
protected static $ignoreOption;
protected static $member;
protected static $language;
protected static $login;
protected static $messengerConversation;
protected static $messengerFolder;
protected static $messengerParticipant;
protected static $messengerReply;
protected static $notification;
protected static $notificationMethod;
protected static $notificationType;
protected static $poll;
protected static $pollQuestion;
protected static $popularContributor;
protected static $profileFieldGroup;
protected static $profileField;
protected static $promotedItem;
protected static $report;
protected static $reportReason;
protected static $search;
protected static $searchResult;
protected static $stats;
protected static $stream;
protected static $tag;
protected static $settings;
protected static $uploadProgress;
protected static ?ActiveUsersType $activeUsers = null;
protected static ?ActiveUserType $activeUser = null;
protected static ?AttachmentType $attachment = null;
protected static ?AttachmentPermissionsType $attachmentPermissions = null;
protected static ?ClubNodeType $clubNode = null;
protected static ?ClubType $club = null;
protected static ?ContentReactionType $contentReaction = null;
protected static ?ContentSearchResultType $contentSearchResult = null;
protected static ?GroupType $group = null;
protected static ?IgnoreOptionType $ignoreOption = null;
protected static ?MemberType $member = null;
protected static ?LanguageType $language = null;
protected static ?LoginType $login = null;
protected static ?MessengerConversationType $messengerConversation = null;
protected static ?MessengerFolderType $messengerFolder = null;
protected static ?MessengerParticipantType $messengerParticipant = null;
protected static ?MessengerReplyType $messengerReply = null;
protected static ?NotificationType $notification = null;
protected static ?NotificationMethodType $notificationMethod = null;
protected static ?NotificationTypeType $notificationType = null;
protected static ?PollType $poll = null;
protected static ?PollQuestionType $pollQuestion = null;
protected static ?PopularContributorType $popularContributor = null;
protected static ?ProfileFieldGroupType $profileFieldGroup = null;
protected static ?ProfileFieldType $profileField = null;
protected static ?PromotedItemType $promotedItem = null;
protected static ?ReportType $report = null;
protected static ?ReportReasonType $reportReason = null;
protected static ?SearchType $search = null;
protected static ?SearchResultType $searchResult = null;
protected static ?StatsType $stats = null;
protected static ?StreamType $stream = null;
protected static ?TagType $tag = null;
protected static ?SettingsType $settings = null;
protected static ?UploadProgressType $uploadProgress = null;
/**
* Constructor
@@ -72,282 +106,282 @@ class _TypeRegistry
}
/**
* @return \IPS\core\api\GraphQL\Types\ActiveUsersType
* @return ActiveUsersType
*/
public static function activeUsers()
public static function activeUsers() : ActiveUsersType
{
return self::$activeUsers ?: (self::$activeUsers = new \IPS\core\api\GraphQL\Types\ActiveUsersType());
return self::$activeUsers ?: (self::$activeUsers = new ActiveUsersType());
}
/**
* @return \IPS\core\api\GraphQL\Types\ActiveUserType
* @return ActiveUserType
*/
public static function activeUser()
public static function activeUser() : ActiveUserType
{
return self::$activeUser ?: (self::$activeUser = new \IPS\core\api\GraphQL\Types\ActiveUserType());
return self::$activeUser ?: (self::$activeUser = new ActiveUserType());
}
/**
* @return \IPS\core\api\GraphQL\Types\AttachmentType
* @return AttachmentType
*/
public static function attachment()
public static function attachment() : AttachmentType
{
return self::$attachment ?: (self::$attachment = new \IPS\core\api\GraphQL\Types\AttachmentType());
return self::$attachment ?: (self::$attachment = new AttachmentType());
}
/**
* @return \IPS\core\api\GraphQL\Types\AttachmentPermissionsType
* @return AttachmentPermissionsType
*/
public static function attachmentPermissions()
public static function attachmentPermissions() : AttachmentPermissionsType
{
return self::$attachmentPermissions ?: (self::$attachmentPermissions = new \IPS\core\api\GraphQL\Types\AttachmentPermissionsType());
return self::$attachmentPermissions ?: (self::$attachmentPermissions = new AttachmentPermissionsType());
}
/**
* @return \IPS\core\api\GraphQL\Types\ClubNodeType
* @return ClubNodeType
*/
public static function clubNode()
public static function clubNode() : ClubNodeType
{
return self::$clubNode ?: (self::$clubNode = new \IPS\core\api\GraphQL\Types\ClubNodeType());
return self::$clubNode ?: (self::$clubNode = new ClubNodeType());
}
/**
* @return \IPS\core\api\GraphQL\Types\ClubType
* @return ClubType
*/
public static function club()
public static function club() : ClubType
{
return self::$club ?: (self::$club = new \IPS\core\api\GraphQL\Types\ClubType());
return self::$club ?: (self::$club = new ClubType());
}
/**
* @return \IPS\core\api\GraphQL\Types\ContentReactionType
* @return ContentReactionType
*/
public static function contentReaction()
public static function contentReaction() : ContentReactionType
{
return self::$contentReaction ?: (self::$contentReaction = new \IPS\core\api\GraphQL\Types\ContentReactionType());
return self::$contentReaction ?: (self::$contentReaction = new ContentReactionType());
}
/**
* @return \IPS\core\api\GraphQL\Types\GroupType
* @return GroupType
*/
public static function group()
public static function group() : GroupType
{
return self::$group ?: (self::$group = new \IPS\core\api\GraphQL\Types\GroupType());
return self::$group ?: (self::$group = new GroupType());
}
/**
* @return \IPS\core\api\GraphQL\Types\IgnoreOptionType
* @return IgnoreOptionType
*/
public static function ignoreOption()
public static function ignoreOption() : IgnoreOptionType
{
return self::$ignoreOption ?: (self::$ignoreOption = new \IPS\core\api\GraphQL\Types\IgnoreOptionType());
return self::$ignoreOption ?: (self::$ignoreOption = new IgnoreOptionType());
}
/**
* @return \IPS\core\api\GraphQL\Types\MemberType
* @return MemberType
*/
public static function member()
public static function member() : MemberType
{
return self::$member ?: (self::$member = new \IPS\core\api\GraphQL\Types\MemberType());
return self::$member ?: (self::$member = new MemberType());
}
/**
* @return \IPS\core\api\GraphQL\Types\LanguageType
* @return LanguageType
*/
public static function language()
public static function language() : LanguageType
{
return self::$language ?: (self::$language = new \IPS\core\api\GraphQL\Types\LanguageType());
return self::$language ?: (self::$language = new LanguageType());
}
/**
* @return \IPS\core\api\GraphQL\Types\LoginType
* @return LoginType
*/
public static function login()
public static function login() : LoginType
{
return self::$login ?: (self::$login = new \IPS\core\api\GraphQL\Types\LoginType());
return self::$login ?: (self::$login = new LoginType());
}
/**
* @return \IPS\core\api\GraphQL\Types\MessengerConversationType
* @return MessengerConversationType
*/
public static function messengerConversation()
public static function messengerConversation() : MessengerConversationType
{
return self::$messengerConversation ?: (self::$messengerConversation = new \IPS\core\api\GraphQL\Types\MessengerConversationType());
return self::$messengerConversation ?: (self::$messengerConversation = new MessengerConversationType());
}
/**
* @return \IPS\core\api\GraphQL\Types\MessengerFolderType
* @return MessengerFolderType
*/
public static function messengerFolder()
public static function messengerFolder() : MessengerFolderType
{
return self::$messengerFolder ?: (self::$messengerFolder = new \IPS\core\api\GraphQL\Types\MessengerFolderType());
return self::$messengerFolder ?: (self::$messengerFolder = new MessengerFolderType());
}
/**
* @return \IPS\core\api\GraphQL\Types\MessengerParticipantType
* @return MessengerParticipantType
*/
public static function messengerParticipant()
public static function messengerParticipant() : MessengerParticipantType
{
return self::$messengerParticipant ?: (self::$messengerParticipant = new \IPS\core\api\GraphQL\Types\MessengerParticipantType());
return self::$messengerParticipant ?: (self::$messengerParticipant = new MessengerParticipantType());
}
/**
* @return \IPS\core\api\GraphQL\Types\MessengerReplyType
* @return MessengerReplyType
*/
public static function messengerReply()
public static function messengerReply() : MessengerReplyType
{
return self::$messengerReply ?: (self::$messengerReply = new \IPS\core\api\GraphQL\Types\MessengerReplyType());
return self::$messengerReply ?: (self::$messengerReply = new MessengerReplyType());
}
/**
* @return \IPS\core\api\GraphQL\Types\NotificationType
* @return NotificationType
*/
public static function notification()
public static function notification() : NotificationType
{
return self::$notification ?: (self::$notification = new \IPS\core\api\GraphQL\Types\NotificationType());
return self::$notification ?: (self::$notification = new NotificationType());
}
/**
* @return \IPS\core\api\GraphQL\Types\NotificationMethodType
* @return NotificationMethodType
*/
public static function notificationMethod()
public static function notificationMethod() : NotificationMethodType
{
return self::$notificationMethod ?: (self::$notificationMethod = new \IPS\core\api\GraphQL\Types\NotificationMethodType());
return self::$notificationMethod ?: (self::$notificationMethod = new NotificationMethodType());
}
/**
* @return \IPS\core\api\GraphQL\Types\NotificationTypeType
* @return NotificationTypeType
*/
public static function notificationType()
public static function notificationType() : NotificationTypeType
{
return self::$notificationType ?: (self::$notificationType = new \IPS\core\api\GraphQL\Types\NotificationTypeType());
return self::$notificationType ?: (self::$notificationType = new NotificationTypeType());
}
/**
* @return \IPS\core\api\GraphQL\Types\PollType
* @return PollType
*/
public static function poll()
public static function poll() : PollType
{
return self::$poll ?: (self::$poll = new \IPS\core\api\GraphQL\Types\PollType());
return self::$poll ?: (self::$poll = new PollType());
}
/**
* @return \IPS\core\api\GraphQL\Types\PollQuestionType
* @return PollQuestionType
*/
public static function pollQuestion(): \IPS\core\api\GraphQL\Types\PollQuestionType
public static function pollQuestion(): PollQuestionType
{
return self::$pollQuestion ?: (self::$pollQuestion = new \IPS\core\api\GraphQL\Types\PollQuestionType());
return self::$pollQuestion ?: (self::$pollQuestion = new PollQuestionType());
}
/**
* @return \IPS\core\api\GraphQL\Types\PopularContributorType
* @return PopularContributorType
*/
public static function popularContributor(): \IPS\core\api\GraphQL\Types\PopularContributorType
public static function popularContributor(): PopularContributorType
{
return self::$popularContributor ?: (self::$popularContributor = new \IPS\core\api\GraphQL\Types\PopularContributorType());
return self::$popularContributor ?: (self::$popularContributor = new PopularContributorType());
}
/**
* @return \IPS\core\api\GraphQL\Types\ProfileFieldGroupType
* @return ProfileFieldGroupType
*/
public static function profileFieldGroup(): \IPS\core\api\GraphQL\Types\ProfileFieldGroupType
public static function profileFieldGroup(): ProfileFieldGroupType
{
return self::$profileFieldGroup ?: (self::$profileFieldGroup = new \IPS\core\api\GraphQL\Types\ProfileFieldGroupType());
return self::$profileFieldGroup ?: (self::$profileFieldGroup = new ProfileFieldGroupType());
}
/**
* @return \IPS\core\api\GraphQL\Types\ProfileFieldType
* @return ProfileFieldType
*/
public static function profileField(): \IPS\core\api\GraphQL\Types\ProfileFieldType
public static function profileField(): ProfileFieldType
{
return self::$profileField ?: (self::$profileField = new \IPS\core\api\GraphQL\Types\ProfileFieldType());
return self::$profileField ?: (self::$profileField = new ProfileFieldType());
}
/**
* @return \IPS\core\api\GraphQL\Types\PromotedItemType
* @return PromotedItemType
*/
public static function promotedItem(): \IPS\core\api\GraphQL\Types\PromotedItemType
public static function promotedItem(): PromotedItemType
{
return self::$promotedItem ?: (self::$promotedItem = new \IPS\core\api\GraphQL\Types\PromotedItemType());
return self::$promotedItem ?: (self::$promotedItem = new PromotedItemType());
}
/**
* @return \IPS\core\api\GraphQL\Types\ContentSearchResultType
* @return ContentSearchResultType
*/
public static function contentSearchResult(): \IPS\core\api\GraphQL\Types\ContentSearchResultType
public static function contentSearchResult(): ContentSearchResultType
{
return self::$contentSearchResult ?: (self::$contentSearchResult = new \IPS\core\api\GraphQL\Types\ContentSearchResultType());
return self::$contentSearchResult ?: (self::$contentSearchResult = new ContentSearchResultType());
}
/**
* @return \IPS\core\api\GraphQL\Types\ReportType
* @return ReportType
*/
public static function report(): \IPS\core\api\GraphQL\Types\ReportType
public static function report(): ReportType
{
return self::$report ?: (self::$report = new \IPS\core\api\GraphQL\Types\ReportType());
return self::$report ?: (self::$report = new ReportType());
}
/**
* @return \IPS\core\api\GraphQL\Types\ReportReasonType
* @return ReportReasonType
*/
public static function reportReason(): \IPS\core\api\GraphQL\Types\ReportReasonType
public static function reportReason(): ReportReasonType
{
return self::$reportReason ?: (self::$reportReason = new \IPS\core\api\GraphQL\Types\ReportReasonType());
return self::$reportReason ?: (self::$reportReason = new ReportReasonType());
}
/**
* @return \IPS\core\api\GraphQL\Types\SearchResultType
* @return SearchResultType
*/
public static function searchResult(): \IPS\core\api\GraphQL\Types\SearchResultType
public static function searchResult(): SearchResultType
{
return self::$searchResult ?: (self::$searchResult = new \IPS\core\api\GraphQL\Types\SearchResultType());
return self::$searchResult ?: (self::$searchResult = new SearchResultType());
}
/**
* @return \IPS\core\api\GraphQL\Types\SearchType
* @return SearchType
*/
public static function search(): \IPS\core\api\GraphQL\Types\SearchType
public static function search(): SearchType
{
return self::$search ?: (self::$search = new \IPS\core\api\GraphQL\Types\SearchType());
return self::$search ?: (self::$search = new SearchType());
}
/**
* @return \IPS\core\api\GraphQL\Types\StatsType
* @return StatsType
*/
public static function stats(): \IPS\core\api\GraphQL\Types\StatsType
public static function stats(): StatsType
{
return self::$stats ?: (self::$stats = new \IPS\core\api\GraphQL\Types\StatsType());
return self::$stats ?: (self::$stats = new StatsType());
}
/**
* @return \IPS\core\api\GraphQL\Types\StreamType
* @return StreamType
*/
public static function stream(): \IPS\core\api\GraphQL\Types\StreamType
public static function stream(): StreamType
{
return self::$stream ?: (self::$stream = new \IPS\core\api\GraphQL\Types\StreamType());
return self::$stream ?: (self::$stream = new StreamType());
}
/**
* @return \IPS\core\api\GraphQL\Types\TagType
* @return TagType
*/
public static function tag(): \IPS\core\api\GraphQL\Types\TagType
public static function tag(): TagType
{
return self::$tag ?: (self::$tag = new \IPS\core\api\GraphQL\Types\TagType());
return self::$tag ?: (self::$tag = new TagType());
}
/**
* @return \IPS\core\api\GraphQL\Types\SettingsType
* @return SettingsType
*/
public static function settings(): \IPS\core\api\GraphQL\Types\SettingsType
public static function settings(): SettingsType
{
return self::$settings ?: (self::$settings = new \IPS\core\api\GraphQL\Types\SettingsType());
return self::$settings ?: (self::$settings = new SettingsType());
}
/**
* @return \IPS\core\api\GraphQL\Types\UploadProgressType
* @return UploadProgressType
*/
public static function uploadProgress(): \IPS\core\api\GraphQL\Types\UploadProgressType
public static function uploadProgress(): UploadProgressType
{
return self::$uploadProgress ?: (self::$uploadProgress = new \IPS\core\api\GraphQL\Types\UploadProgressType());
return self::$uploadProgress ?: (self::$uploadProgress = new UploadProgressType());
}
}
@@ -12,23 +12,27 @@
namespace IPS\core\api\GraphQL\Types;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\Http\Url;
use IPS\Member;
use IPS\Session\Front;
use UnderflowException;
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;
}
/**
* ActiveUsers for GraphQL API
*/
class _ActiveUserType extends ObjectType
class ActiveUserType extends ObjectType
{
/**
* Get object type
*
* @return ObjectType
*/
public function __construct()
{
@@ -38,8 +42,8 @@ class _ActiveUserType extends ObjectType
return [
'url' => [
'type' => TypeRegistry::url(),
'resolve' => function ($user, $args) {
return \IPS\Http\Url::createFromString( $user['location_url'] );
'resolve' => function ($user) {
return Url::createFromString( $user['location_url'] );
}
],
'lang' => [
@@ -56,14 +60,14 @@ class _ActiveUserType extends ObjectType
],
'anonymous' => [
'type' => TypeRegistry::boolean(),
'resolve' => function ($user, $args) {
return $user['login_type'] == \IPS\Session\Front::LOGIN_TYPE_ANONYMOUS;
'resolve' => function ($user) {
return $user['login_type'] == Front::LOGIN_TYPE_ANONYMOUS;
}
],
'ipAddress' => [
'type' => TypeRegistry::string(),
'resolve' => function ($user, $args) {
if( \IPS\Member::loggedIn()->modPermission( 'can_use_ip_tools' ) )
'resolve' => function ($user) {
if( Member::loggedIn()->modPermission( 'can_use_ip_tools' ) )
{
return $user['ip_address'];
}
@@ -73,19 +77,19 @@ class _ActiveUserType extends ObjectType
],
'timestamp' => [
'type' => TypeRegistry::int(),
'resolve' => function ($user, $args) {
'resolve' => function ($user) {
return $user['running_time'];
}
],
'user' => [
'type' => \IPS\core\api\GraphQL\TypeRegistry::member(),
'resolve' => function ($user, $args) {
'resolve' => function ($user) {
if( $user['member_id'] )
{
return \IPS\Member::load( $user['member_id'] );
return Member::load( $user['member_id'] );
}
return new \IPS\Member;
return new Member;
}
]
];
@@ -100,18 +104,18 @@ class _ActiveUserType extends ObjectType
* @todo this calls language()->get(), so we need to figure out we can get the keys in advance to load them
* @param array $user The active user row from session store
* @param boolean $action Use the 'action' version of the language string?
* @return String
* @return string|null
*/
protected static function getLocationLang($user, $action)
protected static function getLocationLang( array $user, bool $action ) : ?string
{
try
{
if( !$user['location_lang'] )
{
return \IPS\Member::loggedIn()->language()->addToStack( 'app_user_browsing_community', FALSE, array('sprintf' => array( $user['member_name'] ) ) );
return Member::loggedIn()->language()->addToStack( 'app_user_browsing_community', FALSE, array('sprintf' => array( $user['member_name'] ) ) );
}
if ( $user['location_permissions'] === NULL or $user['location_permissions'] === '*' or \IPS\Member::loggedIn()->inGroup( explode( ',', $user['location_permissions'] ), TRUE ) )
if ( $user['location_permissions'] === NULL or $user['location_permissions'] === '*' or Member::loggedIn()->inGroup( explode( ',', $user['location_permissions'] ), TRUE ) )
{
$sprintf = array();
$data = json_decode( $user['location_data'], TRUE );
@@ -120,26 +124,24 @@ class _ActiveUserType extends ObjectType
{
foreach ( $data as $key => $parse )
{
$value = htmlspecialchars( $parse ? \IPS\Member::loggedIn()->language()->get( $key ) : $key, ENT_DISALLOWED, 'UTF-8', FALSE );
$value = htmlspecialchars( $parse ? Member::loggedIn()->language()->get( $key ) : $key, ENT_DISALLOWED, 'UTF-8', FALSE );
$sprintf[] = $value;
}
}
if( $action && \IPS\Member::loggedIn()->language()->checkKeyExists($user['location_lang'] . '_action') )
if( $action && Member::loggedIn()->language()->checkKeyExists($user['location_lang'] . '_action') )
{
// Add the member name to the sprintf array since the action strings use it
array_unshift( $sprintf, $user['member_name'] );
return \IPS\Member::loggedIn()->language()->addToStack( $user['location_lang'] . '_action', FALSE, array( 'sprintf' => $sprintf ) );
return Member::loggedIn()->language()->addToStack( $user['location_lang'] . '_action', FALSE, array( 'sprintf' => $sprintf ) );
}
else
{
return \IPS\Member::loggedIn()->language()->addToStack( $user['location_lang'], FALSE, array( 'sprintf' => $sprintf ) );
return Member::loggedIn()->language()->addToStack( $user['location_lang'], FALSE, array( 'sprintf' => $sprintf ) );
}
return sprintf( $lang, $sprintf );
}
}
catch ( \UnderflowException $e ){
catch ( UnderflowException $e ){
}
@@ -12,23 +12,25 @@
namespace IPS\core\api\GraphQL\Types;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\Member;
use IPS\Session\Store;
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;
}
/**
* ActiveUsers for GraphQL API
*/
class _ActiveUsersType extends ObjectType
class ActiveUsersType extends ObjectType
{
/**
* Get object type
*
* @return ObjectType
*/
public function __construct()
{
@@ -45,14 +47,14 @@ class _ActiveUsersType extends ObjectType
]
],
'resolve' => function ($val, $args) {
$flags = \IPS\Session\Store::ONLINE_MEMBERS;
$flags = Store::ONLINE_MEMBERS;
if( $args['includeGuests'] )
{
$flags = \IPS\Session\Store::ONLINE_MEMBERS | \IPS\Session\Store::ONLINE_GUESTS;
$flags = Store::ONLINE_MEMBERS | Store::ONLINE_GUESTS;
}
return \IPS\Session\Store::i()->getOnlineUsers( $flags | \IPS\Session\Store::ONLINE_COUNT_ONLY, 'asc', NULL, NULL, \IPS\Member::loggedIn()->isAdmin() );
return Store::i()->getOnlineUsers( $flags | Store::ONLINE_COUNT_ONLY, 'asc', NULL, NULL, Member::loggedIn()->isAdmin() );
}
],
'users' => [
@@ -79,17 +81,15 @@ class _ActiveUsersType extends ObjectType
]
],
'resolve' => function ($val, $args) {
$flags = \IPS\Session\Store::ONLINE_MEMBERS;
$flags = Store::ONLINE_MEMBERS;
if( $args['includeGuests'] )
{
$flags = \IPS\Session\Store::ONLINE_MEMBERS | \IPS\Session\Store::ONLINE_GUESTS;
$flags = Store::ONLINE_MEMBERS | Store::ONLINE_GUESTS;
}
$offset = max( $args['offset'], 0 );
$limit = min( $args['limit'], 50 );
$users = \IPS\Session\Store::i()->getOnlineUsers( $flags, $args['sortDir'], array( $offset, $limit ), NULL, \IPS\Member::loggedIn()->isAdmin() );
return $users;
return Store::i()->getOnlineUsers( $flags, $args['sortDir'], array( $offset, $limit ), NULL, Member::loggedIn()->isAdmin() );
}
]
];
@@ -12,23 +12,24 @@
namespace IPS\core\api\GraphQL\Types;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\Db;
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;
}
/**
* AttachmentPermissionsType for GraphQL API
*/
class _AttachmentPermissionsType extends ObjectType
class AttachmentPermissionsType extends ObjectType
{
/**
* Get object type
*
* @return ObjectType
*/
public function __construct()
{
@@ -43,7 +44,7 @@ class _AttachmentPermissionsType extends ObjectType
'resolve' => function( $data ) {
$currentPostUsage = 0;
// @todo Currently this only considers postKey because the GraphQL doesn't support editing. When edit support is added we'll need to modify this query to do "OR ( location_key=? AND id=? AND id2=?... )"
foreach ( \IPS\Db::i()->select( '*', 'core_attachments', array( 'attach_post_key=?', $data['postKey'] ) ) as $attachment )
foreach ( Db::i()->select( '*', 'core_attachments', array( 'attach_post_key=?', $data['postKey'] ) ) as $attachment )
{
$currentPostUsage += $attachment['attach_filesize'];
}
@@ -12,23 +12,25 @@
namespace IPS\core\api\GraphQL\Types;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\File;
use IPS\Member;
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;
}
/**
* AttachmentType for GraphQL API
*/
class _AttachmentType extends ObjectType
class AttachmentType extends ObjectType
{
/**
* Get object type
*
* @return ObjectType
*/
public function __construct()
{
@@ -72,7 +74,7 @@ class _AttachmentType extends ObjectType
if ( $attachment['attach_is_image'] )
{
return array(
'url' => (string) \IPS\File::get( 'core_Attachment', $attachment['attach_location'] )->url,
'url' => (string) File::get( 'core_Attachment', $attachment['attach_location'] )->url,
'width' => $attachment['attach_img_width'],
'height' => $attachment['attach_img_height'],
);
@@ -89,7 +91,7 @@ class _AttachmentType extends ObjectType
if ( $attachment['attach_thumb_location'] )
{
return array(
'url' => (string) \IPS\File::get( 'core_Attachment', $attachment['attach_thumb_location'] )->url,
'url' => (string) File::get( 'core_Attachment', $attachment['attach_thumb_location'] )->url,
'width' => $attachment['attach_thumb_width'],
'height' => $attachment['attach_thumb_height'],
);
@@ -97,7 +99,7 @@ class _AttachmentType extends ObjectType
else
{
return array(
'url' => (string) \IPS\File::get( 'core_Attachment', $attachment['attach_location'] )->url,
'url' => (string) File::get( 'core_Attachment', $attachment['attach_location'] )->url,
'width' => $attachment['attach_img_width'],
'height' => $attachment['attach_img_height'],
);
@@ -117,7 +119,7 @@ class _AttachmentType extends ObjectType
'type' => \IPS\core\api\GraphQL\TypeRegistry::member(),
'description' => "Member who uploaded the attachment",
'resolve' => function ( $attachment ) {
return \IPS\Member::load( $attachment['attach_member_id'] );
return Member::load( $attachment['attach_member_id'] );
}
],
];
@@ -11,25 +11,25 @@
namespace IPS\core\api\GraphQL\Types;
use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\UnionType;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\Http\Url\Friendly;
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;
}
/**
* ClubNodeType for GraphQL API
*/
class _ClubNodeType extends ObjectType
class ClubNodeType extends ObjectType
{
/**
* Get object type
*
* @return ObjectType
*/
public function __construct()
{
@@ -41,28 +41,28 @@ class _ClubNodeType extends ObjectType
'id' => [
'type' => TypeRegistry::id(),
'description' => "Node ID",
'resolve' => function ($node, $args, $context, $info) {
'resolve' => function ($node) {
return $node['node_id'];
}
],
'name' => [
'type' => TypeRegistry::string(),
'description' => "Node name",
'resolve' => function ($node, $args, $context, $info) {
'resolve' => function ($node) {
return $node['name'];
}
],
'seoTitle' => [
'type' => TypeRegistry::string(),
'description' => "Node's SEO title",
'resolve' => function ($node, $args, $context, $info) {
return \IPS\Http\Url\Friendly::seoTitle( $node['name'] );
'resolve' => function ($node) {
return Friendly::seoTitle( $node['name'] );
}
],
'type' => [
'type' => TypeRegistry::string(),
'description' => "Node type (from classname)",
'resolve' => function ($node, $args, $context, $info) {
'resolve' => function ($node) {
return str_replace('\\', '_', str_replace('IPS\\', '', $node['node_class'] ) );
}
]
@@ -12,23 +12,27 @@
namespace IPS\core\api\GraphQL\Types;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\File;
use IPS\Http\Url\Friendly;
use IPS\Member;
use IPS\Member\Club;
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;
}
/**
* ClubType for GraphQL API
*/
class _ClubType extends ObjectType
class ClubType extends ObjectType
{
/**
* Get object type
*
* @return ObjectType
*/
public function __construct()
{
@@ -62,7 +66,7 @@ class _ClubType extends ObjectType
'type' => TypeRegistry::string(),
'description' => "Club SEO title",
'resolve' => function ($club) {
return \IPS\Http\Url\Friendly::seoTitle( $club->name );
return Friendly::seoTitle( $club->name );
}
],
'createdDate' => [
@@ -110,7 +114,11 @@ class _ClubType extends ObjectType
'type' => TypeRegistry::string(),
'description' => "Club icon image",
'resolve' => function ($club) {
return ( $club->profile_photo ) ? \IPS\File::get( 'core_Clubs', $club->profile_photo )->url : null;
if( $club->profile_photo )
{
return File::get( 'core_Clubs', $club->profile_photo )->url;
}
return null;
}
],
'coverPhoto' => [
@@ -158,11 +166,11 @@ class _ClubType extends ObjectType
/**
* Resolve nodes field
*
* @param \IPS\Member\Club
* @param array Arguments passed to this resolver
* @param Club $club
* @param array $args Arguments passed to this resolver
* @return array
*/
protected static function nodes($club, $args)
protected static function nodes( Club $club, array $args ) : array
{
return $club->nodes();
}
@@ -170,11 +178,11 @@ class _ClubType extends ObjectType
/**
* Resolve members field
*
* @param \IPS\Member\Club
* @param array Arguments passed to this resolver
* @param Club $club
* @param array $args Arguments passed to this resolver
* @return array
*/
protected static function members($club, $args)
protected static function members( Club $club, array $args ) : array
{
$memberType = ( $args['type'] == 'all' ) ? array( 'member', 'moderator', 'leader' ) : array( $args['type'] );
$result = array();
@@ -182,7 +190,7 @@ class _ClubType extends ObjectType
$members = $club->members( $memberType, $limit, 'core_clubs_memberships.joined ASC', 2 );
foreach( $members as $memberRow ){
$result[] = \IPS\Member::constructFromData( $memberRow );
$result[] = Member::constructFromData( $memberRow );
}
return $result;
@@ -12,23 +12,25 @@
namespace IPS\core\api\GraphQL\Types;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\Content\Reaction;
use IPS\Member;
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;
}
/**
* ContentReactionType for GraphQL API
*/
class _ContentReactionType extends ObjectType
class ContentReactionType extends ObjectType
{
/**
* Get object type
*
* @return ObjectType
*/
public function __construct()
{
@@ -55,14 +57,14 @@ class _ContentReactionType extends ObjectType
'type' => TypeRegistry::int(),
'description' => "Count of this reaction type",
'resolve' => function ($reaction) {
return isset( $reaction['count'] ) ? $reaction['count'] : 0;
return $reaction['count'] ?? 0;
}
],
'image' => [
'type' => TypeRegistry::string(),
'description' => "Reaction image",
'resolve' => function ($reaction) {
$_reaction = isset( $reaction['reaction'] ) ? $reaction['reaction'] : \IPS\Content\Reaction::load( $reaction['reactionId'] );
$_reaction = $reaction['reaction'] ?? Reaction::load( $reaction['reactionId'] );
return (string) $_reaction->_icon->url;
}
],
@@ -70,8 +72,8 @@ class _ContentReactionType extends ObjectType
'type' => TypeRegistry::string(),
'description' => "Reaction name",
'resolve' => function ($reaction) {
$_reaction = isset( $reaction['reaction'] ) ? $reaction['reaction'] : \IPS\Content\Reaction::load( $reaction['reactionId'] );
return \IPS\Member::loggedIn()->language()->addToStack("reaction_title_{$_reaction->id}", FALSE, array('escape' => TRUE));
$_reaction = $reaction['reaction'] ?? Reaction::load( $reaction['reactionId'] );
return Member::loggedIn()->language()->addToStack("reaction_title_{$_reaction->id}", FALSE, array('escape' => TRUE));
}
]
];
@@ -10,25 +10,36 @@
*/
namespace IPS\core\api\GraphQL\Types;
use Exception;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\Content\Comment;
use IPS\Content\Item;
use IPS\Content\Reaction;
use IPS\Content\Search\Result;
use IPS\File;
use IPS\Http\Url;
use IPS\Member;
use IPS\Member\Club;
use function count;
use function defined;
use function in_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;
}
/**
* ContentSearchResultType for GraphQL API
*/
class _ContentSearchResultType extends ObjectType
class ContentSearchResultType extends ObjectType
{
/**
* Get object type
*
* @return ObjectType
*/
public function __construct()
{
@@ -91,9 +102,7 @@ class _ContentSearchResultType extends ObjectType
'description' => "Class of the item type, if this result is a comment/review",
'resolve' => function ($result) {
$asArray = $result->asArray();
$itemClass = static::getItemClass( $asArray );
return $itemClass;
return static::getItemClass( $asArray );
}
],
// @todo this should really be in a more generic ClassType that returns
@@ -103,6 +112,8 @@ class _ContentSearchResultType extends ObjectType
'description' => "Does the result class require a first comment (e.g. topics)?",
'resolve' => function ($result) {
$asArray = $result->asArray();
/* @var Item $itemClass */
$itemClass = static::getItemClass( $asArray );
return $itemClass::$firstCommentRequired;
@@ -148,20 +159,23 @@ class _ContentSearchResultType extends ObjectType
],
'resolveField' => function ($result, $args, $context, $info) {
$asArray = $result->asArray();
/* @var Item $classToUse */
$classToUse = static::getItemClass( $asArray );
switch( $info->fieldName )
{
case 'indefinite':
return $classToUse::_indefiniteArticle( $asArray['containerData'] );
break;
case 'definite':
return $classToUse::_definiteArticle( $asArray['containerData'] );
break;
case 'definiteUC':
return $classToUse::_definiteArticle( $asArray['containerData'], NULL, array( 'ucfirst' => TRUE ) );
break;
}
return '';
}
]),
'resolve' => function ($result) {
@@ -217,14 +231,14 @@ class _ContentSearchResultType extends ObjectType
'type' => TypeRegistry::boolean(),
'description' => "Is this result a comment?",
'resolve' => function ($result) {
return \in_array( 'IPS\Content\Comment', class_parents( self::getFieldValue('index_class', $result) ) ) && !self::getFieldValue('index_title', $result);
return in_array( 'IPS\Content\Comment', class_parents( self::getFieldValue('index_class', $result) ) ) && !self::getFieldValue('index_title', $result);
}
],
'isReview' => [
'type' => TypeRegistry::boolean(),
'description' => "Is this result a review?",
'resolve' => function ($result) {
return \in_array( 'IPS\Content\Review', class_parents( self::getFieldValue('index_class', $result) ) );
return in_array( 'IPS\Content\Review', class_parents( self::getFieldValue('index_class', $result) ) );
}
],
'replies' => [
@@ -245,14 +259,14 @@ class _ContentSearchResultType extends ObjectType
'type' => \IPS\core\api\GraphQL\TypeRegistry::member(),
'description' => "Author of this result",
'resolve' => function ($result) {
return \IPS\Member::load( self::getFieldValue('index_author', $result) );
return Member::load( self::getFieldValue('index_author', $result) );
}
],
'itemAuthor' => [
'type' => \IPS\core\api\GraphQL\TypeRegistry::member(),
'description' => "Author of the original content item",
'resolve' => function ($result) {
return \IPS\Member::load( self::getFieldValue('index_item_author', $result) );
return Member::load( self::getFieldValue('index_item_author', $result) );
}
],
'club' => [
@@ -269,13 +283,13 @@ class _ContentSearchResultType extends ObjectType
try {
$reactions = array();
if( \count( $result->reactions ) )
if( count( $result->reactions ) )
{
foreach( $result->reactions as $reactID => $count )
{
$reactions[] = array(
'id' => $reactID,
'reaction' => \IPS\Content\Reaction::load( $reactID ),
'reaction' => Reaction::load( $reactID ),
'count' => $count
);
}
@@ -283,7 +297,7 @@ class _ContentSearchResultType extends ObjectType
return $reactions;
}
catch (\Exception $e)
catch (Exception $e)
{}
return array();
@@ -305,15 +319,17 @@ class _ContentSearchResultType extends ObjectType
/**
* Return the number of replies
*
* @param \IPS\Content\Search\Result Search result
* @return string
* @param Result $result Search result
* @return int|null
*/
protected static function replies($result) {
protected static function replies( Result $result) : ?int
{
$asArray = $result->asArray();
$itemData = $asArray['itemData'];
if ( \in_array( 'IPS\Content\Comment', class_parents( $asArray['indexData']['index_class'] ) ) )
if ( in_array( 'IPS\Content\Comment', class_parents( $asArray['indexData']['index_class'] ) ) )
{
/* @var Item $itemClass */
$itemClass = static::getItemClass( $asArray );
if( isset( $itemClass::$databaseColumnMap['num_comments'] ) and isset( $itemData[ $itemClass::$databasePrefix . $itemClass::$databaseColumnMap['num_comments'] ] ) )
@@ -344,8 +360,6 @@ class _ContentSearchResultType extends ObjectType
{
return $itemData[ $indexClass::$databasePrefix . $indexClass::$databaseColumnMap['num_comments'] ];
}
return 0;
}
}
@@ -355,12 +369,16 @@ class _ContentSearchResultType extends ObjectType
/**
* Return the content item title
*
* @param \IPS\Content\Search\Result Search result
* @return string
* @param Result $result Search result
* @return string|null
*/
protected static function title( $result )
protected static function title( Result $result ) : ?string
{
$asArray = $result->asArray();
/* @var Item $itemClass
* @var array $databaseColumnMap
*/
$itemClass = static::getItemClass( $asArray );
// If the content is used as the title (e.g. status updates), don't return anything
@@ -375,19 +393,21 @@ class _ContentSearchResultType extends ObjectType
/**
* Return the item URL
*
* @param \IPS\Content\Search\Result Search result
* @return string
* @param Result $result Search result
* @return Url
*/
protected static function url( $result )
protected static function url( Result $result ) : Url
{
$asArray = $result->asArray();
/* @var Item $itemClass */
$itemClass = static::getItemClass( $asArray );
$itemUrl = $itemClass::urlFromIndexData( $asArray['indexData'], $asArray['itemData'] );
/* Object URL */
if ( \in_array( 'IPS\Content\Comment', class_parents( $asArray['indexData']['index_class'] ) ) )
if ( in_array( 'IPS\Content\Comment', class_parents( $asArray['indexData']['index_class'] ) ) )
{
if ( \in_array( 'IPS\Content\Review', class_parents( $asArray['indexData']['index_class'] ) ) )
if ( in_array( 'IPS\Content\Review', class_parents( $asArray['indexData']['index_class'] ) ) )
{
$itemUrl = $itemUrl->setQueryString( array( 'do' => 'findReview', 'review' => $asArray['indexData']['index_object_id'] ) );
}
@@ -403,21 +423,23 @@ class _ContentSearchResultType extends ObjectType
/**
* Return the unread status of this content
*
* @param \IPS\Content\Search\Result Search result
* @param Result $result Search result
* @return boolean
*/
protected static function isUnread( $result )
protected static function isUnread( Result $result ) : bool
{
$asArray = $result->asArray();
$itemClass = static::getItemClass( $asArray );
if ( \in_array( 'IPS\Content\Comment', class_parents( $itemClass ) ) )
if ( in_array( 'IPS\Content\Comment', class_parents( $itemClass ) ) )
{
$contentClass = $itemClass::$contentItemClass;
/* @var Comment $itemClass */
$contentClass = $itemClass::$itemClass;
$unread = $contentClass::unreadFromData( NULL, $asArray['indexData']['index_date_updated'], $asArray['indexData']['index_date_created'], $asArray['indexData']['index_item_id'], $asArray['indexData']['index_container_id'], FALSE );
}
else
{
/* @var Item $itemClass */
$unread = $itemClass::unreadFromData( NULL, $asArray['indexData']['index_date_updated'], $asArray['indexData']['index_date_created'], $asArray['indexData']['index_item_id'], $asArray['indexData']['index_container_id'], FALSE );
}
@@ -427,13 +449,13 @@ class _ContentSearchResultType extends ObjectType
/**
* Resolve contentImage
*
* @param array Array representation of \IPS\Content\Search\Result
* @param array Arguments passed from resolver
* @return string
* @param Result $result Array representation of \IPS\Content\Search\Result
* @return array|null
*/
protected static function contentImages( $result )
protected static function contentImages( Result $result ) : ?array
{
try {
/* @var Item $itemClass */
$itemClass = static::getItemClass( $result->asArray() );
$item = $itemClass::load( self::getFieldValue('index_item_id', $result) );
$toReturn = array();
@@ -444,29 +466,28 @@ class _ContentSearchResultType extends ObjectType
{
foreach( $image as $extension => $file )
{
$toReturn[] = (string) \IPS\File::get( $extension, $file )->url;
$toReturn[] = (string) File::get( $extension, $file )->url;
}
}
}
return $toReturn;
} catch (\Exception $e) {
} catch (Exception $e) {
return NULL;
}
return NULL;
}
/**
* Resolve containerTitle
*
* @param array Array representation of \IPS\Content\Search\Result
* @param array Arguments passed from resolver
* @param Result $result Array representation of \IPS\Content\Search\Result
* @return string
*/
protected static function containerTitle( $result )
protected static function containerTitle( Result $result ) : string
{
$result = $result->asArray();
/* @var Item $itemClass */
$itemClass = static::getItemClass( $result );
$containerTitle = NULL;
@@ -482,15 +503,14 @@ class _ContentSearchResultType extends ObjectType
/**
* Resolve club
*
* @param array Array representation of \IPS\Content\Search\Result
* @param array Arguments passed from resolver
* @return \IPS\Member\Club
* @param Result $result Array representation of \IPS\Content\Search\Result
* @return Club|null
*/
protected static function club( $result )
protected static function club( Result $result ) : ?Club
{
if( self::getFieldValue('index_club_id', $result) )
{
return \IPS\Member\Club::load( self::getFieldValue('index_club_id', $result) );
return Club::load( self::getFieldValue('index_club_id', $result) );
}
return NULL;
@@ -499,14 +519,12 @@ class _ContentSearchResultType extends ObjectType
/**
* Get the item class for the result
*
* @param array Array representation of \IPS\Content\Search\Result
* @param Result $result Array representation of \IPS\Content\Search\Result
* @return string
*/
protected static function getItemClass( $result )
protected static function getItemClass( Result $result ) : string
{
$indexClass = $result['indexData']['index_class'];
$itemClass = ( \in_array( 'IPS\Content\Comment', class_parents( $indexClass ) ) ) ? $indexClass::$itemClass : $indexClass;
return $itemClass;
return ( in_array( 'IPS\Content\Comment', class_parents( $indexClass ) ) ) ? $indexClass::$itemClass : $indexClass;
}
}
@@ -12,23 +12,27 @@
namespace IPS\core\api\GraphQL\Types;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\Db;
use IPS\Member;
use IPS\Patterns\ActiveRecordIterator;
use IPS\Settings;
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;
}
/**
* GroupType for GraphQL API
*/
class _GroupType extends ObjectType
class GroupType extends ObjectType
{
/**
* Get object type
*
* @return ObjectType
*/
public function __construct()
{
@@ -40,7 +44,7 @@ class _GroupType extends ObjectType
'id' => [
'type' => TypeRegistry::int(),
'description' => "Group ID",
'resolve' => function ($group, $args, $context, $info) {
'resolve' => function ($group) {
return $group->g_id;
}
],
@@ -50,12 +54,12 @@ class _GroupType extends ObjectType
'values' => ['GUEST', 'MEMBER', 'ADMIN']
]),
'description' => "Is this a guest, member or admin group?",
'resolve' => function ($group, $args, $context, $info) {
if( $group->g_id == \IPS\Settings::i()->guest_group )
'resolve' => function ($group) {
if( $group->g_id == Settings::i()->guest_group )
{
return 'GUEST';
}
elseif( isset( \IPS\Member::administrators()['g'][ $group->g_id ] ) )
elseif( isset( Member::administrators()['g'][ $group->g_id ] ) )
{
return 'ADMIN';
}
@@ -74,21 +78,21 @@ class _GroupType extends ObjectType
'defaultValue' => FALSE
]
],
'resolve' => function ($group, $args, $context, $info) {
'resolve' => function ($group, $args) {
return ( $args['formatted'] ) ? $group->get_formattedName() : $group->name;
}
],
'canAccessSite' => [
'type' => TypeRegistry::boolean(),
'description' => "Can users in this group access the site?",
'resolve' => function ($group, $args, $context, $info) {
'resolve' => function ($group) {
return $group->g_view_board;
}
],
'canAccessOffline' => [
'type' => TypeRegistry::boolean(),
'description' => "Can users in this group access the site when it's offline?",
'resolve' => function ($group, $args, $context, $info) {
'resolve' => function ($group) {
return $group->g_access_offline;
}
],
@@ -96,14 +100,14 @@ class _GroupType extends ObjectType
'type' => TypeRegistry::boolean(),
'description' => "Can users in this group tag content (if enabled)?",
'resolve' => function ($group) {
return !$group->g_id || !\IPS\Settings::i()->tags_enabled ? FALSE : !( $group->g_bitoptions['gbw_disable_tagging'] );
return ( !$group->g_id || !Settings::i()->tags_enabled ) ? FALSE : !( $group->g_bitoptions['gbw_disable_tagging'] );
}
],
'maxMessengerRecipients' => [
'type' => TypeRegistry::int(),
'description' => "Maximum number of recipients to a PM sent by a member in this group",
'resolve' => function ($group) {
return \IPS\Member::loggedIn()->group['g_max_mass_pm'];
return Member::loggedIn()->group['g_max_mass_pm'];
}
],
'members' => [
@@ -119,7 +123,7 @@ class _GroupType extends ObjectType
'defaultValue' => 25
]
],
'resolve' => function ($group, $args, $context, $info) {
'resolve' => function ($group, $args) {
/* If we don't allow filtering by this group, don't return the members in it */
if( $group->g_bitoptions['gbw_hide_group'] )
{
@@ -128,7 +132,7 @@ class _GroupType extends ObjectType
$offset = max( $args['offset'], 0 );
$limit = min( $args['limit'], 50 );
return new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'core_members', array('member_group_id=?', $group->g_id), NULL, array( $offset, $limit ) ), 'IPS\Member' );
return new ActiveRecordIterator( Db::i()->select( '*', 'core_members', array('member_group_id=?', $group->g_id), NULL, array( $offset, $limit ) ), 'IPS\Member' );
}
]
];
@@ -12,23 +12,24 @@
namespace IPS\core\api\GraphQL\Types;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\Member;
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;
}
/**
* IgnoreOptionType for GraphQL API
*/
class _IgnoreOptionType extends ObjectType
class IgnoreOptionType extends ObjectType
{
/**
* Get object type
*
* @return ObjectType
*/
public function __construct()
{
@@ -62,7 +63,7 @@ class _IgnoreOptionType extends ObjectType
'type' => TypeRegistry::string(),
'description' => "The language string for this ignore type",
'resolve' => function ($ignore) {
return \IPS\Member::loggedIn()->language()->addToStack( 'ignore_' . $ignore['type'] );
return Member::loggedIn()->language()->addToStack( 'ignore_' . $ignore['type'] );
}
]
];
@@ -10,25 +10,29 @@
*/
namespace IPS\core\api\GraphQL\Types;
use Exception;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\TypeRegistry;
use function defined;
use function strtolower;
use function strtoupper;
use function substr;
/* 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;
}
/**
* LanguageType for GraphQL API
*/
class _LanguageType extends ObjectType
class LanguageType extends ObjectType
{
/**
* Get object type
*
* @return ObjectType
*/
public function __construct()
{
@@ -57,7 +61,7 @@ class _LanguageType extends ObjectType
'resolve' => function ($lang) {
if ( preg_match( '/^\w{2}[-_]\w{2}($|\.)/i', $lang->short ) )
{
return \strtolower( \substr( $lang->short, 0, 2 ) ) . '-' . \strtoupper( \substr( $lang->short, 3, 2 ) );
return strtolower( substr( $lang->short, 0, 2 ) ) . '-' . strtoupper( substr( $lang->short, 3, 2 ) );
}
return '';
@@ -91,12 +95,12 @@ class _LanguageType extends ObjectType
'type' => TypeRegistry::nonNull( TypeRegistry::string() )
]
],
'resolve' => function ($lang, $args, $context, $info) {
'resolve' => function ($lang, $args) {
try
{
return $lang->addToStack( $args['key'] );
}
catch (\Exception $err)
catch (Exception $err)
{
return $args['key'];
}
@@ -12,23 +12,27 @@
namespace IPS\core\api\GraphQL\Types;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\Http\Url;
use IPS\Login;
use IPS\Member;
use IPS\Session;
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;
}
/**
* LoginType for GraphQL API
*/
class _LoginType extends ObjectType
class LoginType extends ObjectType
{
/**
* Get object type
*
* @return ObjectType
*/
public function __construct()
{
@@ -48,14 +52,14 @@ class _LoginType extends ObjectType
'type' => TypeRegistry::string(),
'description' => "Login name",
'resolve' => function ($login) {
return \IPS\Member::loggedIn()->language()->get( $login->getTitle() );
return Member::loggedIn()->language()->get( $login->getTitle() );
}
],
'text' => [
'type' => TypeRegistry::string(),
'description' => "Login button text",
'resolve' => function ($login) {
return \IPS\Member::loggedIn()->language()->get( $login->buttonText() );
return Member::loggedIn()->language()->get( $login->buttonText() );
}
],
'icon' => [
@@ -76,8 +80,8 @@ class _LoginType extends ObjectType
'type' => TypeRegistry::string(),
'description' => "URL to visit to authorize with this handler",
'resolve' => function ($login) {
$loginClass = new \IPS\Login;
return (string) \IPS\Http\Url::internal( $loginClass->url )->setQueryString('csrfKey', \IPS\Session::i()->csrfKey)->setQueryString('_processLogin', $login->_id);
$loginClass = new Login;
return (string) Url::internal( $loginClass->url )->setQueryString('csrfKey', Session::i()->csrfKey)->setQueryString('_processLogin', $login->_id);
}
]
];
@@ -11,24 +11,43 @@
namespace IPS\core\api\GraphQL\Types;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\Fields\CoverPhotoField;
use IPS\Api\GraphQL\SafeException;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\Application;
use IPS\Content\Search\Query;
use IPS\Content\Search\Results;
use IPS\core\Ignore;
use IPS\DateTime;
use IPS\Db;
use IPS\forums\Topic;
use IPS\Helpers\Form\Editor;
use IPS\Member;
use IPS\Member\Club;
use IPS\Member\Group;
use IPS\Notification\Api;
use IPS\Patterns\ActiveRecordIterator;
use IPS\Settings;
use LogicException;
use OutOfRangeException;
use UnderflowException;
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;
}
/**
* MemberrType for GraphQL API
*/
class _MemberType extends ObjectType
class MemberType extends ObjectType
{
/**
* Get object type
*
* @return ObjectType
*/
public function __construct()
{
@@ -40,14 +59,14 @@ class _MemberType extends ObjectType
'id' => [
'type' => TypeRegistry::id(),
'description' => "Returns the member's ID",
'resolve' => function( $member, $args, $context, $info ) {
'resolve' => function( $member ) {
return $member->member_id;
}
],
'email' => [
'type' => TypeRegistry::string(),
'description' => "Returns the member's email address (depending on permissions)",
'resolve' => function( $member, $args, $context, $info ) {
'resolve' => function( $member ) {
if( !self::isAuthorized($member) )
{
return NULL;
@@ -58,7 +77,7 @@ class _MemberType extends ObjectType
'url' => [
'type' => TypeRegistry::string(),
'description' => "Returns the URL to member's profile",
'resolve' => function( $member, $args, $context, $info ) {
'resolve' => function( $member ) {
return (string) $member->url();
}
],
@@ -71,21 +90,21 @@ class _MemberType extends ObjectType
'defaultValue' => FALSE
]
],
'resolve' => function( $member, $args, $context, $info ) {
return ( $args['formatted'] ) ? \IPS\Member\Group::load( $member->member_group_id )->formatName( $member->name ) : $member->name;
'resolve' => function( $member, $args ) {
return ( $args['formatted'] ) ? Group::load( $member->member_group_id )->formatName( $member->name ) : $member->name;
}
],
'title' => [
'type' => TypeRegistry::string(),
'description' => "Returns the member's title",
'resolve' => function( $member, $args, $context, $info ) {
'resolve' => function( $member ) {
return null;
}
],
'timezone' => [
'type' => TypeRegistry::string(),
'description' => "Returns the member's timezone (depending on permissions)",
'resolve' => function( $member, $args, $context, $info ) {
'resolve' => function( $member ) {
if( !self::isAuthorized($member) )
{
return NULL;
@@ -96,7 +115,7 @@ class _MemberType extends ObjectType
'joined' => [
'type' => TypeRegistry::int(),
'description' => "Returns the date the member joined",
'resolve' => function( $member, $args, $context, $info ) {
'resolve' => function( $member ) {
return $member->joined->getTimestamp();
}
],
@@ -131,7 +150,7 @@ class _MemberType extends ObjectType
'defaultValue' => NULL
]
],
'resolve' => function( $member, $args, $context, $info ) {
'resolve' => function( $member, $args, $context ) {
if( !self::isOwnerMember($member) )
{
return NULL;
@@ -142,7 +161,7 @@ class _MemberType extends ObjectType
'notificationCount' => [
'type' => TypeRegistry::int(),
'description' => "Returns the member's notification count (depending on permissions)",
'resolve' => function( $member, $args, $context, $info ) {
'resolve' => function( $member ) {
if( !self::isOwnerMember($member) )
{
return NULL;
@@ -153,41 +172,40 @@ class _MemberType extends ObjectType
'posts' => [
'type' => TypeRegistry::int(),
'description' => "Returns the member's post count",
'resolve' => function( $member, $args, $context, $info ) {
'resolve' => function( $member ) {
return $member->member_posts;
}
],
'contentCount' => [
'type' => TypeRegistry::int(),
'description' => "Returns the member's post count",
'resolve' => function( $member, $args, $context, $info ) {
'resolve' => function( $member ) {
return $member->member_posts;
}
],
'reputationCount' => [
'type' => TypeRegistry::int(),
'description' => "Returns the member's reputation count",
'resolve' => function( $member, $args, $context, $info ) {
return ( \IPS\Settings::i()->reputation_enabled ) ? $member->pp_reputation_points : null;
'resolve' => function( $member ) {
return ( Settings::i()->reputation_enabled ) ? $member->pp_reputation_points : null;
}
],
'solvedCount' => [
'type' => TypeRegistry::int(),
'description' => "Returns the number of items this member has solved",
'resolve' => function ($member) {
if( !\IPS\Application::appIsEnabled('forums') || !\IPS\forums\Topic::anyContainerAllowsSolvable() )
if( !Application::appIsEnabled('forums') || !Topic::anyContainerAllowsSolvable() )
{
return 0;
}
$count = \IPS\Db::i()->select( 'COUNT(*) as count', 'core_solved_index', array( 'member_id=?', $member->member_id ) )->first();
return $count;
return (int) Db::i()->select( 'COUNT(*) as count', 'core_solved_index', array( 'member_id=? AND type=?', $member->member_id, 'solved' ) )->first();
}
],
'ip_address' => [
'type' => TypeRegistry::string(),
'description' => "Returns the member's IP address (depending on permissions)",
'resolve' => function( $member, $args, $context, $info ) {
'resolve' => function( $member ) {
if( !self::isAuthorized($member) )
{
return NULL;
@@ -198,7 +216,7 @@ class _MemberType extends ObjectType
'warn_level' => [
'type' => TypeRegistry::int(),
'description' => "Returns the member's warning level (depending on permissions)",
'resolve' => function( $member, $args, $context, $info ) {
'resolve' => function( $member ) {
if( !self::isAuthorized($member) ){
return NULL;
}
@@ -208,7 +226,7 @@ class _MemberType extends ObjectType
'profileViews' => [
'type' => TypeRegistry::int(),
'description' => "Returns the number of profile views for this member (depending on permissions)",
'resolve' => function( $member, $args, $context, $info ) {
'resolve' => function( $member ) {
if( !self::isAuthorized($member) )
{
return NULL;
@@ -231,35 +249,35 @@ class _MemberType extends ObjectType
'type' => \IPS\core\api\GraphQL\TypeRegistry::group(),
'description' => "Returns the member's primary group",
'resolve' => function( $member, $args, $context, $info ) {
return \IPS\Member\Group::load( $member->member_group_id );
return Group::load( $member->member_group_id );
}
],
'isOnline' => [
'type' => TypeRegistry::boolean(),
'description' => "Indicates whether the user is online, taking permissions into account",
'resolve' => function ($member) {
return ( $member->isOnline() AND !$member->isOnlineAnonymously() ) OR ( $member->isOnlineAnonymously() AND \IPS\Member::loggedIn()->isAdmin() );
return ( $member->isOnline() AND !$member->isOnlineAnonymously() ) OR ( $member->isOnlineAnonymously() AND Member::loggedIn()->isAdmin() );
}
],
'lastActivity' => [
'type' => TypeRegistry::string(),
'description' => "Returns the timestamp of the member's last activity",
'resolve' => function( $member, $args, $context, $info ) {
return \IPS\DateTime::ts( $member->last_activity )->rfc3339();
return DateTime::ts( $member->last_activity )->rfc3339();
}
],
'lastVisit' => [
'type' => TypeRegistry::string(),
'description' => "Returns the timestamp of the member's last visit",
'resolve' => function( $member, $args, $context, $info ) {
return \IPS\DateTime::ts( $member->last_visit )->rfc3339();
return DateTime::ts( $member->last_visit )->rfc3339();
}
],
'lastPost' => [
'type' => TypeRegistry::string(),
'description' => "Returns the timestamp of member's last post",
'resolve' => function( $member, $args, $context, $info ) {
return \IPS\DateTime::ts( $this->member_last_post )->rfc3339();
return DateTime::ts( $member->member_last_post )->rfc3339();
}
],
'secondaryGroups' => [
@@ -325,7 +343,7 @@ class _MemberType extends ObjectType
'type' => TypeRegistry::listOf( \IPS\core\api\GraphQL\TypeRegistry::club() ),
'description' => "Returns the member's clubs (depending on permissions)",
'resolve' => function( $member, $args, $context, $info ) {
return \IPS\Member\Club::clubs( $member, 25, 'last_activity' );
return Club::clubs( $member, 25, 'last_activity' );
}
],
'photo' => [
@@ -335,7 +353,7 @@ class _MemberType extends ObjectType
return self::photo($member);
}
],
'coverPhoto' => \IPS\Api\GraphQL\Fields\CoverPhotoField::getDefinition('core_MemberCoverPhoto'),
'coverPhoto' => CoverPhotoField::getDefinition('core_MemberCoverPhoto'),
'customFieldGroups' => [
'type' => TypeRegistry::listOf( \IPS\core\api\GraphQL\TypeRegistry::profileFieldGroup() ),
'resolve' => function( $member, $args, $context, $info ) {
@@ -348,10 +366,10 @@ class _MemberType extends ObjectType
'resolve' => function( $member ) {
if( $member->member_id && !self::isOwnerMember( $member ) )
{
throw new \IPS\Api\GraphQL\SafeException( 'INVALID_USER', '2S401/1', 403 );
throw new SafeException( 'INVALID_USER', '2S401/1', 403 );
}
return \IPS\Helpers\Form\Editor::maxTotalAttachmentSize( $member, 0 );
return Editor::maxTotalAttachmentSize( $member, 0 );
}
],
'canBeIgnored' => [
@@ -399,10 +417,10 @@ class _MemberType extends ObjectType
/**
* Return a member's photo
*
* @param \IPS\Member
* @param Member $member
* @return string
*/
protected static function photo($member)
protected static function photo( Member $member ) : string
{
$member_properties = array();
@@ -411,7 +429,7 @@ class _MemberType extends ObjectType
$member_properties[ $column ] = $member->$column;
}
$photoUrl = \IPS\Member::photoUrl( $member_properties );
$photoUrl = Member::photoUrl( $member_properties );
if( mb_strpos( $photoUrl, "data:image/svg+xml" ) === 0 )
{
@@ -426,12 +444,12 @@ class _MemberType extends ObjectType
/**
* Return a json array containing letter/color combo for a user's letter photo
*
* @param \IPS\Member
* @param Member $member
* @return string
*/
protected static function getLetterPhotoData($member)
protected static function getLetterPhotoData( Member $member ) : string
{
return json_encode( \IPS\Member::generateLetterPhoto( array(
return json_encode( Member::generateLetterPhoto( array(
'name' => $member->name,
'pp_main_photo' => $member->pp_main_photo,
'member_id' => $member->member_id
@@ -441,32 +459,33 @@ class _MemberType extends ObjectType
/**
* Determines if this is a user authorized to access sensitive data
*
* @param \IPS\Member
* @param Member $member
* @return boolean
*/
protected static function isAuthorized($member)
protected static function isAuthorized( Member $member ) : bool
{
return self::isOwnerMember($member) || \IPS\Member::loggedIn()->isAdmin();
return self::isOwnerMember($member) || Member::loggedIn()->isAdmin();
}
/**
* Determines if this user is the same as the user requesting the info
*
* @param \IPS\Member
* @param Member $member
* @return boolean
*/
protected static function isOwnerMember($member)
protected static function isOwnerMember( Member $member ) : bool
{
return $member->member_id && $member->member_id == \IPS\Member::loggedIn()->member_id;
return $member->member_id && $member->member_id == Member::loggedIn()->member_id;
}
/**
* Returns a member's content
*
* @param \IPS\Member
* @return boolean
* @param Member $member
* @param array $args
* @return Results
*/
protected static function content($member, $args)
protected static function content( Member $member, array $args) : Results
{
// Get page
// We don't know the count at this stage, so figure out the page number from
@@ -480,8 +499,8 @@ class _MemberType extends ObjectType
$page = floor( $offset / $limit ) + 1;
}
$latestActivity = \IPS\Content\Search\Query::init()->filterForProfile( $member )->setLimit( $limit )->setPage( $page )->setOrder( \IPS\Content\Search\Query::ORDER_NEWEST_CREATED )->search();
$latestActivity->init( TRUE );
$latestActivity = Query::init()->filterForProfile( $member )->setLimit( $limit )->setPage( $page )->setOrder( Query::ORDER_NEWEST_CREATED )->search();
$latestActivity->init();
return $latestActivity;
}
@@ -489,20 +508,20 @@ class _MemberType extends ObjectType
/**
* Return user's notifications
*
* @param \IPS\Member
* @param Member $member
* @param array $args
* @param array $context
* @return array
*/
protected static function notifications($member, $args, $context)
protected static function notifications( Member $member, array $args, array $context ) : array
{
/* Specify filter in where clause */
$where = array();
$where[] = array( "notification_app IN('" . implode( "','", array_keys( \IPS\Application::enabledApplications() ) ) . "')" );
$where[] = array( "`member`=?", \IPS\Member::loggedIn()->member_id );
$where[] = array( "notification_app IN('" . implode( "','", array_keys( Application::enabledApplications() ) ) . "')" );
$where[] = array( "`member`=?", Member::loggedIn()->member_id );
/* Are we filtering by unread status? */
if( isset( $args['unread'] ) && $args['unread'] !== NULL )
if( isset( $args['unread'] ) )
{
if( $args['unread'] === TRUE )
{
@@ -523,21 +542,21 @@ class _MemberType extends ObjectType
}
/* Get Count */
$count = \IPS\Db::i()->select( 'COUNT(*) as cnt', 'core_notifications', $where )->first();
$count = Db::i()->select( 'COUNT(*) as cnt', 'core_notifications', $where )->first();
/* Get results */
$returnRows = array();
$offset = max( $args['offset'], 0 );
$limit = min( $args['limit'], 50 );
foreach( \IPS\Db::i()->select( '*', 'core_notifications', $where, $sort, array( $offset, $limit ) ) as $row )
foreach( Db::i()->select( '*', 'core_notifications', $where, $sort, array( $offset, $limit ) ) as $row )
{
try
{
$notification = \IPS\Notification\Api::constructFromData( $row );
$notification = Api::constructFromData( $row );
$returnRows[] = array( 'notification' => $notification, 'data' => $notification->getData( FALSE ) );
}
catch ( \LogicException $e ) { }
catch ( LogicException $e ) { }
}
return $returnRows;
@@ -546,17 +565,19 @@ class _MemberType extends ObjectType
/**
* Return custom profile field groups
*
* @param \IPS\Member
* @return boolean
* @param Member $member
* @param array $args
* @param array $context
* @return array|null
*/
protected static function customFieldGroups($member, $args, $context)
protected static function customFieldGroups( Member $member, array $args, array $context ) : ?array
{
/* Get profile field values */
try
{
$profileFieldValues = \IPS\Db::i()->select( '*', 'core_pfields_content', array( 'member_id=?', $member->member_id ) )->first();
$profileFieldValues = Db::i()->select( '*', 'core_pfields_content', array( 'member_id=?', $member->member_id ) )->first();
}
catch ( \UnderflowException $e )
catch ( UnderflowException $e )
{
return null;
}
@@ -565,11 +586,11 @@ class _MemberType extends ObjectType
{
$fields = array();
if( \IPS\Member::loggedIn()->isAdmin() OR \IPS\Member::loggedIn()->modPermissions() )
if( Member::loggedIn()->isAdmin() OR Member::loggedIn()->modPermissions() )
{
$where = array( "pfd.pf_member_hide='owner' OR pfd.pf_member_hide='staff' OR pfd.pf_member_hide='all'" );
}
elseif( \IPS\Member::loggedIn()->member_id == $member->member_id )
elseif( Member::loggedIn()->member_id == $member->member_id )
{
$where = array( "pfd.pf_member_hide='owner' OR pfd.pf_member_hide='all'" );
}
@@ -578,7 +599,7 @@ class _MemberType extends ObjectType
$where = array( "pfd.pf_member_hide='all'" );
}
foreach( new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( 'pfd.*', array('core_pfields_data', 'pfd'), $where, 'pfg.pf_group_order, pfd.pf_position' )->join(
foreach( new ActiveRecordIterator( Db::i()->select( 'pfd.*', array('core_pfields_data', 'pfd'), $where, 'pfg.pf_group_order, pfd.pf_position' )->join(
array('core_pfields_groups', 'pfg'),
"pfd.pf_group_id=pfg.pf_group_id"
), 'IPS\core\ProfileFields\Field' ) as $field )
@@ -598,7 +619,7 @@ class _MemberType extends ObjectType
'id' => md5( $member->member_id . $field->id ),
'fieldId' => $field->id,
'title' => 'core_pfield_' . $field->id,
'value' => json_encode( $field->apiValue( $profileFieldValues['field_' . $field->id] ) ),
'value' => json_encode( $field->apiValue( $profileFieldValues['field_' . $field->id], true ) ),
'type' => $field->type
);
}
@@ -613,18 +634,20 @@ class _MemberType extends ObjectType
/**
* Resolve followers field
*
* @param \IPS\Member
* @param array Arguments passed to this resolver
* @param Member $member
* @param array $args Arguments passed to this resolver
* @param array $context
* @param array $info
* @return array
*/
protected static function followers($member, $args, $context, $info)
protected static function followers( Member $member, array $args, array $context, array $info ) : array
{
$limit = min( $args['limit'], 50 );
return array_map(
function ($followRow)
{
return \IPS\Member::load( $followRow['follow_member_id'] );
return Member::load( $followRow['follow_member_id'] );
},
iterator_to_array( $member->followers( 3, array( 'immediate', 'daily', 'weekly' ), NULL, array(0, $limit ) ) )
);
@@ -633,20 +656,22 @@ class _MemberType extends ObjectType
/**
* Resolve secondary groups field
*
* @param \IPS\Member
* @param array Arguments passed to this resolver
* @return array
* @param Member $member
* @param array $args
* @param array $context
* @param array $info
* @return array
*/
protected static function secondaryGroups($member, $args, $context, $info)
protected static function secondaryGroups( Member $member, array $args, array $context, array $info ) : array
{
$secondaryGroups = array();
foreach ( array_filter( array_map( "intval", explode( ',', $member->mgroup_others ) ) ) as $secondaryGroupId )
{
try
{
$secondaryGroups[] = \IPS\Member\Group::load( $secondaryGroupId );
$secondaryGroups[] = Group::load( $secondaryGroupId );
}
catch ( \OutOfRangeException $e ) { }
catch ( OutOfRangeException $e ) { }
}
return $secondaryGroups;
@@ -655,12 +680,12 @@ class _MemberType extends ObjectType
/**
* Resolve ignore status field
*
* @param \IPS\Member $member Member to check
* @return array
* @param Member $member Member to check
* @return array|null
*/
protected static function ignoreStatus( \IPS\Member $member)
protected static function ignoreStatus( Member $member) : ?array
{
if( !$member->canBeIgnored() || $member->member_id === \IPS\Member::loggedIn()->member_id ){
if( !$member->canBeIgnored() || $member->member_id === Member::loggedIn()->member_id ){
return NULL;
}
@@ -668,15 +693,15 @@ class _MemberType extends ObjectType
try
{
$ignore = \IPS\core\Ignore::load( $member->member_id, 'ignore_ignore_id', array( 'ignore_owner_id=?', \IPS\Member::loggedIn()->member_id ) );
$ignore = Ignore::load( $member->member_id, 'ignore_ignore_id', array( 'ignore_owner_id=?', Member::loggedIn()->member_id ) );
}
catch ( \OutOfRangeException $e ) {
catch ( OutOfRangeException $e ) {
// Just keep ignore as false
}
$ignoreStatus = array();
foreach ( \IPS\core\Ignore::types() as $type )
foreach ( Ignore::types() as $type )
{
$ignoreStatus[] = array(
'type' => $type,
@@ -687,7 +712,7 @@ class _MemberType extends ObjectType
return $ignoreStatus;
}
public static function getOrderByOptions()
public static function getOrderByOptions() : array
{
return ['member_id', 'joined','last_activity','name','last_visit'];
}
@@ -12,40 +12,42 @@
namespace IPS\core\api\GraphQL\Types;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\TypeRegistry;
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;
}
/**
* MessengerConversation for GraphQL API
*/
class _MessengerConversationType extends \IPS\Content\Api\GraphQL\ItemType
class MessengerConversationType extends ItemType
{
/*
* @brief The item classname we use for this type
*/
protected static $itemClass = '\IPS\core\Messenger\Conversation';
protected static string $itemClass = '\IPS\core\Messenger\Conversation';
/*
* @brief GraphQL type name
*/
protected static $typeName = 'core_MessengerConversation';
protected static string $typeName = 'core_MessengerConversation';
/*
* @brief GraphQL type description
*/
protected static $typeDescription = 'A messenger conversation';
protected static string $typeDescription = 'A messenger conversation';
/**
* Return the fields available in this type
*
* @return array
*/
public function fields()
public function fields(): array
{
$defaultFields = parent::fields();
$conversationFields = array(
@@ -130,9 +132,9 @@ class _MessengerConversationType extends \IPS\Content\Api\GraphQL\ItemType
* Here we adjust the resolver for the commentInformation field to check whether this is
* a poll-only topic.
*
* @return string|null
* @return array
*/
public static function getItemPermissionFields()
public static function getItemPermissionFields(): array
{
$defaultFields = parent::getItemPermissionFields();
@@ -149,7 +151,7 @@ class _MessengerConversationType extends \IPS\Content\Api\GraphQL\ItemType
*
* @return array
*/
public static function getOrderByOptions()
public static function getOrderByOptions(): array
{
// Note: these options all get prefixed with 'mt_' when passed into the query.
return array('last_post_time', 'start_time', 'replies');
@@ -160,21 +162,8 @@ class _MessengerConversationType extends \IPS\Content\Api\GraphQL\ItemType
*
* @return ObjectType
*/
protected static function getCommentType()
protected static function getCommentType(): ObjectType
{
return \IPS\core\api\GraphQL\TypeRegistry::messengerReply();
}
/**
* Resolve the comments field - overridden from ItemType
* If this is a question and order isn't date, then force order by votes
*
* @param \IPS\forums\Topic
* @param array Arguments passed to this resolver
* @return array
*/
/*protected static function comments($topic, $args)
{
return parent::comments($topic, $args);
}*/
}
@@ -12,26 +12,29 @@
namespace IPS\core\api\GraphQL\Types;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\Db;
use IPS\Http\Url;
use IPS\Member;
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;
}
/**
* MessengerFolder for GraphQL API
*/
class _MessengerFolderType extends ObjectType
class MessengerFolderType extends ObjectType
{
public $memberFolders = NULL;
public ?array $memberFolders = NULL;
/**
* Get object type
*
* @return ObjectType
*/
public function __construct()
{
@@ -81,7 +84,7 @@ class _MessengerFolderType extends ObjectType
* @Param boolean $refetch If true, will force folder data to be refetched rather than served from cached values
* @return array
*/
public function getMemberFolders($refetch = FALSE)
public function getMemberFolders( bool $refetch = FALSE ) : array
{
if( $this->memberFolders !== NULL && !$refetch )
{
@@ -89,15 +92,15 @@ class _MessengerFolderType extends ObjectType
}
/* Get folders */
$folders = array( 'myconvo' => \IPS\Member::loggedIn()->language()->addToStack('messenger_folder_inbox') );
if ( \IPS\Member::loggedIn()->pconversation_filters )
$folders = array( 'myconvo' => Member::loggedIn()->language()->addToStack('messenger_folder_inbox') );
if ( Member::loggedIn()->pconversation_filters )
{
$folders = $folders + array_filter( json_decode( \IPS\Member::loggedIn()->pconversation_filters, TRUE ) );
$folders = $folders + array_filter( json_decode( Member::loggedIn()->pconversation_filters, TRUE ) );
}
/* What are our folder counts? */
/* Note: The setKeyField and setValueField calls here were causing the folder counts to be incorrect (if you had two folders with 1 message in each, then both showed a count of 2) */
$counts = iterator_to_array( \IPS\Db::i()->select( 'map_folder_id, count(*) as count', 'core_message_topic_user_map', array( 'map_user_id=? AND map_user_active=1', \IPS\Member::loggedIn()->member_id ), NULL, NULL, 'map_folder_id' ) );
$counts = iterator_to_array( Db::i()->select( 'map_folder_id, count(*) as count', 'core_message_topic_user_map', array( 'map_user_id=? AND map_user_active=1', Member::loggedIn()->member_id ), NULL, NULL, 'map_folder_id' ) );
$folderCounts = array();
foreach( $counts AS $k => $count )
{
@@ -109,8 +112,8 @@ class _MessengerFolderType extends ObjectType
$this->memberFolders[ $id ] = array(
'id' => $id,
'name' => $name,
'url' => \IPS\Http\Url::internal( "app=core&module=messaging&controller=messenger", 'front', 'messaging' )->setQueryString('folder', $id),
'count' => isset( $folderCounts[ $id ] ) ? $folderCounts[ $id ] : 0
'url' => Url::internal( "app=core&module=messaging&controller=messenger", 'front', 'messaging' )->setQueryString('folder', $id),
'count' => $folderCounts[$id] ?? 0
);
}
@@ -12,23 +12,24 @@
namespace IPS\core\api\GraphQL\Types;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\Member;
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;
}
/**
* MessengerParticipant for GraphQL API
*/
class _MessengerParticipantType extends ObjectType
class MessengerParticipantType extends ObjectType
{
/**
* Get object type
*
* @return ObjectType
*/
public function __construct()
{
@@ -50,7 +51,7 @@ class _MessengerParticipantType extends ObjectType
'resolve' => function ($map) {
if( $map['map_user_id'] )
{
return \IPS\Member::load( $map['map_user_id'] );
return Member::load( $map['map_user_id'] );
}
return NULL;
@@ -11,63 +11,44 @@
namespace IPS\core\api\GraphQL\Types;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\Content\Api\GraphQL\CommentType;
use IPS\core\api\GraphQL\TypeRegistry;
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;
}
/**
* MessengerReply for GraphQL API
*/
class _MessengerReplyType extends \IPS\Content\Api\GraphQL\CommentType
class MessengerReplyType extends CommentType
{
/*
* @brief The item classname we use for this type
*/
protected static $commentClass = '\IPS\core\Messenger\Message';
protected static string $commentClass = '\IPS\core\Messenger\Message';
/*
* @brief GraphQL type name
*/
protected static $typeName = 'core_MessengerReply';
protected static string $typeName = 'core_MessengerReply';
/*
* @brief GraphQL type description
*/
protected static $typeDescription = 'A reply';
protected static string $typeDescription = 'A reply';
/**
* Get the item type that goes with this item type
*
* @return ObjectType
*/
public static function getItemType()
public static function getItemType(): ObjectType
{
return \IPS\core\api\GraphQL\TypeRegistry::messengerConversation();
return TypeRegistry::messengerConversation();
}
/**
* Return the fields available in this type
*
* @return array
*/
/*public function fields()
{
}*/
/**
* Return the definite article, but without the item type
*
* @return string
*/
/*public static function definiteArticleNoItem($post, $options = array())
{
$type = $post->item()->isQuestion() ? 'answer_lc' : 'post_lc';
return \IPS\Member::loggedIn()->language()->addToStack($type, FALSE, $options);
}*/
}
@@ -12,23 +12,23 @@
namespace IPS\core\api\GraphQL\Types;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\TypeRegistry;
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;
}
/**
* NotificationMethodType for GraphQL API
*/
class _NotificationMethodType extends ObjectType
class NotificationMethodType extends ObjectType
{
/**
* Get object type
*
* @return ObjectType
*/
public function __construct()
{
@@ -12,23 +12,23 @@
namespace IPS\core\api\GraphQL\Types;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\TypeRegistry;
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;
}
/**
* NotificationType for GraphQL API
*/
class _NotificationType extends ObjectType
class NotificationType extends ObjectType
{
/**
* Get object type
*
* @return ObjectType
*/
public function __construct()
{
@@ -97,21 +97,21 @@ class _NotificationType extends ObjectType
'type' => \IPS\core\Api\GraphQL\TypeRegistry::member(),
'description' => "Member that triggered this notification",
'resolve' => function ($notification) {
return isset( $notification['data']['author'] ) ? $notification['data']['author'] : NULL;
return $notification['data']['author'] ?? NULL;
}
],
'title' => [
'type' => TypeRegistry::string(),
'description' => "Notification title",
'resolve' => function ($notification) {
return isset( $notification['data']['title'] ) ? $notification['data']['title'] : NULL;
return $notification['data']['title'] ?? NULL;
}
],
'content' => [
'type' => TypeRegistry::richText(),
'description' => "Notification content",
'resolve' => function ($notification) {
return isset( $notification['data']['content'] ) ? $notification['data']['content'] : NULL;
return $notification['data']['content'] ?? NULL;
}
],
'url' => [
@@ -12,23 +12,25 @@
namespace IPS\core\api\GraphQL\Types;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\Member;
use function count;
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;
}
/**
* NotificationTypeType for GraphQL API
*/
class _NotificationTypeType extends ObjectType
class NotificationTypeType extends ObjectType
{
/**
* Get object type
*
* @return ObjectType
*/
public function __construct()
{
@@ -55,7 +57,7 @@ class _NotificationTypeType extends ObjectType
'type' => TypeRegistry::string(),
'description' => "Title of the notification group",
'resolve' => function ($type) {
return \IPS\Member::loggedIn()->language()->addToStack( 'notifications__' . $type['extension'] );
return Member::loggedIn()->language()->addToStack( 'notifications__' . $type['extension'] );
}
],
'type' => [
@@ -76,14 +78,14 @@ class _NotificationTypeType extends ObjectType
'type' => TypeRegistry::string(),
'description' => "Type description",
'resolve' => function ($type) {
return \IPS\Member::loggedIn()->language()->addToStack( $type['description'] );
return Member::loggedIn()->language()->addToStack( $type['description'] );
}
],
'lang' => [
'type' => TypeRegistry::string(),
'description' => "The translated label",
'resolve' => function ($type) {
return \IPS\Member::loggedIn()->language()->addToStack( $type['name'] );
return Member::loggedIn()->language()->addToStack( $type['name'] );
}
],
'inline' => [
@@ -104,7 +106,7 @@ class _NotificationTypeType extends ObjectType
'type' => \IPS\core\api\GraphQL\TypeRegistry::notificationMethod(),
'description' => "Push notification method",
'resolve' => function ($type) {
if ( !isset( $type['push'] ) || !\count( $type['push'] ) || !\IPS\Member::loggedIn()->members_bitoptions['mobile_notifications'] )
if ( !isset( $type['push'] ) || !count( $type['push'] ) || !Member::loggedIn()->members_bitoptions['mobile_notifications'] )
{
return NULL;
}
@@ -12,23 +12,26 @@
namespace IPS\core\api\GraphQL\Types;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\Member;
use function array_slice;
use function defined;
use function in_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;
}
/**
* PollQuestionType for GraphQL API
*/
class _PollQuestionType extends ObjectType
class PollQuestionType extends ObjectType
{
/**
* Get object type
*
* @return ObjectType
*/
public function __construct()
{
@@ -92,7 +95,7 @@ class _PollQuestionType extends ObjectType
'type' => TypeRegistry::boolean(),
'description' => "Whether the logged-in member voted for this choice",
'resolve' => function ($choice) {
return \in_array( \IPS\Member::loggedIn()->member_id, $choice['voters'] );
return in_array( Member::loggedIn()->member_id, $choice['voters'] );
}
],
'voters' => [
@@ -111,11 +114,11 @@ class _PollQuestionType extends ObjectType
$members = array();
$offset = max( $args['offset'], 0 );
$limit = min( $args['limit'], 50 );
$membersToLoad = \array_slice( $choice['voters'], $offset, $limit );
$membersToLoad = array_slice( $choice['voters'], $offset, $limit );
foreach( $membersToLoad as $memberID )
{
$members[] = \IPS\Member::load( $memberID );
$members[] = Member::load( $memberID );
}
return $members;
@@ -134,7 +137,7 @@ class _PollQuestionType extends ObjectType
'poll' => $question['poll'],
'title' => $choice,
'votes' => isset( $question['data']['votes'] ) ? $question['data']['votes'][ $idx ] : 0,
'voters' => isset( $question['voters'][ $idx ] ) ? $question['voters'][ $idx ] : array()
'voters' => $question['voters'][$idx] ?? array()
);
}
@@ -12,23 +12,28 @@
namespace IPS\core\api\GraphQL\Types;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\DateTime;
use IPS\Db;
use IPS\Poll;
use function defined;
use function intval;
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;
}
/**
* PollType for GraphQL API
*/
class _PollType extends ObjectType
class PollType extends ObjectType
{
/**
* Get object type
*
* @return ObjectType
*/
public function __construct()
{
@@ -69,7 +74,7 @@ class _PollType extends ObjectType
'type' => TypeRegistry::int(),
'description' => "Timestamp of when this poll will close (NULL if no close date set)",
'resolve' => function ($poll) {
if( $poll->poll_close_date instanceof \IPS\DateTime )
if( $poll->poll_close_date instanceof DateTime )
{
return $poll->poll_close_date->getTimestamp();
}
@@ -136,10 +141,11 @@ class _PollType extends ObjectType
/**
* Resolve poll questions field
*
* @param \IPS\Poll
* @param Poll $poll
* @return array
*/
protected static function getQuestions ($poll) {
protected static function getQuestions ( Poll $poll ) : array
{
$questions = array();
foreach ( $poll->choices as $idx => $choice )
@@ -161,7 +167,7 @@ class _PollType extends ObjectType
// Get the voters for each choice in advance here, but we won't load the member
// until questions -> choices -> voters is resolved in PollQuestionType
$voters = array();
$query = \IPS\Db::i()->select( '*', 'core_voters', array( 'poll=?', $poll->pid ) );
$query = Db::i()->select( '*', 'core_voters', array( 'poll=?', $poll->pid ) );
foreach( $query as $voter )
{
@@ -170,16 +176,16 @@ class _PollType extends ObjectType
$voteData = json_decode( $voter['member_choices'] );
foreach( $voteData as $questionIdx => $answer )
{
if( \is_array( $answer ) )
if( is_array( $answer ) )
{
foreach( $answer as $_answer )
{
$questions[ $questionIdx ]['voters'][ \intval( $_answer ) ][] = $voter['member_id'];
$questions[ $questionIdx ]['voters'][ intval( $_answer ) ][] = $voter['member_id'];
}
}
else
{
$questions[ $questionIdx ]['voters'][ \intval( $answer ) ][] = $voter['member_id'];
$questions[ $questionIdx ]['voters'][ intval( $answer ) ][] = $voter['member_id'];
}
}
}
@@ -12,23 +12,24 @@
namespace IPS\core\api\GraphQL\Types;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\Member;
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;
}
/**
* PopularContributorsType for GraphQL API
*/
class _PopularContributorType extends ObjectType
class PopularContributorType extends ObjectType
{
/**
* Get object type
*
* @return ObjectType
*/
public function __construct()
{
@@ -38,19 +39,19 @@ class _PopularContributorType extends ObjectType
return [
'rep' => [
'type' => TypeRegistry::int(),
'resolve' => function ($contributor, $args) {
'resolve' => function ($contributor) {
return $contributor['rep'];
}
],
'user' => [
'type' => \IPS\core\api\GraphQL\TypeRegistry::member(),
'resolve' => function ($contributor, $args) {
'resolve' => function ($contributor) {
if( $contributor['member_id'] )
{
return \IPS\Member::load( $contributor['member_id'] );
return Member::load( $contributor['member_id'] );
}
return new \IPS\Member;
return new Member;
}
]
];
@@ -12,23 +12,24 @@
namespace IPS\core\api\GraphQL\Types;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\Member;
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;
}
/**
* StreamType for GraphQL API
*/
class _ProfileFieldGroupType extends ObjectType
class ProfileFieldGroupType extends ObjectType
{
/**
* Get object type
*
* @return ObjectType
*/
public function __construct()
{
@@ -55,7 +56,7 @@ class _ProfileFieldGroupType extends ObjectType
'type' => TypeRegistry::string(),
'description' => "Profile field group title",
'resolve' => function ($fieldGroup) {
return \IPS\Member::loggedIn()->language()->get( $fieldGroup['title'] );
return Member::loggedIn()->language()->get( $fieldGroup['title'] );
}
],
'fields' => [
@@ -12,23 +12,24 @@
namespace IPS\core\api\GraphQL\Types;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\Member;
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;
}
/**
* ProfileFieldType for GraphQL API
*/
class _ProfileFieldType extends ObjectType
class ProfileFieldType extends ObjectType
{
/**
* Get object type
*
* @return ObjectType
*/
public function __construct()
{
@@ -56,7 +57,7 @@ class _ProfileFieldType extends ObjectType
'type' => TypeRegistry::string(),
'description' => "Profile field title",
'resolve' => function ($field) {
return \IPS\Member::loggedIn()->language()->get( $field['title'] );
return Member::loggedIn()->language()->get( $field['title'] );
}
],
'value' => [
@@ -13,23 +13,30 @@ namespace IPS\core\api\GraphQL\Types;
use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\UnionType;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\Content;
use IPS\Content\Comment;
use IPS\Content\Item;
use IPS\Content\Review;
use IPS\Member;
use IPS\Node\Model;
use function count;
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;
}
/**
* PromotedItemType for GraphQL API
*/
class _PromotedItemType extends ObjectType
class PromotedItemType extends ObjectType
{
/**
* Get object type
*
* @return ObjectType
*/
public function __construct()
{
@@ -49,7 +56,7 @@ class _PromotedItemType extends ObjectType
'type' => \IPS\core\api\GraphQL\TypeRegistry::member(),
'description' => 'Who promoted this item',
'resolve' => function ($item) {
return \IPS\Member::load( $item->added_by );
return Member::load( $item->added_by );
}
],
'images' => [
@@ -58,7 +65,7 @@ class _PromotedItemType extends ObjectType
'resolve' => function ($item) {
$images = array();
if( \count( $item->imageObjects() ) )
if( count( $item->imageObjects() ) )
{
foreach( $item->imageObjects() as $file )
{
@@ -87,23 +94,24 @@ class _PromotedItemType extends ObjectType
'type' => new UnionType([
'name' => 'core_PromotedItem_TypeUnion',
'types' => [
\IPS\Content\Api\GraphQL\TypeRegistry::comment(),
\IPS\Content\Api\GraphQL\TypeRegistry::item(),
Content\Api\GraphQL\TypeRegistry::comment(),
Content\Api\GraphQL\TypeRegistry::item(),
\IPS\Node\Api\GraphQL\TypeRegistry::node()
],
'resolveType' => function ($item) {
if ( $item instanceof \IPS\Content\Comment )
if ( $item instanceof Comment )
{
return \IPS\Content\Api\GraphQL\TypeRegistry::comment();
return Content\Api\GraphQL\TypeRegistry::comment();
}
else if ( $item instanceof \IPS\Content\Item )
else if ( $item instanceof Item )
{
return \IPS\Content\Api\GraphQL\TypeRegistry::item();
return Content\Api\GraphQL\TypeRegistry::item();
}
else if( $item instanceof \IPS\Node\Model )
else if( $item instanceof Model )
{
return \IPS\Node\Api\GraphQL\TypeRegistry::node();
}
}
return null;
}
]),
'description' => 'The original item',
@@ -118,26 +126,23 @@ class _PromotedItemType extends ObjectType
]),
'description' => "What kind of content is this item?",
'resolve' => function ($item) {
if ( $item->object() instanceof \IPS\Content\Comment )
if ( $item->object() instanceof Comment )
{
return 'COMMENT';
}
else if ( $item->object() instanceof \IPS\Content\Review )
else if ( $item->object() instanceof Review )
{
return 'REVIEW';
}
else if ( $item->object() instanceof \IPS\Content )
else if ( $item->object() instanceof Content )
{
return 'ITEM';
}
else if ( $item->object() instanceof \IPS\Node\Model )
else if ( $item->object() instanceof Model )
{
return 'NODE';
}
print_r( $item->object() );
exit;
return NULL;
}
],
@@ -145,7 +150,7 @@ class _PromotedItemType extends ObjectType
'type' => TypeRegistry::string(),
'description' => 'Promoted blurb provided by staff',
'resolve' => function ($item) {
$text = trim( $item->getText('internal', false) );
$text = trim( $item->getText(false) );
if( $text ){
return $text;
@@ -164,8 +169,7 @@ class _PromotedItemType extends ObjectType
'reputation' => [
'type' => TypeRegistry::reputation(),
'resolve' => function ($item) {
$reactionClass = $item->objectReactionClass;
return $reactionClass;
return $item->objectReactionClass;
}
],
'dataCount' => [
@@ -12,23 +12,23 @@
namespace IPS\core\api\GraphQL\Types;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\TypeRegistry;
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;
}
/**
* ReportReasonType for GraphQL API
*/
class _ReportReasonType extends ObjectType
class ReportReasonType extends ObjectType
{
/**
* Get object type
*
* @return ObjectType
*/
public function __construct()
{
@@ -12,23 +12,25 @@
namespace IPS\core\api\GraphQL\Types;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\Content;
use IPS\Member;
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;
}
/**
* ReportType for GraphQL API
*/
class _ReportType extends ObjectType
class ReportType extends ObjectType
{
/**
* Get object type
*
* @return ObjectType
*/
public function __construct()
{
@@ -98,10 +100,11 @@ class _ReportType extends ObjectType
/**
* Returns whether the user has reported this content
*
* @param Content $content
* @return boolean
*/
protected function hasReported($content)
protected function hasReported( Content $content ) : bool
{
return ( $content->canReport( \IPS\Member::loggedIn() ) === 'report_err_already_reported' );
return ( $content->canReport( Member::loggedIn() ) === 'report_err_already_reported' );
}
}
@@ -10,19 +10,21 @@
namespace IPS\core\api\GraphQL\Types;
use GraphQL\Type\Definition\UnionType;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\core\api\GraphQL\TypeRegistry;
use IPS\Member;
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;
}
/**
* @brief Search result union type
*/
class _SearchResultType extends UnionType
class SearchResultType extends UnionType
{
public function __construct()
{
@@ -30,17 +32,17 @@ class _SearchResultType extends UnionType
'name' => 'core_SearchResult',
'description' => 'A union type that returns either a member, or a content search result',
'types' => [
\IPS\core\api\GraphQL\TypeRegistry::member(),
\IPS\core\api\GraphQL\TypeRegistry::contentSearchResult()
TypeRegistry::member(),
TypeRegistry::contentSearchResult()
],
'resolveType' => function ($result) {
if ( $result instanceof \IPS\Member )
if ( $result instanceof Member )
{
return \IPS\core\api\GraphQL\TypeRegistry::member();
return TypeRegistry::member();
}
else
{
return \IPS\core\api\GraphQL\TypeRegistry::contentSearchResult();
return TypeRegistry::contentSearchResult();
}
}
];
@@ -12,23 +12,25 @@
namespace IPS\core\api\GraphQL\Types;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\core\modules\front\search\search;
use IPS\Member;
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;
}
/**
* SearchType for GraphQL API
*/
class _SearchType extends ObjectType
class SearchType extends ObjectType
{
/**
* Get object type
*
* @return ObjectType
*/
public function __construct()
{
@@ -64,15 +66,17 @@ class _SearchType extends ObjectType
{
case 'key':
return $type;
break;
case 'lang':
return \IPS\Member::loggedIn()->language()->get( $type . '_pl' );
break;
return Member::loggedIn()->language()->get( $type . '_pl' );
}
return null;
}
]) ),
'resolve' => function () {
return array_merge( array('core_members'), array_keys( \IPS\core\modules\front\search\search::contentTypes() ) );
return array_merge( array('core_members'), array_keys( search::contentTypes() ) );
}
]
];
@@ -10,25 +10,38 @@
*/
namespace IPS\core\api\GraphQL\Types;
use Exception;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\Application;
use IPS\core\Reports\Report;
use IPS\core\Reports\Types;
use IPS\File;
use IPS\forums\Topic;
use IPS\GeoLocation;
use IPS\Helpers\Form\Editor;
use IPS\Helpers\Form\Upload;
use IPS\Login;
use IPS\Member;
use IPS\Settings;
use function defined;
use function strtoupper;
/* 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;
}
/**
* SettingsType for GraphQL API
*/
class _SettingsType extends ObjectType
class SettingsType extends ObjectType
{
/**
* Get object type
*
* @return ObjectType
*/
public function __construct()
{
@@ -91,7 +104,7 @@ class _SettingsType extends ObjectType
'values' => ['NORMAL', 'FULL', 'REDIRECT', 'DISABLED']
]),
'resolve' => function ($val, $args, $context, $info) {
return \strtoupper( \IPS\Login::registrationType() );
return strtoupper( Login::registrationType() );
}
],
'allow_reg_target' => [
@@ -103,13 +116,13 @@ class _SettingsType extends ObjectType
'geolocation_enabled' => [
'type' => TypeRegistry::boolean(),
'resolve' => function () {
return \IPS\GeoLocation::enabled();
return GeoLocation::enabled();
}
],
'version' => [
'type' => TypeRegistry::int(),
'resolve' => function () {
return \IPS\Application::load('core')->long_version;
return Application::load('core')->long_version;
}
],
@@ -121,13 +134,13 @@ class _SettingsType extends ObjectType
'values' => ['INTERNAL', 'EXTERNAL', 'NONE']
]),
'resolve' => function ($val) {
return mb_strtoupper( \IPS\Settings::i()->privacy_type );
return mb_strtoupper( Settings::i()->privacy_type );
}
],
'privacy_text' => [
'type' => TypeRegistry::richText(),
'resolve' => function () {
return \IPS\Member::loggedIn()->language()->get('privacy_text_value');
return Member::loggedIn()->language()->get('privacy_text_value');
}
],
'privacy_link' => [
@@ -136,7 +149,7 @@ class _SettingsType extends ObjectType
'reg_rules' => [
'type' => TypeRegistry::richText(),
'resolve' => function () {
return \IPS\Member::loggedIn()->language()->get('reg_rules_value');
return Member::loggedIn()->language()->get('reg_rules_value');
}
],
'guidelines_type' => [
@@ -145,31 +158,28 @@ class _SettingsType extends ObjectType
'values' => ['INTERNAL', 'EXTERNAL', 'NONE']
]),
'resolve' => function ($val) {
return mb_strtoupper( \IPS\Settings::i()->gl_type );
return mb_strtoupper( Settings::i()->gl_type );
}
],
'guidelines_text' => [
'type' => TypeRegistry::richText(),
'resolve' => function ($val) {
return \IPS\Member::loggedIn()->language()->get('guidelines_value');
return Member::loggedIn()->language()->get('guidelines_value');
}
],
'guidelines_link' => [
'type' => TypeRegistry::string(),
'resolve' => function ($val) {
return \IPS\Settings::i()->gl_link;
return Settings::i()->gl_link;
}
],
/* -------------------------------- */
/* Forums settings */
'forums_questions_downvote' => [
'type' => TypeRegistry::boolean()
],
'forums_uses_solved' => [
'type' => TypeRegistry::boolean(),
'resolve' => function ($val) {
return \IPS\Application::appIsEnabled('forums') && \IPS\forums\Topic::anyContainerAllowsSolvable();
return Application::appIsEnabled('forums') && Topic::anyContainerAllowsSolvable();
}
],
@@ -179,14 +189,14 @@ class _SettingsType extends ObjectType
'type' => TypeRegistry::listOf( TypeRegistry::string() ),
'description' => "File extensions that are allowed to be uploaded or NULL for any extensions. Note: may be an empty array which means attachments not allowed.",
'resolve' => function() {
return \IPS\Helpers\Form\Editor::allowedFileExtensions();
return Editor::allowedFileExtensions();
}
],
'chunkingSupported' => [
'type' => TypeRegistry::boolean(),
'description' => "If chunking is supported",
'resolve' => function() {
$storageClass = \IPS\File::getClass( 'core_Attachment' );
$storageClass = File::getClass( 'core_Attachment' );
return $storageClass::$supportsChunking;
}
],
@@ -194,7 +204,7 @@ class _SettingsType extends ObjectType
'type' => TypeRegistry::int(),
'description' => "The maximum size (in bytes) the server can handle without crashing. If chunking is supported, you can send chunks of up to this size - if it isn't, this effectively becomes the maximum size per file.",
'resolve' => function() {
return \IPS\Helpers\Form\Upload::maxChunkSize();
return Upload::maxChunkSize();
}
],
@@ -204,7 +214,7 @@ class _SettingsType extends ObjectType
'type' => TypeRegistry::boolean(),
'description' => "Whether the automoderation feature is enabled",
'resolve' => function () {
return \IPS\Settings::i()->automoderation_enabled;
return Settings::i()->automoderation_enabled;
}
],
'reportReasons' => [
@@ -214,11 +224,11 @@ class _SettingsType extends ObjectType
$options = array();
$options[] = array(
'id' => \IPS\core\Reports\Report::TYPE_MESSAGE,
'reason' => \IPS\Member::loggedIn()->language()->addToStack('report_message_item')
'id' => Report::TYPE_MESSAGE,
'reason' => Member::loggedIn()->language()->addToStack('report_message_item')
);
foreach( \IPS\core\Reports\Types::roots() as $type )
foreach( Types::roots() as $type )
{
$options[] = array(
'id' => $type->id,
@@ -235,9 +245,9 @@ class _SettingsType extends ObjectType
$setting = $info->fieldName;
try
{
return \IPS\Settings::i()->$setting;
return Settings::i()->$setting;
}
catch(\Exception $error)
catch(Exception $error)
{
return null;
}
@@ -10,25 +10,32 @@
*/
namespace IPS\core\api\GraphQL\Types;
use DateInterval;
use Exception;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\Application;
use IPS\Data\Cache;
use IPS\DateTime;
use IPS\Db;
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;
}
/**
* StatsType for GraphQL API
*/
class _StatsType extends ObjectType
class StatsType extends ObjectType
{
/**
* Get object type
*
* @return ObjectType
*/
public function __construct()
{
@@ -41,7 +48,7 @@ class _StatsType extends ObjectType
'type' => TypeRegistry::int(),
'description' => "Content count",
'resolve' => function () {
return (int) static::getContentCount();
return static::getContentCount();
}
],
'memberCount' => [
@@ -58,18 +65,18 @@ class _StatsType extends ObjectType
parent::__construct($config);
}
protected static function getContentCount()
protected static function getContentCount() : int
{
$cacheKey = 'content_count';
$total = 0;
try
{
return \IPS\Data\Cache::i()->getWithExpire( $cacheKey, TRUE );
return Cache::i()->getWithExpire( $cacheKey, TRUE );
}
catch( \OutOfRangeException $e ){}
catch( OutOfRangeException $e ){}
foreach( \IPS\Application::enabledApplications() as $app )
foreach( Application::enabledApplications() as $app )
{
foreach( $app->extensions( 'core', 'ContentRouter', TRUE, TRUE ) as $object )
{
@@ -121,25 +128,24 @@ class _StatsType extends ObjectType
}
}
}
catch( \Exception $e ){}
catch( Exception $e ){}
}
}
}
}
\IPS\Data\Cache::i()->storeWithExpire( $cacheKey, $total, \IPS\DateTime::create()->add( new \DateInterval('P1W') ), TRUE );
Cache::i()->storeWithExpire( $cacheKey, $total, DateTime::create()->add( new DateInterval('P1W') ), TRUE );
return $total;
}
protected static function getMemberCount()
protected static function getMemberCount() : ?int
{
try
{
$memberCount = \IPS\Db::i()->select( 'COUNT(*)', 'core_members', array( 'completed=?', true ) )->first();
return $memberCount;
return Db::i()->select( 'COUNT(*)', 'core_members', array( 'completed=?', true ) )->first();
}
catch ( \Exception $e )
catch ( Exception $e )
{
return NULL;
}
@@ -12,23 +12,27 @@
namespace IPS\core\api\GraphQL\Types;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\Content\Search\Query;
use IPS\Content\Search\Results;
use IPS\core\Stream;
use IPS\Member;
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;
}
/**
* StreamType for GraphQL API
*/
class _StreamType extends ObjectType
class StreamType extends ObjectType
{
/**
* Get object type
*
* @return ObjectType
*/
public function __construct()
{
@@ -49,7 +53,7 @@ class _StreamType extends ObjectType
'description' => "Stream title",
'resolve' => function ($stream) {
if( !$stream->title ) {
return \IPS\Member::loggedIn()->language()->addToStack( "stream_title_{$stream->id}" );
return Member::loggedIn()->language()->addToStack( "stream_title_{$stream->id}" );
}
return $stream->title;
}
@@ -58,7 +62,7 @@ class _StreamType extends ObjectType
'type' => \IPS\core\api\GraphQL\TypeRegistry::member(),
'description' => "Stream owner, if applicable",
'resolve' => function ($stream) {
return ( $stream->member ) ? \IPS\Member::load( $stream->member ) : null;
return ( $stream->member ) ? Member::load( $stream->member ) : null;
}
],
'isDefault' => [
@@ -98,11 +102,12 @@ class _StreamType extends ObjectType
/**
* Resolve items
*
* @param \IPS\core\Stream
* @param array Arguments passed from resolver
* @return array
* @param Stream $stream
* @param array $args Arguments passed from resolver
* @param array $context
* @return Results
*/
protected static function items( $stream, $args, $context )
protected static function items( Stream $stream, array $args, array $context ) : Results
{
/* Clubs */
if( isset( $args['club'] ) )
@@ -120,7 +125,7 @@ class _StreamType extends ObjectType
}
/* Build the query */
$query = $stream->query( \IPS\Member::loggedIn() );
$query = $stream->query( Member::loggedIn() );
// Get page
// We don't know the count at this stage, so figure out the page number from
@@ -137,7 +142,7 @@ class _StreamType extends ObjectType
$query->setLimit( $limit )->setPage( $page );
/* Get the results */
$results = $query->search( NULL, NULL, ( $stream->include_comments ? \IPS\Content\Search\Query::TAGS_MATCH_ITEMS_ONLY + \IPS\Content\Search\Query::TERM_OR_TAGS : \IPS\Content\Search\Query::TERM_OR_TAGS ) );
$results = $query->search( NULL, NULL, ( $stream->include_comments ? Query::TAGS_MATCH_ITEMS_ONLY + Query::TERM_OR_TAGS : Query::TERM_OR_TAGS ) );
/* Load data we need like the authors, etc */
$results->init();
@@ -12,23 +12,24 @@
namespace IPS\core\api\GraphQL\Types;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\TypeRegistry;
use IPS\Http\Url;
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;
}
/**
* TagType for GraphQL API
*/
class _TagType extends ObjectType
class TagType extends ObjectType
{
/**
* Get object type
*
* @return ObjectType
*/
public function __construct()
{
@@ -49,7 +50,7 @@ class _TagType extends ObjectType
'description' => "Tag URL",
'resolve' => function ($tag) {
$_tag = urlencode($tag);
return \IPS\Http\Url::internal( "app=core&module=search&controller=search&tags={$_tag}", 'front', 'tags' );
return Url::internal( "app=core&module=discover&controller=tag&tag={$_tag}", 'front', 'tags' );
}
]
];
@@ -12,23 +12,23 @@
namespace IPS\core\api\GraphQL\Types;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\TypeRegistry;
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;
}
/**
* UploadProgressType for GraphQL API
*/
class _UploadProgressType extends ObjectType
class UploadProgressType extends ObjectType
{
/**
* Get object type
*
* @return ObjectType
*/
public function __construct()
{