Created
October 22, 2021 09:42
-
-
Save pbalan/1627bcd88b3da44ed15716739d3ba108 to your computer and use it in GitHub Desktop.
graphql
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\Exceptions; | |
use Exception; | |
use Nuwave\Lighthouse\Exceptions\RendersErrorsExtensions; | |
class GraphQLException extends Exception implements RendersErrorsExtensions | |
{ | |
/** | |
* @var @string | |
*/ | |
protected $reason; | |
public function __construct(string $message, $reason) | |
{ | |
parent::__construct($message); | |
$this->reason = json_encode($reason); | |
} | |
/** | |
* Returns true when exception message is safe to be displayed to a client. | |
* | |
* @api | |
* @return bool | |
*/ | |
public function isClientSafe(): bool | |
{ | |
return true; | |
} | |
/** | |
* Returns string describing a category of the error. | |
* | |
* Value "graphql" is reserved for errors produced by query parsing or validation, do not use it. | |
* | |
* @api | |
* @return string | |
*/ | |
public function getCategory(): string | |
{ | |
return 'custom'; | |
} | |
/** | |
* Return the content that is put in the "extensions" part | |
* of the returned error. | |
* | |
* @return array | |
*/ | |
public function extensionsContent(): array | |
{ | |
return [ | |
'some' => 'additional information', | |
'reason' => $this->reason, | |
]; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\Traits; | |
use App\User; | |
use Illuminate\Database\Eloquent\Model; | |
use Illuminate\Support\Facades\Auth; | |
use Illuminate\Support\Facades\Log; | |
trait HasOwner | |
{ | |
static $belongsTo = 'BelongsTo'; | |
public static function boot() | |
{ | |
try { | |
parent::boot(); | |
if (Auth::check()) { | |
$user = User::where('auth0_id', Auth::user()->sub)->first(); | |
static::creating(function (Model $model) use ($user) { | |
foreach ($model->relationships() as $field => $relation) { | |
try { | |
if (property_exists($model, 'notOwner') && is_array($model->notOwner) && in_array($relation['foreign'], $model->notOwner)) { | |
continue; | |
} | |
if (self::$belongsTo === $relation['type'] && User::class === $relation['model'] && null !== $user) { | |
$model->{$relation['foreign']} = $user->id; | |
} | |
} catch(\Exception $ex) { | |
Log::info($user->toArray()); | |
Log::info(sprintf('field: %s, foreign: %s', $field, $relation['foreign'])); | |
Log::info($ex->getMessage()); | |
throw $ex; | |
} | |
} | |
}); | |
static::saving(function (Model $model) use ($user) { | |
foreach ($model->relationships() as $field => $relation) { | |
try { | |
if (property_exists($model, 'notOwner') && is_array($model->notOwner) && in_array($relation['foreign'], $model->notOwner)) { | |
continue; | |
} | |
if (self::$belongsTo === $relation['type'] && User::class === $relation['model'] && null !== $user) { | |
$model->{$relation['foreign']} = $user->id; | |
} | |
} catch(\Exception $ex) { | |
Log::info($user->toArray()); | |
Log::info(sprintf('field: %s, foreign: %s', $field, $relation['foreign'])); | |
Log::info($ex->getMessage()); | |
throw $ex; | |
} | |
} | |
}); | |
} | |
} catch (\Exception $e) { | |
Log::info($e->getMessage()); | |
throw $e; | |
} | |
} | |
public function scopeIsOwner($query) | |
{ | |
$field = 'user_id'; | |
if (User::class === get_class($query->getModel())) { | |
$field = 'id'; | |
} | |
$user = User::where('auth0_id', Auth::user()->sub)->first(); | |
return $query->where($field, $user->id); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\GraphQL\Directives; | |
use Nuwave\Lighthouse\Exceptions\AuthenticationException; | |
use Illuminate\Contracts\Auth\Factory as Auth; | |
use GraphQL\Language\AST\Node; | |
use GraphQL\Language\AST\NodeList; | |
use GraphQL\Language\AST\FieldDefinitionNode; | |
use GraphQL\Language\AST\ObjectTypeExtensionNode; | |
use GraphQL\Type\Definition\ResolveInfo; | |
use Nuwave\Lighthouse\Support\Contracts\FieldManipulator; | |
use Nuwave\Lighthouse\Support\Contracts\GraphQLContext; | |
use Nuwave\Lighthouse\Schema\Values\FieldValue; | |
use GraphQL\Language\Parser; | |
use Nuwave\Lighthouse\Schema\AST\ASTHelper; | |
use Nuwave\Lighthouse\Schema\AST\DocumentAST; | |
use Nuwave\Lighthouse\Support\Contracts\CreatesContext; | |
use Nuwave\Lighthouse\Schema\Directives\BaseDirective; | |
use Nuwave\Lighthouse\Support\Contracts\FieldMiddleware; | |
class ProtectDirective extends BaseDirective implements FieldManipulator, FieldMiddleware | |
{ | |
/** | |
* The authentication factory instance. | |
* | |
* @var \Illuminate\Contracts\Auth\Factory | |
*/ | |
protected $auth; | |
/** @var CreatesContext */ | |
protected $createsContext; | |
/** | |
* Create a new middleware instance. | |
* | |
* @param \Illuminate\Contracts\Auth\Factory $auth | |
* @return void | |
*/ | |
public function __construct(Auth $auth, CreatesContext $createsContext) | |
{ | |
$this->auth = $auth; | |
$this->createsContext = $createsContext; | |
} | |
/** | |
* Directive name. | |
* | |
* @return string | |
*/ | |
public function name(): string | |
{ | |
return 'protect'; | |
} | |
/** | |
* Resolve the field directive. | |
* | |
* @param FieldValue $fieldValue | |
* @param \Closure $next | |
* | |
* @return FieldValue | |
*/ | |
public function handleField(FieldValue $fieldValue, \Closure $next) | |
{ | |
$resolver = $fieldValue->getResolver(); | |
return $next($fieldValue->setResolver(function ($root, array $args, GraphQLContext $context, ResolveInfo $resolveInfo) use ($resolver) { | |
$guards = $this->directiveArgValue('guards', []); | |
$this->authenticate($context->request, $guards); | |
return $resolver( | |
$root, | |
$args, | |
$this->createsContext->generate($context->request()), | |
$resolveInfo | |
); | |
})); | |
} | |
/** | |
* @param Node $node | |
* @param DocumentAST $documentAST | |
* | |
* @return DocumentAST | |
*/ | |
public function manipulateFieldDefinition(DocumentAST &$documentAST, FieldDefinitionNode &$fieldDefinition, &$parentType): DocumentAST | |
{ | |
$args = $this->directiveArgValue('guards', []); | |
$node = $this->setProtectDirectiveOnFields($fieldDefinition, $args); | |
$documentAST->setDefinition($node); | |
return $documentAST; | |
} | |
/** | |
* @param FieldDefinitionNode|ObjectTypeExtensionNode $objectType | |
* | |
* @throws \Nuwave\Lighthouse\Exceptions\DirectiveException | |
* | |
* @return FieldDefinitionNode|ObjectTypeExtensionNode | |
*/ | |
protected function setProtectDirectiveOnFields($objectType, array $args) | |
{ | |
$objectType->fields = new NodeList( | |
collect($objectType->fields) | |
->map(function (FieldDefinitionNode $fieldDefinition) use ($args) { | |
$existingProtectDirective = ASTHelper::directiveDefinition( | |
$fieldDefinition, | |
$this->name() | |
); | |
if ($existingProtectDirective){ | |
return $fieldDefinition; | |
} else { | |
$protectArgValue = collect($args)->implode('", "'); | |
$directive = !empty($args) | |
? Parser::directive("@protect(guards: [\"$protectArgValue\"])") | |
: Parser::directive("@protect"); | |
$fieldDefinition->directives = $fieldDefinition->directives->merge([$directive]); | |
return $fieldDefinition; | |
} | |
}) | |
->toArray() | |
); | |
return $objectType; | |
} | |
/** | |
* Determine if the user is logged in to any of the given guards. | |
* | |
* @param \Illuminate\Http\Request $request | |
* @param array $guards | |
* @return void | |
* | |
* @throws \App\Containers\Core\GraphQL\Exceptions\AuthException | |
*/ | |
protected function authenticate($request, array $guards) | |
{ | |
if (empty($guards)) { | |
$guards = [null]; | |
} | |
foreach ($guards as $guard) { | |
if ($this->auth->guard($guard)->check()) { | |
return $this->auth->shouldUse($guard); | |
} | |
} | |
throw new AuthenticationException("You are not authorized to view this resource"); | |
} | |
public static function definition(): string | |
{ | |
// TODO: Implement definition() method. | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\Traits; | |
use Illuminate\Database\Eloquent\Relations\Relation; | |
use Illuminate\Support\Facades\Log; | |
use ReflectionClass; | |
use ReflectionMethod; | |
trait Relationship | |
{ | |
public function relationships() | |
{ | |
$model = new static; | |
$relationships = []; | |
foreach ((new ReflectionClass($model))->getMethods(ReflectionMethod::IS_PUBLIC) as $method) { | |
if ( | |
$method->class != get_class($model) || | |
!empty($method->getParameters()) || | |
$method->getName() == __FUNCTION__ | |
) { | |
continue; | |
} | |
$forgin = null; | |
try { | |
$return = $method->invoke($model); | |
if ($return instanceof Relation) { | |
$returnReflection = new ReflectionClass($return); | |
$ownerKey = null; | |
if ($returnReflection->hasMethod('getOwnerKey')) | |
$ownerKey = $return->getOwnerKey(); | |
else { | |
$segments = explode('.', $return->getQualifiedParentKeyName()); | |
$ownerKey = $segments[count($segments) - 1]; | |
} | |
if ($returnReflection->hasMethod('getForeignKey')) { | |
$forgin = $return->getForeignKey(); | |
} else if ($returnReflection->hasMethod('getForeignKeyName')) { | |
$forgin = $return->getForeignKeyName(); | |
} else if ($returnReflection->hasMethod('getForeignPivotKeyName')) { | |
$forgin = $return->getForeignPivotKeyName(); | |
} | |
$relationships[$method->getName()] = [ | |
'type' => $returnReflection->getShortName(), | |
'model' => (new ReflectionClass($return->getRelated()))->getName(), | |
'owner' => $ownerKey, | |
'foreign' => $forgin | |
]; | |
} | |
} catch (\Exception $e) { | |
Log::info("Error while creating relationship matrix", [$e->getMessage()]); | |
} | |
} | |
return $relationships; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
type Admin @model(class: "\\Modules\\Example\\Entities\\Admin") { | |
id: ID! | |
admin: User @belongsTo | |
addedBy: User @belongsTo | |
created_at: DateTime! | |
updated_at: DateTime! | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment