-
-
Notifications
You must be signed in to change notification settings - Fork 622
Expand file tree
/
Copy pathEntryQuery.php
More file actions
135 lines (108 loc) · 3.88 KB
/
EntryQuery.php
File metadata and controls
135 lines (108 loc) · 3.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
<?php
namespace Statamic\GraphQL\Queries;
use Facades\Statamic\API\FilterAuthorizer;
use Facades\Statamic\API\ResourceAuthorizer;
use Facades\Statamic\GraphQL\Middleware\AuthorizeFilters;
use GraphQL\Type\Definition\Type;
use Illuminate\Validation\ValidationException;
use Statamic\Facades;
use Statamic\Facades\GraphQL;
use Statamic\GraphQL\Middleware\AuthorizeSubResources;
use Statamic\GraphQL\Queries\Concerns\FiltersQuery;
use Statamic\GraphQL\Types\EntryInterface;
use Statamic\GraphQL\Types\JsonArgument;
class EntryQuery extends Query
{
use FiltersQuery {
filterQuery as traitFilterQuery;
}
protected $attributes = [
'name' => 'entry',
];
protected $middleware = [
AuthorizeSubResources::class,
];
public function type(): Type
{
return GraphQL::type(EntryInterface::NAME);
}
public function args(): array
{
return [
'id' => GraphQL::string(),
'slug' => GraphQL::string(),
'collection' => GraphQL::string(),
'uri' => GraphQL::string(),
'site' => GraphQL::string(),
'filter' => GraphQL::type(JsonArgument::NAME),
];
}
public function resolve($root, $args)
{
$query = Facades\Entry::query();
if ($id = $args['id'] ?? null) {
$query->where('id', $id);
}
if ($slug = $args['slug'] ?? null) {
$query->where('slug', $slug);
}
if ($collection = $args['collection'] ?? null) {
$query->where('collection', $collection);
}
if ($uri = $args['uri'] ?? null) {
$query->where('uri', $uri);
}
if ($site = $args['site'] ?? null) {
$query->where('site', $site);
}
$filters = $args['filter'] ?? [];
$this->filterQuery($query, $filters);
$entry = $query->limit(1)->get()->first();
if ($entry && $entry->published() === false && ! request()->isLivePreviewOf($entry)) {
return null;
}
// The `AuthorizeSubResources` middleware will authorize when using `collection` arg,
// but this is still required when the user queries entry using other args.
if ($entry && ! in_array($collection = $entry->collection()->handle(), $this->allowedSubResources())) {
throw ValidationException::withMessages([
'collection' => 'Forbidden: '.$collection,
]);
}
// We cannot use the `AuthorizeFilters` middleware on this query, because
// you can get an entry by `id`, `slug`, `uri`, etc. so we'll get the
// queried entry's collection and authorize filters manually here.
if ($entry && $filters) {
$allowedFilters = collect($this->allowedFilters([
'collection' => $entry->collection()->handle(),
]));
$forbidden = collect($filters)
->keys()
->filter(fn ($filter) => ! $allowedFilters->contains($filter));
if ($forbidden->isNotEmpty()) {
throw ValidationException::withMessages([
'filter' => 'Forbidden: '.$forbidden->join(', '),
]);
}
}
return $entry;
}
private function filterQuery($query, $filters)
{
if (! request()->isLivePreview() && (! isset($filters['status']) && ! isset($filters['published']))) {
$filters['status'] = 'published';
}
$this->traitFilterQuery($query, $filters);
}
public function subResourceArg()
{
return 'collection';
}
public function allowedSubResources()
{
return ResourceAuthorizer::allowedSubResources('graphql', 'collections');
}
public function allowedFilters($args)
{
return FilterAuthorizer::allowedForSubResources('graphql', 'collections', $args['collection'] ?? '*');
}
}