Version 4.7.0

This commit is contained in:
Neo committed 2025-12-19 16:00:35 -08:00
1 parent 517a5e1f70
commit 8ba7d43898
1933 files changed
+65613 -11332

No files matched your search

@@ -36,8 +36,6 @@ abstract class _Mutation
'follow' => new \IPS\core\api\GraphQL\Mutations\Follow(),
'unfollow' => new \IPS\core\api\GraphQL\Mutations\Unfollow(),
'markNotificationRead' => new \IPS\core\api\GraphQL\Mutations\MarkNotificationRead(),
'sessionStart' => new \IPS\core\api\GraphQL\Mutations\SessionStart(),
'sessionEnd' => new \IPS\core\api\GraphQL\Mutations\SessionEnd(),
'uploadAttachment' => new \IPS\core\api\GraphQL\Mutations\UploadAttachment(),
'deleteAttachment' => new \IPS\core\api\GraphQL\Mutations\DeleteAttachment(),
'ignoreMember' => new \IPS\core\api\GraphQL\Mutations\IgnoreUser(),
@@ -1,102 +0,0 @@
<?php
/**
* @brief GraphQL: End a session for the user
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Community Suite
* @since 02 Apr 2019
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\api\GraphQL\Mutations;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\TypeRegistry;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Register a push token for a specific user
*/
class _SessionEnd
{
/*
* @brief Query description
*/
public static $description = "End a user session";
/*
* Mutation arguments
*/
public function args()
{
return [
'token' => TypeRegistry::string()
];
}
/**
* Return the mutation return type
*/
public function type()
{
return \IPS\core\Api\GraphQL\TypeRegistry::member();
}
/**
* Resolves this mutation
* @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
* @return \IPS\forums\Forum
*/
public function resolve($val, $args)
{
if( !\IPS\Member::loggedIn()->member_id )
{
throw new \IPS\Api\GraphQL\SafeException( 'NOT_LOGGED_IN', 'GQL/0001/6', 403 );
}
\IPS\Db::i()->update( 'core_oauth_server_access_tokens', array( 'status' => 'revoked' ), array( 'member_id=? AND access_token=?', \IPS\Member::loggedIn()->member_id, \IPS\Dispatcher::i()->accessToken['access_token'] ) );
if ( isset( \IPS\Dispatcher::i()->accessToken['device_key'] ) )
{
\IPS\Db::i()->update( 'core_oauth_server_access_tokens', array( 'status' => 'revoked' ), array( 'member_id=? AND device_key=?', \IPS\Member::loggedIn()->member_id, \IPS\Dispatcher::i()->accessToken['device_key'] ) );
}
if ( isset( $args['token'] ) and $args['token'] )
{
try
{
$response = \IPS\Http\Url::ips('mobile/signout')->request()->login( \IPS\Settings::i()->mobile_app_id, \IPS\Settings::i()->mobile_app_secret )->post( array(
'member' => \IPS\Member::loggedIn()->member_id,
'token' => $args['token']
) )->decodeJson();
if ( $response->httpResponseCode != 200 )
{
throw new \DomainException( (string) $response );
}
if ( !$response['remainingDevices'] )
{
\IPS\Member::loggedIn()->members_bitoptions['mobile_notifications'] = FALSE;
\IPS\Member::loggedIn()->save();
}
}
catch ( \Exception $e )
{
\IPS\Log::log( $e, 'mobile-push-notifications' );
}
}
return \IPS\Member::loggedIn();
}
}
@@ -1,116 +0,0 @@
<?php
/**
* @brief GraphQL: Start a session for a user
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Community Suite
* @since 20 Mar 2019
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\api\GraphQL\Mutations;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\TypeRegistry;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Register a push token for a specific user
*/
class _SessionStart
{
/*
* @brief Query description
*/
public static $description = "Start a session for an authenticated user";
/*
* Mutation arguments
*/
public function args()
{
return [
'token' => TypeRegistry::string()
];
}
/**
* Return the mutation return type
*/
public function type()
{
return \IPS\core\Api\GraphQL\TypeRegistry::member();
}
/**
* Resolves this mutation
* @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
* @return \IPS\forums\Forum
*/
public function resolve($val, $args)
{
if( !\IPS\Member::loggedIn()->member_id )
{
throw new \IPS\Api\GraphQL\SafeException( 'NOT_LOGGED_IN', 'GQL/0001/6', 403 );
}
if ( isset( $args['token'] ) and $args['token'] )
{
try
{
/* Register the token with the backend */
$response = \IPS\Http\Url::ips('mobile/signin')->request()->login( \IPS\Settings::i()->mobile_app_id, \IPS\Settings::i()->mobile_app_secret )->post( array(
'member' => \IPS\Member::loggedIn()->member_id,
'token' => $args['token']
) );
if ( !\in_array( $response->httpResponseCode, array( 200, 201 ) ) )
{
throw new \DomainException( (string) $response );
}
/* If we didn't already have notifications enabled, enable them and set the defaults */
if ( !\IPS\Member::loggedIn()->members_bitoptions['mobile_notifications'] )
{
\IPS\Member::loggedIn()->members_bitoptions['mobile_notifications'] = TRUE;
\IPS\Member::loggedIn()->save();
$notificationPreferences = \IPS\Db::i()->select( '*', 'core_notification_preferences', array( 'member_id=?', \IPS\Member::loggedIn()->member_id ) );
if ( \count( $notificationPreferences ) )
{
$keysToAddPushTo = array();
foreach ( $notificationPreferences as $row )
{
if ( \in_array( 'inline', explode( ',', $row['preference'] ) ) )
{
$keysToAddPushTo[] = $row['notification_key'];
}
}
if ( \count( $keysToAddPushTo ) )
{
\IPS\Db::i()->update( 'core_notification_preferences', "`preference` = IF( `preference` = '', 'push', CONCAT_WS( ',', `preference`, 'push' ) )", array( array( 'member_id=?', \IPS\Member::loggedIn()->member_id ), array( \IPS\Db::i()->in( 'notification_key', $keysToAddPushTo ) ) ) );
}
}
}
}
catch ( \Exception $e )
{
\IPS\Log::log( $e, 'mobile-push-notifications' );
}
}
return \IPS\Member::loggedIn();
}
}
@@ -1,81 +0,0 @@
<?php
/**
* @brief GraphQL: Mobile menu query
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Community Suite
* @since 12 June 2019
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\api\GraphQL\Queries;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\TypeRegistry;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Mobile menu query for GraphQL API
*/
class _MobileMenu
{
/*
* @brief Query description
*/
public static $description = "Returns details of the mobile app menu";
/*
* Query arguments
*/
public function args()
{
return array();
}
/**
* Return the query return type
*/
public function type()
{
return TypeRegistry::listOf( \IPS\core\api\GraphQL\TypeRegistry::mobileMenu() );
}
/**
* Resolves this query
*
* @param mixed Value passed into this resolver
* @param array Arguments
* @param array Context values
* @return array
*/
public function resolve($val, $args, $context)
{
$return = array();
foreach ( \IPS\Db::i()->select( '*', 'core_mobileapp_menu', NULL, 'position' ) as $item )
{
if ( \IPS\Application::appIsEnabled( $item['app'] ) )
{
$class = 'IPS\\' . $item['app'] . '\extensions\core\MobileNavigation\\' . $item['extension'];
if ( class_exists( $class ) )
{
$object = new $class( json_decode( $item['config'], TRUE ), $item['id'], $item['permissions'] );
if ( $object->canView() )
{
$return[ $item['id'] ] = $object;
}
}
}
}
return $return;
}
}
-1
View File
@@ -46,7 +46,6 @@ abstract class _Query
'messengerConversation' => new \IPS\core\api\GraphQL\Queries\MessengerConversation(),
'messengerConversations' => new \IPS\core\api\GraphQL\Queries\MessengerConversations(),
'messengerFolders' => new \IPS\core\api\GraphQL\Queries\MessengerFolders(),
'mobileMenu' => new \IPS\core\api\GraphQL\Queries\MobileMenu(),
'notificationTypes' => new \IPS\core\api\GraphQL\Queries\NotificationTypes(),
'ourPicks' => new \IPS\core\api\GraphQL\Queries\OurPicks(),
'popularContributors' => new \IPS\core\api\GraphQL\Queries\PopularContributors(),
@@ -38,7 +38,6 @@ class _TypeRegistry
protected static $group;
protected static $ignoreOption;
protected static $member;
protected static $mobileMenu;
protected static $language;
protected static $login;
protected static $messengerConversation;
@@ -151,14 +150,6 @@ class _TypeRegistry
{
return self::$member ?: (self::$member = new \IPS\core\api\GraphQL\Types\MemberType());
}
/**
* @return MobileMenuType
*/
public static function mobileMenu()
{
return self::$mobileMenu ?: (self::$mobileMenu = new \IPS\core\api\GraphQL\Types\MobileMenuType());
}
/**
* @return LanguageType
@@ -499,7 +499,7 @@ class _MemberType extends ObjectType
/* 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( "`member`=?", \IPS\Member::loggedIn()->member_id );
/* Are we filtering by unread status? */
if( isset( $args['unread'] ) && $args['unread'] !== NULL )
@@ -1,81 +0,0 @@
<?php
/**
* @brief GraphQL: Mobile Menu Type
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Community Suite
* @since 12 June 2019
* @version SVN_VERSION_NUMBER
*/
namespace IPS\core\api\GraphQL\Types;
use GraphQL\Type\Definition\ObjectType;
use IPS\Api\GraphQL\TypeRegistry;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Mobile Menu Type for GraphQL API
*/
class _MobileMenuType extends ObjectType
{
/**
* Get object type
*
* @return ObjectType
*/
public function __construct()
{
$config = [
'name' => 'core_MobileMenu',
'description' => 'Mobile menu item type',
'fields' => function () {
return [
'id' => [
'type' => TypeRegistry::id(),
'description' => "Item ID",
'resolve' => function ( $item ) {
return $item->id;
}
],
'class' => [
'type' => TypeRegistry::string(),
'description' => "Class which handles this item",
'resolve' => function ( $item ) {
return \get_class( $item );
}
],
'title' => [
'type' => TypeRegistry::string(),
'description' => "Menu item title",
'resolve' => function ($item) {
return $item->title();
}
],
'icon' => [
'type' => TypeRegistry::string(),
'description' => "Icon key for this item",
'resolve' => function ($item) {
return $item->icon();
}
],
'url' => [
'type' => TypeRegistry::url(),
'description' => "URL to content",
'resolve' => function ( $item ) {
return $item->link();
}
]
];
}
];
parent::__construct($config);
}
}
@@ -104,7 +104,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\Settings::i()->mobile_app_id || !\IPS\Member::loggedIn()->members_bitoptions['mobile_notifications'] )
if ( !isset( $type['push'] ) || !\count( $type['push'] ) || !\IPS\Member::loggedIn()->members_bitoptions['mobile_notifications'] )
{
return NULL;
}
@@ -126,7 +126,6 @@ class _PollQuestionType extends ObjectType
'description' => "The choices for this question",
'resolve' => function ($question) {
$choices = array();
$canViewCount = \IPS\Member::loggedIn()->modPermission('can_edit_poll_votes');
foreach( $question['data']['choice'] as $idx => $choice )
{
@@ -106,22 +106,6 @@ class _SettingsType extends ObjectType
return \IPS\GeoLocation::enabled();
}
],
'mobileHomeBlocks' => [
'type' => TypeRegistry::listOf( TypeRegistry::string() ),
'resolve' => function () {
try
{
$parsed = json_decode( \IPS\Settings::i()->mobile_app_home_blocks_order, TRUE );
$blocksToShow = array_filter( $parsed );
return array_keys( $blocksToShow );
}
catch (\Exception $e)
{
return array("new_content", "active_users", "our_picks", "popular_contributors");
}
}
],
'version' => [
'type' => TypeRegistry::int(),
'resolve' => function () {
@@ -41,14 +41,16 @@ class _StatsType extends ObjectType
'type' => TypeRegistry::int(),
'description' => "Content count",
'resolve' => function () {
return ( isset( \IPS\Settings::i()->mobile_app_hide_stats ) && \IPS\Settings::i()->mobile_app_hide_stats ) ? NULL : static::getContentCount();
// Return null for now until GQL is fleshed out
return NULL;
}
],
'memberCount' => [
'type' => TypeRegistry::int(),
'description' => 'Member count',
'resolve' => function () {
return ( isset( \IPS\Settings::i()->mobile_app_hide_stats ) && \IPS\Settings::i()->mobile_app_hide_stats ) ? NULL : static::getMemberCount();
// Return null for now until GQL is fleshed out
return NULL;
}
]
];