mirror of
https://github.com/AnimeThemes/animethemes-server.git
synced 2026-07-11 01:24:46 +02:00
feat: GraphQL (#814)
This commit is contained in:
@@ -198,6 +198,13 @@ IMAGE_DISK_ROOT=
|
||||
JETSTREAM_PATH=
|
||||
JETSTREAM_URL=http://localhost
|
||||
|
||||
# lighthouse
|
||||
GRAPHQL_DOMAIN_NAME=
|
||||
GRAPHQL_PATH=/graphql
|
||||
LIGHTHOUSE_DEBUG=true
|
||||
LIGHTHOUSE_MAX_QUERY_COMPLEXITY=100
|
||||
LIGHTHOUSE_MAX_QUERY_DEPTH=10
|
||||
|
||||
# logging
|
||||
LOG_CHANNEL=daily
|
||||
LOG_DEPRECATIONS_CHANNEL=null
|
||||
|
||||
@@ -196,6 +196,13 @@ IMAGE_DISK_ROOT=
|
||||
JETSTREAM_PATH=
|
||||
JETSTREAM_URL=http://localhost
|
||||
|
||||
# lighthouse
|
||||
GRAPHQL_DOMAIN_NAME=
|
||||
GRAPHQL_PATH=/graphql
|
||||
LIGHTHOUSE_DEBUG=true
|
||||
LIGHTHOUSE_MAX_QUERY_COMPLEXITY=100
|
||||
LIGHTHOUSE_MAX_QUERY_DEPTH=10
|
||||
|
||||
# logging
|
||||
LOG_CHANNEL=daily
|
||||
LOG_DEPRECATIONS_CHANNEL=null
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Contracts\Models;
|
||||
|
||||
use App\Models\Service\ViewAggregate;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphOne;
|
||||
|
||||
/**
|
||||
* Interface HasAggregateViews.
|
||||
*
|
||||
* @property ViewAggregate|null $viewAggregate
|
||||
*/
|
||||
interface HasAggregateViews
|
||||
{
|
||||
/**
|
||||
* Get the views count of the model.
|
||||
*
|
||||
* @return MorphOne
|
||||
*/
|
||||
public function viewAggregate(): MorphOne;
|
||||
}
|
||||
@@ -13,6 +13,8 @@ enum SpecialPermission: string
|
||||
|
||||
case BYPASS_FEATURE_FLAGS = 'bypass feature flags';
|
||||
|
||||
case BYPASS_GRAPHQL_RATE_LIMITER = 'bypass graphql rate limiter';
|
||||
|
||||
case VIEW_FILAMENT = 'view filament';
|
||||
|
||||
case VIEW_HORIZON = 'view horizon';
|
||||
|
||||
@@ -5,6 +5,7 @@ declare(strict_types=1);
|
||||
namespace App\Enums\Models\Wiki;
|
||||
|
||||
use App\Concerns\Enums\LocalizesName;
|
||||
use App\GraphQL\Types\Definition\Hidden;
|
||||
|
||||
/**
|
||||
* Enum ThemeType.
|
||||
@@ -14,6 +15,9 @@ enum ThemeType: int
|
||||
use LocalizesName;
|
||||
|
||||
case OP = 0;
|
||||
|
||||
case ED = 1;
|
||||
|
||||
#[Hidden]
|
||||
case IN = 2;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\GraphQL\Builders\Admin;
|
||||
|
||||
use App\Constants\FeatureConstants;
|
||||
use App\Models\Admin\Feature;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Nuwave\Lighthouse\Execution\ResolveInfo;
|
||||
use Nuwave\Lighthouse\Support\Contracts\GraphQLContext;
|
||||
|
||||
/**
|
||||
* Class FeatureBuilder.
|
||||
*/
|
||||
class FeatureBuilder
|
||||
{
|
||||
/**
|
||||
* Apply the query builder to the index query.
|
||||
*
|
||||
* @param Builder $builder
|
||||
* @param mixed $value
|
||||
* @param mixed $root
|
||||
* @param array $args
|
||||
* @param GraphQLContext $context
|
||||
* @param ResolveInfo $resolveInfo
|
||||
* @return Builder
|
||||
*/
|
||||
public function index(Builder $builder, mixed $value, mixed $root, array $args, GraphQLContext $context, ResolveInfo $resolveInfo): Builder
|
||||
{
|
||||
return $builder->where(Feature::ATTRIBUTE_SCOPE, FeatureConstants::NULL_SCOPE);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\GraphQL\Builders\Admin;
|
||||
|
||||
use App\Enums\Http\Api\Filter\ComparisonOperator;
|
||||
use App\Models\Admin\FeaturedTheme;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Facades\Date;
|
||||
use Nuwave\Lighthouse\Execution\ResolveInfo;
|
||||
use Nuwave\Lighthouse\Support\Contracts\GraphQLContext;
|
||||
|
||||
/**
|
||||
* Class FeaturedThemeBuilder.
|
||||
*/
|
||||
class FeaturedThemeBuilder
|
||||
{
|
||||
/**
|
||||
* Apply the query builder to the index query.
|
||||
*
|
||||
* @param Builder $builder
|
||||
* @param mixed $value
|
||||
* @param mixed $root
|
||||
* @param array $args
|
||||
* @param GraphQLContext $context
|
||||
* @param ResolveInfo $resolveInfo
|
||||
* @return Builder
|
||||
*/
|
||||
public function index(Builder $builder, mixed $value, mixed $root, array $args, GraphQLContext $context, ResolveInfo $resolveInfo): Builder
|
||||
{
|
||||
return $builder->whereNotNull(FeaturedTheme::ATTRIBUTE_START_AT)
|
||||
->whereDate(FeaturedTheme::ATTRIBUTE_START_AT, ComparisonOperator::LTE->value, Date::now());
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the query builder to the index query.
|
||||
*
|
||||
* @param Builder $builder
|
||||
* @param mixed $value
|
||||
* @param mixed $root
|
||||
* @param array $args
|
||||
* @param GraphQLContext $context
|
||||
* @param ResolveInfo $resolveInfo
|
||||
* @return Builder
|
||||
*/
|
||||
public function current(Builder $builder, mixed $value, mixed $root, array $args, GraphQLContext $context, ResolveInfo $resolveInfo): Builder
|
||||
{
|
||||
return $builder->whereNotNull(FeaturedTheme::ATTRIBUTE_START_AT)
|
||||
->whereNotNull(FeaturedTheme::ATTRIBUTE_END_AT)
|
||||
->whereDate(FeaturedTheme::ATTRIBUTE_START_AT, ComparisonOperator::LTE->value, Date::now())
|
||||
->whereDate(FeaturedTheme::ATTRIBUTE_END_AT, ComparisonOperator::GT->value, Date::now());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\GraphQL\Builders\List\External;
|
||||
|
||||
use App\Models\List\External\ExternalEntry;
|
||||
use App\Models\List\ExternalProfile;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Arr;
|
||||
use Nuwave\Lighthouse\Execution\ResolveInfo;
|
||||
use Nuwave\Lighthouse\Support\Contracts\GraphQLContext;
|
||||
|
||||
/**
|
||||
* Class ExternalEntryBuilder.
|
||||
*/
|
||||
class ExternalEntryBuilder
|
||||
{
|
||||
/**
|
||||
* Apply the query builder to the index query.
|
||||
*
|
||||
* @param Builder $builder
|
||||
* @param mixed $value
|
||||
* @param mixed $root
|
||||
* @param array $args
|
||||
* @param GraphQLContext $context
|
||||
* @param ResolveInfo $resolveInfo
|
||||
* @return Builder
|
||||
*/
|
||||
public function index(Builder $builder, mixed $value, mixed $root, array $args, GraphQLContext $context, ResolveInfo $resolveInfo): Builder
|
||||
{
|
||||
/** @var ExternalProfile $profile */
|
||||
$profile = Arr::get($args, 'profile');
|
||||
|
||||
$builder->where(ExternalEntry::ATTRIBUTE_PROFILE, $profile->getKey());
|
||||
|
||||
return $builder;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\GraphQL\Builders\List;
|
||||
|
||||
use App\Enums\Models\List\ExternalProfileVisibility;
|
||||
use App\Models\List\ExternalProfile;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Nuwave\Lighthouse\Execution\ResolveInfo;
|
||||
use Nuwave\Lighthouse\Support\Contracts\GraphQLContext;
|
||||
|
||||
/**
|
||||
* Class ExternalProfileBuilder.
|
||||
*/
|
||||
class ExternalProfileBuilder
|
||||
{
|
||||
/**
|
||||
* Apply the query builder to the index query.
|
||||
*
|
||||
* @param Builder $builder
|
||||
* @param mixed $value
|
||||
* @param mixed $root
|
||||
* @param array $args
|
||||
* @param GraphQLContext $context
|
||||
* @param ResolveInfo $resolveInfo
|
||||
* @return Builder
|
||||
*/
|
||||
public function index(Builder $builder, mixed $value, mixed $root, array $args, GraphQLContext $context, ResolveInfo $resolveInfo): Builder
|
||||
{
|
||||
$builder->where(ExternalProfile::ATTRIBUTE_VISIBILITY, ExternalProfileVisibility::PUBLIC->value);
|
||||
|
||||
if ($user = Auth::user()) {
|
||||
return $builder->orWhereBelongsTo($user, ExternalProfile::RELATION_USER);
|
||||
}
|
||||
|
||||
return $builder;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\GraphQL\Builders\List\Playlist;
|
||||
|
||||
use App\Models\List\Playlist;
|
||||
use App\Models\List\Playlist\PlaylistTrack;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Arr;
|
||||
use Nuwave\Lighthouse\Execution\ResolveInfo;
|
||||
use Nuwave\Lighthouse\Support\Contracts\GraphQLContext;
|
||||
|
||||
/**
|
||||
* Class PlaylistTrackBuilder.
|
||||
*/
|
||||
class PlaylistTrackBuilder
|
||||
{
|
||||
/**
|
||||
* Apply the query builder to the index query.
|
||||
*
|
||||
* @param Builder $builder
|
||||
* @param mixed $value
|
||||
* @param mixed $root
|
||||
* @param array $args
|
||||
* @param GraphQLContext $context
|
||||
* @param ResolveInfo $resolveInfo
|
||||
* @return Builder
|
||||
*/
|
||||
public function index(Builder $builder, mixed $value, mixed $root, array $args, GraphQLContext $context, ResolveInfo $resolveInfo): Builder
|
||||
{
|
||||
/** @var Playlist $playlist */
|
||||
$playlist = Arr::get($args, 'playlist');
|
||||
|
||||
$builder->where(PlaylistTrack::ATTRIBUTE_PLAYLIST, $playlist->getKey());
|
||||
|
||||
return $builder;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\GraphQL\Builders\List;
|
||||
|
||||
use App\Enums\Models\List\PlaylistVisibility;
|
||||
use App\Models\List\Playlist;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Nuwave\Lighthouse\Execution\ResolveInfo;
|
||||
use Nuwave\Lighthouse\Support\Contracts\GraphQLContext;
|
||||
|
||||
/**
|
||||
* Class PlaylistBuilder.
|
||||
*/
|
||||
class PlaylistBuilder
|
||||
{
|
||||
/**
|
||||
* Apply the query builder to the index query.
|
||||
*
|
||||
* @param Builder $builder
|
||||
* @param mixed $value
|
||||
* @param mixed $root
|
||||
* @param array $args
|
||||
* @param GraphQLContext $context
|
||||
* @param ResolveInfo $resolveInfo
|
||||
* @return Builder
|
||||
*/
|
||||
public function index(Builder $builder, mixed $value, mixed $root, array $args, GraphQLContext $context, ResolveInfo $resolveInfo): Builder
|
||||
{
|
||||
$builder->where(Playlist::ATTRIBUTE_VISIBILITY, PlaylistVisibility::PUBLIC->value);
|
||||
|
||||
if ($user = Auth::user()) {
|
||||
return $builder->orWhereBelongsTo($user, Playlist::RELATION_USER);
|
||||
}
|
||||
|
||||
return $builder;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\GraphQL\Directives;
|
||||
|
||||
use GraphQL\Type\Definition\ResolveInfo;
|
||||
use Nuwave\Lighthouse\Schema\Directives\BaseDirective;
|
||||
use Nuwave\Lighthouse\Schema\Values\FieldValue;
|
||||
use Nuwave\Lighthouse\Support\Contracts\FieldMiddleware;
|
||||
use Nuwave\Lighthouse\Support\Contracts\GraphQLContext;
|
||||
|
||||
/**
|
||||
* Class LocalizedEnumDirective.
|
||||
*/
|
||||
class LocalizedEnumDirective extends BaseDirective implements FieldMiddleware
|
||||
{
|
||||
/**
|
||||
* Define the directive.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function definition(): string
|
||||
{
|
||||
return /** @lang GraphQL */ <<<'GRAPHQL'
|
||||
"""
|
||||
Translate the enum value.
|
||||
"""
|
||||
directive @localizedEnum on FIELD_DEFINITION
|
||||
GRAPHQL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap around the final field resolver.
|
||||
*
|
||||
* @param FieldValue $fieldValue
|
||||
* @return void
|
||||
*/
|
||||
public function handleField(FieldValue $fieldValue): void
|
||||
{
|
||||
$fieldValue->wrapResolver(
|
||||
fn (callable $resolver) => function ($root, array $args, GraphQLContext $context, ResolveInfo $resolveInfo) use ($resolver) {
|
||||
|
||||
/** @phpstan-ignore-next-line */
|
||||
$enum = $resolver($root, $args, $context, $resolveInfo);
|
||||
|
||||
return $enum->localize();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\GraphQL\Directives;
|
||||
|
||||
use Illuminate\Support\Facades\App;
|
||||
use Nuwave\Lighthouse\Schema\Directives\BaseDirective;
|
||||
use Nuwave\Lighthouse\Schema\Values\TypeValue;
|
||||
use Nuwave\Lighthouse\Support\Contracts\TypeMiddleware;
|
||||
|
||||
/**
|
||||
* Class MiddlewareDirective.
|
||||
*/
|
||||
class MiddlewareDirective extends BaseDirective implements TypeMiddleware
|
||||
{
|
||||
/**
|
||||
* Define the directive.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function definition(): string
|
||||
{
|
||||
return /** @lang GraphQL */ <<<'GRAPHQL'
|
||||
directive @middleware(class: String!) on OBJECT
|
||||
GRAPHQL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a type AST as it is converted to an executable type.
|
||||
*
|
||||
* @param TypeValue $value
|
||||
* @return void
|
||||
*/
|
||||
public function handleNode(TypeValue $value): void
|
||||
{
|
||||
$class = $this->directiveArgValue('class');
|
||||
|
||||
App::make($class)->handle(request(), fn () => null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\GraphQL\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
/**
|
||||
* Class GraphQLPolicy.
|
||||
*/
|
||||
class GraphQLPolicy
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Closure(Request): mixed $next
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle(Request $request, Closure $next): mixed
|
||||
{
|
||||
Gate::guessPolicyNamesUsing(
|
||||
fn (string $modelClass) => Str::of($modelClass)
|
||||
->replace('Models', 'GraphQL\\Policies')
|
||||
->append('Policy')
|
||||
->__toString()
|
||||
);
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\GraphQL\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
/**
|
||||
* Class GraphqlLocalhost.
|
||||
*/
|
||||
class GraphqlLocalhost
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Closure(Request): mixed $next
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle(Request $request, Closure $next): mixed
|
||||
{
|
||||
$ip = $request->ip();
|
||||
|
||||
if ($ip !== '127.0.0.1' && app()->isProduction()) {
|
||||
abort(403, "GraphQL is only enabled for localhost");
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\GraphQL\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
|
||||
/**
|
||||
* Class MaxCount.
|
||||
*/
|
||||
class MaxCount
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Closure(Request): mixed $next
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle(Request $request, Closure $next): mixed
|
||||
{
|
||||
Config::set('lighthouse.pagination.max_count', $request->ip() === '127.0.0.1' ? null : 100);
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\GraphQL\Mutations\List;
|
||||
|
||||
use App\Models\List\ExternalProfile;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Support\Arr;
|
||||
|
||||
/**
|
||||
* Class ExternalProfileMutator.
|
||||
*/
|
||||
class ExternalProfileMutator
|
||||
{
|
||||
final public const ROUTE_SLUG = 'id';
|
||||
|
||||
/**
|
||||
* Start a new sync job.
|
||||
*
|
||||
* @param null $_
|
||||
* @param array $args
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function sync($_, array $args): JsonResponse
|
||||
{
|
||||
/** @var ExternalProfile $profile */
|
||||
$profile = Arr::pull($args, self::ROUTE_SLUG);
|
||||
|
||||
if (!$profile->canBeSynced()) {
|
||||
return new JsonResponse([
|
||||
'error' => 'This external profile cannot be synced at the moment.'
|
||||
], 403);
|
||||
}
|
||||
|
||||
$profile->startSyncJob();
|
||||
|
||||
return new JsonResponse([
|
||||
'message' => 'Job dispatched.'
|
||||
], 201);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\GraphQL\Mutations\List\Playlist;
|
||||
|
||||
use App\Actions\Http\Api\List\Playlist\Track\DestroyTrackAction;
|
||||
use App\Actions\Http\Api\List\Playlist\Track\ForceDeleteTrackAction;
|
||||
use App\Actions\Http\Api\List\Playlist\Track\RestoreTrackAction;
|
||||
use App\Actions\Http\Api\List\Playlist\Track\StoreTrackAction;
|
||||
use App\Actions\Http\Api\List\Playlist\Track\UpdateTrackAction;
|
||||
use App\Models\List\Playlist;
|
||||
use App\Models\List\Playlist\PlaylistTrack;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Support\Arr;
|
||||
|
||||
/**
|
||||
* Class PlaylistTrackMutator.
|
||||
*/
|
||||
class PlaylistTrackMutator
|
||||
{
|
||||
final public const ROUTE_SLUG = 'id';
|
||||
|
||||
/**
|
||||
* Store a newly created resource.
|
||||
*
|
||||
* @param null $_
|
||||
* @param array $args
|
||||
* @return PlaylistTrack
|
||||
*/
|
||||
public function store($_, array $args): PlaylistTrack
|
||||
{
|
||||
/** @var Playlist $playlist */
|
||||
$playlist = Arr::pull($args, 'playlist');
|
||||
|
||||
$action = new StoreTrackAction();
|
||||
|
||||
/** @var PlaylistTrack $stored */
|
||||
$stored = $action->store($playlist, PlaylistTrack::query(), $args);
|
||||
|
||||
return $stored;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource.
|
||||
*
|
||||
* @param null $_
|
||||
* @param array $args
|
||||
* @return PlaylistTrack
|
||||
*/
|
||||
public function update($_, array $args): PlaylistTrack
|
||||
{
|
||||
/** @var PlaylistTrack $track */
|
||||
$track = Arr::pull($args, self::ROUTE_SLUG);
|
||||
|
||||
$action = new UpdateTrackAction();
|
||||
|
||||
/** @var PlaylistTrack $updated */
|
||||
$updated = $action->update($track->playlist, $track, $args);
|
||||
|
||||
return $updated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource.
|
||||
*
|
||||
* @param null $_
|
||||
* @param array $args
|
||||
* @return PlaylistTrack
|
||||
*/
|
||||
public function destroy($_, array $args): PlaylistTrack
|
||||
{
|
||||
/** @var PlaylistTrack $track */
|
||||
$track = Arr::get($args, self::ROUTE_SLUG);
|
||||
|
||||
$action = new DestroyTrackAction();
|
||||
|
||||
/** @var PlaylistTrack $destroyed */
|
||||
$destroyed = $action->destroy($track->playlist, $track);
|
||||
|
||||
return $destroyed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore the specified resource.
|
||||
*
|
||||
* @param null $_
|
||||
* @param array $args
|
||||
* @return PlaylistTrack
|
||||
*/
|
||||
public function restore($_, array $args): PlaylistTrack
|
||||
{
|
||||
/** @var PlaylistTrack $track */
|
||||
$track = Arr::get($args, self::ROUTE_SLUG);
|
||||
|
||||
$action = new RestoreTrackAction();
|
||||
|
||||
/** @var PlaylistTrack $restored */
|
||||
$restored = $action->restore($track->playlist, $track);
|
||||
|
||||
return $restored;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hard-delete the specified resource.
|
||||
*
|
||||
* @param null $_
|
||||
* @param array $args
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function forceDelete($_, array $args): JsonResponse
|
||||
{
|
||||
/** @var PlaylistTrack $track */
|
||||
$track = Arr::get($args, self::ROUTE_SLUG);
|
||||
|
||||
$action = new ForceDeleteTrackAction();
|
||||
|
||||
$message = $action->forceDelete($track->playlist, $track);
|
||||
|
||||
return new JsonResponse([
|
||||
'message' => $message,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\GraphQL\Mutations\List;
|
||||
|
||||
use App\Actions\Http\Api\DestroyAction;
|
||||
use App\Actions\Http\Api\ForceDeleteAction;
|
||||
use App\Actions\Http\Api\RestoreAction;
|
||||
use App\Actions\Http\Api\StoreAction;
|
||||
use App\Actions\Http\Api\UpdateAction;
|
||||
use App\Models\List\Playlist;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
/**
|
||||
* Class PlaylistMutator.
|
||||
*/
|
||||
class PlaylistMutator
|
||||
{
|
||||
final public const ROUTE_SLUG = 'id';
|
||||
|
||||
/**
|
||||
* Store a newly created resource.
|
||||
*
|
||||
* @param null $_
|
||||
* @param array $args
|
||||
* @return Playlist
|
||||
*/
|
||||
public function store($_, array $args): Playlist
|
||||
{
|
||||
$parameters = [
|
||||
...$args,
|
||||
Playlist::ATTRIBUTE_USER => Auth::id()
|
||||
];
|
||||
|
||||
$action = new StoreAction();
|
||||
|
||||
/** @var Playlist $stored */
|
||||
$stored = $action->store(Playlist::query(), $parameters);
|
||||
|
||||
return $stored;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource.
|
||||
*
|
||||
* @param null $_
|
||||
* @param array $args
|
||||
* @return Playlist
|
||||
*/
|
||||
public function update($_, array $args): Playlist
|
||||
{
|
||||
/** @var Playlist $playlist */
|
||||
$playlist = Arr::pull($args, self::ROUTE_SLUG);
|
||||
|
||||
$action = new UpdateAction();
|
||||
|
||||
/** @var Playlist $updated */
|
||||
$updated = $action->update($playlist, $args);
|
||||
|
||||
return $updated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource.
|
||||
*
|
||||
* @param null $_
|
||||
* @param array $args
|
||||
* @return Playlist
|
||||
*/
|
||||
public function destroy($_, array $args): Playlist
|
||||
{
|
||||
/** @var Playlist $playlist */
|
||||
$playlist = Arr::get($args, self::ROUTE_SLUG);
|
||||
|
||||
$action = new DestroyAction();
|
||||
|
||||
/** @var Playlist $destroyed */
|
||||
$destroyed = $action->destroy($playlist);
|
||||
|
||||
return $destroyed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore the specified resource.
|
||||
*
|
||||
* @param null $_
|
||||
* @param array $args
|
||||
* @return Playlist
|
||||
*/
|
||||
public function restore($_, array $args): Playlist
|
||||
{
|
||||
$hashId = Arr::get($args, self::ROUTE_SLUG);
|
||||
|
||||
$playlist = Playlist::withTrashed()->firstWhere(Playlist::ATTRIBUTE_HASHID, $hashId);
|
||||
|
||||
$action = new RestoreAction();
|
||||
|
||||
/** @var Playlist $restored */
|
||||
$restored = $action->restore($playlist);
|
||||
|
||||
return $restored;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hard-delete the specified resource.
|
||||
*
|
||||
* @param null $_
|
||||
* @param array $args
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function forceDelete($_, array $args): JsonResponse
|
||||
{
|
||||
/** @var Playlist $playlist */
|
||||
$playlist = Arr::get($args, self::ROUTE_SLUG);
|
||||
|
||||
$action = new ForceDeleteAction();
|
||||
|
||||
$message = $action->forceDelete($playlist);
|
||||
|
||||
return new JsonResponse([
|
||||
'message' => $message,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\GraphQL\Policies\Admin;
|
||||
|
||||
use App\GraphQL\Policies\BasePolicy;
|
||||
|
||||
/**
|
||||
* Class AnnouncementPolicy.
|
||||
*/
|
||||
class AnnouncementPolicy extends BasePolicy
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\GraphQL\Policies\Admin;
|
||||
|
||||
use App\GraphQL\Policies\BasePolicy;
|
||||
|
||||
/**
|
||||
* Class DumpPolicy.
|
||||
*/
|
||||
class DumpPolicy extends BasePolicy
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\GraphQL\Policies\Admin;
|
||||
|
||||
use App\GraphQL\Policies\BasePolicy;
|
||||
use App\Models\Admin\Feature;
|
||||
use App\Models\Auth\User;
|
||||
use Illuminate\Support\Arr;
|
||||
|
||||
/**
|
||||
* Class FeaturePolicy.
|
||||
*/
|
||||
class FeaturePolicy extends BasePolicy
|
||||
{
|
||||
/**
|
||||
* Determine whether the user can view the model.
|
||||
*
|
||||
* @param User|null $user
|
||||
* @param array|null $injected
|
||||
* @return bool
|
||||
*/
|
||||
public function view(?User $user, ?array $injected = null): bool
|
||||
{
|
||||
/** @var Feature $feature */
|
||||
$feature = Arr::get($injected, 'id');
|
||||
|
||||
return $feature->isNullScope();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\GraphQL\Policies\Admin;
|
||||
|
||||
use App\GraphQL\Policies\BasePolicy;
|
||||
use App\Models\Admin\FeaturedTheme;
|
||||
use App\Models\Auth\User;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Facades\Date;
|
||||
|
||||
/**
|
||||
* Class FeaturedThemePolicy.
|
||||
*/
|
||||
class FeaturedThemePolicy extends BasePolicy
|
||||
{
|
||||
/**
|
||||
* Determine whether the user can view the model.
|
||||
*
|
||||
* @param User|null $user
|
||||
* @param array|null $injected
|
||||
* @return bool
|
||||
*/
|
||||
public function view(?User $user, ?array $injected = null): bool
|
||||
{
|
||||
/** @var FeaturedTheme $featuredtheme */
|
||||
$featuredtheme = Arr::get($injected, 'id');
|
||||
|
||||
return $featuredtheme->start_at->isBefore(Date::now());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\GraphQL\Policies\Auth;
|
||||
|
||||
use App\Enums\Auth\CrudPermission;
|
||||
use App\Enums\Auth\ExtendedCrudPermission;
|
||||
use App\GraphQL\Policies\BasePolicy;
|
||||
use App\Models\Auth\Permission;
|
||||
use App\Models\Auth\User;
|
||||
|
||||
/**
|
||||
* Class PermissionPolicy.
|
||||
*/
|
||||
class PermissionPolicy extends BasePolicy
|
||||
{
|
||||
/**
|
||||
* Determine whether the user can view any models.
|
||||
*
|
||||
* @param User|null $user
|
||||
* @param array|null $injected
|
||||
* @return bool
|
||||
*/
|
||||
public function viewAny(?User $user, ?array $injected = null): bool
|
||||
{
|
||||
return $user !== null && $user->can(CrudPermission::VIEW->format(Permission::class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can view the model.
|
||||
*
|
||||
* @param User|null $user
|
||||
* @param array|null $injected
|
||||
* @return bool
|
||||
*
|
||||
* @noinspection PhpUnusedParameterInspection
|
||||
*/
|
||||
public function view(?User $user, ?array $injected = null): bool
|
||||
{
|
||||
return $user !== null && $user->can(CrudPermission::VIEW->format(Permission::class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can update the model.
|
||||
*
|
||||
* @param User $user
|
||||
* @param array $injected
|
||||
* @return bool
|
||||
*
|
||||
* @noinspection PhpUnusedParameterInspection
|
||||
*/
|
||||
public function update(User $user, array $injected): bool
|
||||
{
|
||||
return $user->can(CrudPermission::UPDATE->format(Permission::class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can delete the model.
|
||||
*
|
||||
* @param User $user
|
||||
* @param array $injected
|
||||
* @return bool
|
||||
*
|
||||
* @noinspection PhpUnusedParameterInspection
|
||||
*/
|
||||
public function delete(User $user, array $injected): bool
|
||||
{
|
||||
return $user->can(CrudPermission::DELETE->format(Permission::class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can restore the model.
|
||||
*
|
||||
* @param User $user
|
||||
* @param array $injected
|
||||
* @return bool
|
||||
*
|
||||
* @noinspection PhpUnusedParameterInspection
|
||||
*/
|
||||
public function restore(User $user, array $injected): bool
|
||||
{
|
||||
return $user->can(ExtendedCrudPermission::RESTORE->format(Permission::class));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\GraphQL\Policies\Auth;
|
||||
|
||||
use App\Enums\Auth\CrudPermission;
|
||||
use App\Enums\Auth\ExtendedCrudPermission;
|
||||
use App\GraphQL\Policies\BasePolicy;
|
||||
use App\Models\Auth\Role;
|
||||
use App\Models\Auth\User;
|
||||
|
||||
/**
|
||||
* Class RolePolicy.
|
||||
*/
|
||||
class RolePolicy extends BasePolicy
|
||||
{
|
||||
/**
|
||||
* Determine whether the user can view any models.
|
||||
*
|
||||
* @param User|null $user
|
||||
* @param array|null $injected
|
||||
* @return bool
|
||||
*/
|
||||
public function viewAny(?User $user, ?array $injected = null): bool
|
||||
{
|
||||
return $user !== null && $user->can(CrudPermission::VIEW->format(Role::class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can view the model.
|
||||
*
|
||||
* @param User|null $user
|
||||
* @param array|null $injected
|
||||
* @return bool
|
||||
*
|
||||
* @noinspection PhpUnusedParameterInspection
|
||||
*/
|
||||
public function view(?User $user, ?array $injected = null): bool
|
||||
{
|
||||
return $user !== null && $user->can(CrudPermission::VIEW->format(Role::class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can update the model.
|
||||
*
|
||||
* @param User $user
|
||||
* @param array $injected
|
||||
* @return bool
|
||||
*
|
||||
* @noinspection PhpUnusedParameterInspection
|
||||
*/
|
||||
public function update(User $user, array $injected): bool
|
||||
{
|
||||
return $user->can(CrudPermission::UPDATE->format(Role::class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can delete the model.
|
||||
*
|
||||
* @param User $user
|
||||
* @param array $injected
|
||||
* @return bool
|
||||
*
|
||||
* @noinspection PhpUnusedParameterInspection
|
||||
*/
|
||||
public function delete(User $user, array $injected): bool
|
||||
{
|
||||
return $user->can(CrudPermission::DELETE->format(Role::class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can restore the model.
|
||||
*
|
||||
* @param User $user
|
||||
* @param array $injected
|
||||
* @return bool
|
||||
*
|
||||
* @noinspection PhpUnusedParameterInspection
|
||||
*/
|
||||
public function restore(User $user, array $injected): bool
|
||||
{
|
||||
return $user->can(ExtendedCrudPermission::RESTORE->format(Role::class));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\GraphQL\Policies\Auth;
|
||||
|
||||
use App\Enums\Auth\CrudPermission;
|
||||
use App\Enums\Auth\ExtendedCrudPermission;
|
||||
use App\GraphQL\Policies\BasePolicy;
|
||||
use App\Models\Auth\Role;
|
||||
use App\Models\Auth\User;
|
||||
|
||||
/**
|
||||
* Class UserPolicy.
|
||||
*/
|
||||
class UserPolicy extends BasePolicy
|
||||
{
|
||||
/**
|
||||
* Determine whether the user can view any models.
|
||||
*
|
||||
* @param User|null $user
|
||||
* @param array|null $injected
|
||||
* @return bool
|
||||
*/
|
||||
public function viewAny(?User $user, ?array $injected = null): bool
|
||||
{
|
||||
return $user !== null && $user->can(CrudPermission::VIEW->format(User::class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can view the model.
|
||||
*
|
||||
* @param User|null $user
|
||||
* @param array|null $injected
|
||||
* @return bool
|
||||
*
|
||||
* @noinspection PhpUnusedParameterInspection
|
||||
*/
|
||||
public function view(?User $user, ?array $injected = null): bool
|
||||
{
|
||||
return $user !== null && $user->can(CrudPermission::VIEW->format(User::class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can update the model.
|
||||
*
|
||||
* @param User $user
|
||||
* @param array $injected
|
||||
* @return bool
|
||||
*
|
||||
* @noinspection PhpUnusedParameterInspection
|
||||
*/
|
||||
public function update(User $user, array $injected): bool
|
||||
{
|
||||
return $user->can(CrudPermission::UPDATE->format(User::class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can delete the model.
|
||||
*
|
||||
* @param User $user
|
||||
* @param array $injected
|
||||
* @return bool
|
||||
*
|
||||
* @noinspection PhpUnusedParameterInspection
|
||||
*/
|
||||
public function delete(User $user, array $injected): bool
|
||||
{
|
||||
return $user->can(CrudPermission::DELETE->format(User::class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can restore the model.
|
||||
*
|
||||
* @param User $user
|
||||
* @param array $injected
|
||||
* @return bool
|
||||
*
|
||||
* @noinspection PhpUnusedParameterInspection
|
||||
*/
|
||||
public function restore(User $user, array $injected): bool
|
||||
{
|
||||
return $user->can(ExtendedCrudPermission::RESTORE->format(User::class));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\GraphQL\Policies;
|
||||
|
||||
use App\Enums\Auth\CrudPermission;
|
||||
use App\Enums\Auth\ExtendedCrudPermission;
|
||||
use App\Models\Auth\User;
|
||||
use App\Models\BaseModel;
|
||||
use Illuminate\Auth\Access\HandlesAuthorization;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
/**
|
||||
* Class BasePolicy.
|
||||
*
|
||||
* GraphQL will read any attach{model}, attachAny{model}, detach{model}, detachAny{model}
|
||||
* to make the validation for pivots. {model} must be the name of the model.
|
||||
*/
|
||||
abstract class BasePolicy
|
||||
{
|
||||
use HandlesAuthorization;
|
||||
|
||||
/**
|
||||
* Get the model class of the policy.
|
||||
*
|
||||
* @return class-string
|
||||
*/
|
||||
protected static function getModel(): string
|
||||
{
|
||||
return Str::of(get_called_class())
|
||||
->replace('GraphQL\\Policies', 'Models')
|
||||
->remove('Policy')
|
||||
->__toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can view any models.
|
||||
*
|
||||
* @param User|null $user
|
||||
* @param array|null $injected
|
||||
* @return bool
|
||||
*/
|
||||
public function viewAny(?User $user, ?array $injected = null): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can view the model.
|
||||
*
|
||||
* @param User|null $user
|
||||
* @param array|null $injected
|
||||
* @return bool
|
||||
*/
|
||||
public function view(?User $user, ?array $injected = null): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can create models.
|
||||
*
|
||||
* @param User $user
|
||||
* @param array|null $injected
|
||||
* @return bool
|
||||
*/
|
||||
public function create(User $user, ?array $injected = null): bool
|
||||
{
|
||||
return $user->can(CrudPermission::CREATE->format(static::getModel()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can update the model.
|
||||
*
|
||||
* @param User $user
|
||||
* @param array $injected
|
||||
* @return bool
|
||||
*/
|
||||
public function update(User $user, array $injected): bool
|
||||
{
|
||||
/** @var BaseModel $model */
|
||||
$model = Arr::get($injected, 'id');
|
||||
|
||||
return (!($model instanceof BaseModel) || !$model->trashed()) && $user->can(CrudPermission::UPDATE->format(static::getModel()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can delete the model.
|
||||
*
|
||||
* @param User $user
|
||||
* @param array $injected
|
||||
* @return bool
|
||||
*/
|
||||
public function delete(User $user, array $injected): bool
|
||||
{
|
||||
/** @var BaseModel $model */
|
||||
$model = Arr::get($injected, 'id');
|
||||
|
||||
return (!($model instanceof BaseModel) || !$model->trashed()) && $user->can(CrudPermission::DELETE->format(static::getModel()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can permanently delete the model.
|
||||
*
|
||||
* @param User $user
|
||||
* @return bool
|
||||
*/
|
||||
public function forceDelete(User $user): bool
|
||||
{
|
||||
return $user->can(ExtendedCrudPermission::FORCE_DELETE->format(static::getModel()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can permanently delete any model.
|
||||
*
|
||||
* @param User $user
|
||||
* @return bool
|
||||
*/
|
||||
public function forceDeleteAny(User $user): bool
|
||||
{
|
||||
return $user->can(ExtendedCrudPermission::FORCE_DELETE->format(static::getModel()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can restore the model.
|
||||
*
|
||||
* @param User $user
|
||||
* @param array $injected
|
||||
* @return bool
|
||||
*/
|
||||
public function restore(User $user, array $injected): bool
|
||||
{
|
||||
/** @var BaseModel $model */
|
||||
$model = Arr::get($injected, 'id');
|
||||
|
||||
return (!($model instanceof BaseModel) || $model->trashed()) && $user->can(ExtendedCrudPermission::RESTORE->format(static::getModel()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can restore any model.
|
||||
*
|
||||
* @param User $user
|
||||
* @return bool
|
||||
*/
|
||||
public function restoreAny(User $user): bool
|
||||
{
|
||||
return $user->can(ExtendedCrudPermission::RESTORE->format(static::getModel()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\GraphQL\Policies\Discord;
|
||||
|
||||
use App\GraphQL\Policies\BasePolicy;
|
||||
|
||||
/**
|
||||
* Class DiscordThreadPolicy.
|
||||
*/
|
||||
class DiscordThreadPolicy extends BasePolicy
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\GraphQL\Policies\Document;
|
||||
|
||||
use App\GraphQL\Policies\BasePolicy;
|
||||
|
||||
/**
|
||||
* Class PagePolicy.
|
||||
*/
|
||||
class PagePolicy extends BasePolicy
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\GraphQL\Policies\List\External;
|
||||
|
||||
use App\Enums\Auth\CrudPermission;
|
||||
use App\Enums\Auth\ExtendedCrudPermission;
|
||||
use App\Enums\Models\List\ExternalProfileVisibility;
|
||||
use App\GraphQL\Policies\BasePolicy;
|
||||
use App\Models\Auth\User;
|
||||
use App\Models\List\External\ExternalEntry;
|
||||
use App\Models\List\ExternalProfile;
|
||||
use Illuminate\Support\Arr;
|
||||
|
||||
/**
|
||||
* Class ExternalEntryPolicy.
|
||||
*/
|
||||
class ExternalEntryPolicy extends BasePolicy
|
||||
{
|
||||
/**
|
||||
* Determine whether the user can view any models.
|
||||
*
|
||||
* @param User|null $user
|
||||
* @param array|null $injected
|
||||
* @return bool
|
||||
*/
|
||||
public function viewAny(?User $user, ?array $injected = null): bool
|
||||
{
|
||||
/** @var ExternalProfile|null $profile */
|
||||
$profile = Arr::get($injected, 'profile');
|
||||
|
||||
return $user !== null
|
||||
? ($profile?->user()->is($user) || ExternalProfileVisibility::PRIVATE !== $profile?->visibility) && $user->can(CrudPermission::VIEW->format(ExternalEntry::class))
|
||||
: ExternalProfileVisibility::PRIVATE !== $profile?->visibility;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can view the model.
|
||||
*
|
||||
* @param User|null $user
|
||||
* @param array|null $injected
|
||||
* @return bool
|
||||
*
|
||||
* @noinspection PhpUnusedParameterInspection
|
||||
*/
|
||||
public function view(?User $user, ?array $injected = null): bool
|
||||
{
|
||||
/** @var ExternalProfile|null $profile */
|
||||
$profile = Arr::get($injected, 'profile');
|
||||
|
||||
return $user !== null
|
||||
? ($profile?->user()->is($user) || ExternalProfileVisibility::PRIVATE !== $profile?->visibility) && $user->can(CrudPermission::VIEW->format(ExternalEntry::class))
|
||||
: ExternalProfileVisibility::PRIVATE !== $profile?->visibility;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can create models.
|
||||
*
|
||||
* @param User $user
|
||||
* @param array|null $injected
|
||||
* @return bool
|
||||
*/
|
||||
public function create(User $user, ?array $injected = null): bool
|
||||
{
|
||||
/** @var ExternalProfile|null $profile */
|
||||
$profile = Arr::get($injected, 'profile');
|
||||
|
||||
return $profile?->user()->is($user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can update the model.
|
||||
*
|
||||
* @param User $user
|
||||
* @param array $injected
|
||||
* @return bool
|
||||
*/
|
||||
public function update(User $user, array $injected): bool
|
||||
{
|
||||
/** @var ExternalProfile|null $profile */
|
||||
$profile = Arr::get($injected, 'profile');
|
||||
/** @var ExternalEntry $entry */
|
||||
$entry = Arr::get($injected, 'id');
|
||||
|
||||
return !$entry->trashed() && $profile?->user()->is($user) && $user->can(CrudPermission::UPDATE->format(ExternalEntry::class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can delete the model.
|
||||
*
|
||||
* @param User $user
|
||||
* @param array $injected
|
||||
* @return bool
|
||||
*/
|
||||
public function delete(User $user, array $injected): bool
|
||||
{
|
||||
/** @var ExternalProfile|null $profile */
|
||||
$profile = Arr::get($injected, 'profile');
|
||||
/** @var ExternalEntry $entry */
|
||||
$entry = Arr::get($injected, 'id');
|
||||
|
||||
return !$entry->trashed() && $profile?->user()->is($user) && $user->can(CrudPermission::DELETE->format(ExternalEntry::class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can restore the model.
|
||||
*
|
||||
* @param User $user
|
||||
* @param array $injected
|
||||
* @return bool
|
||||
*/
|
||||
public function restore(User $user, array $injected): bool
|
||||
{
|
||||
/** @var ExternalProfile|null $profile */
|
||||
$profile = Arr::get($injected, 'profile');
|
||||
/** @var ExternalEntry $entry */
|
||||
$entry = Arr::get($injected, 'id');
|
||||
|
||||
return $entry->trashed() && $profile?->user()->is($user) && $user->can(ExtendedCrudPermission::RESTORE->format(ExternalEntry::class));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\GraphQL\Policies\List;
|
||||
|
||||
use App\Enums\Auth\CrudPermission;
|
||||
use App\Enums\Auth\ExtendedCrudPermission;
|
||||
use App\Enums\Models\List\ExternalProfileVisibility;
|
||||
use App\GraphQL\Policies\BasePolicy;
|
||||
use App\Models\Auth\User;
|
||||
use App\Models\List\ExternalProfile;
|
||||
use Illuminate\Support\Arr;
|
||||
|
||||
/**
|
||||
* Class ExternalProfilePolicy.
|
||||
*/
|
||||
class ExternalProfilePolicy extends BasePolicy
|
||||
{
|
||||
/**
|
||||
* Determine whether the user can view any models.
|
||||
*
|
||||
* @param User|null $user
|
||||
* @param array|null $injected
|
||||
* @return bool
|
||||
*/
|
||||
public function viewAny(?User $user, ?array $injected = null): bool
|
||||
{
|
||||
return $user === null || $user->can(CrudPermission::VIEW->format(ExternalProfile::class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can view the model.
|
||||
*
|
||||
* @param User|null $user
|
||||
* @param array|null $injected
|
||||
* @return bool
|
||||
*/
|
||||
public function view(?User $user, ?array $injected = null): bool
|
||||
{
|
||||
/** @var ExternalProfile $profile */
|
||||
$profile = Arr::get($injected, 'id');
|
||||
|
||||
return $user !== null
|
||||
? ($profile->user()->is($user) || ExternalProfileVisibility::PRIVATE !== $profile->visibility) && $user->can(CrudPermission::VIEW->format(ExternalProfile::class))
|
||||
: ExternalProfileVisibility::PRIVATE !== $profile->visibility;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can create models.
|
||||
*
|
||||
* @param User $user
|
||||
* @param array|null $injected
|
||||
* @return bool
|
||||
*/
|
||||
public function create(User $user, ?array $injected = null): bool
|
||||
{
|
||||
return $user->can(CrudPermission::CREATE->format(ExternalProfile::class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can update the model.
|
||||
*
|
||||
* @param User $user
|
||||
* @param array $injected
|
||||
* @return bool
|
||||
*/
|
||||
public function update(User $user, array $injected): bool
|
||||
{
|
||||
/** @var ExternalProfile $profile */
|
||||
$profile = Arr::get($injected, 'id');
|
||||
|
||||
return !$profile->trashed() && $profile->user()->is($user) && $user->can(CrudPermission::UPDATE->format(ExternalProfile::class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can delete the model.
|
||||
*
|
||||
* @param User $user
|
||||
* @param array $injected
|
||||
* @return bool
|
||||
*/
|
||||
public function delete(User $user, array $injected): bool
|
||||
{
|
||||
/** @var ExternalProfile $profile */
|
||||
$profile = Arr::get($injected, 'id');
|
||||
|
||||
return !$profile->trashed() && $profile->user()->is($user) && $user->can(CrudPermission::DELETE->format(ExternalProfile::class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can restore the model.
|
||||
*
|
||||
* @param User $user
|
||||
* @param array $injected
|
||||
* @return bool
|
||||
*/
|
||||
public function restore(User $user, array $injected): bool
|
||||
{
|
||||
/** @var ExternalProfile $profile */
|
||||
$profile = Arr::get($injected, 'id');
|
||||
|
||||
return $profile->trashed() && $profile->user()->is($user) && $user->can(ExtendedCrudPermission::RESTORE->format(ExternalProfile::class));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\GraphQL\Policies\List\Playlist;
|
||||
|
||||
use App\Enums\Auth\CrudPermission;
|
||||
use App\Enums\Auth\ExtendedCrudPermission;
|
||||
use App\Enums\Models\List\PlaylistVisibility;
|
||||
use App\GraphQL\Mutations\List\Playlist\PlaylistTrackMutator;
|
||||
use App\GraphQL\Policies\BasePolicy;
|
||||
use App\Models\Auth\User;
|
||||
use App\Models\List\Playlist;
|
||||
use App\Models\List\Playlist\PlaylistTrack;
|
||||
use Illuminate\Support\Arr;
|
||||
|
||||
/**
|
||||
* Class PlaylistTrackPolicy.
|
||||
*/
|
||||
class PlaylistTrackPolicy extends BasePolicy
|
||||
{
|
||||
/**
|
||||
* Determine whether the user can view any models.
|
||||
*
|
||||
* @param User|null $user
|
||||
* @param array|null $injected
|
||||
* @return bool
|
||||
*/
|
||||
public function viewAny(?User $user, ?array $injected = null): bool
|
||||
{
|
||||
/** @var Playlist|null $playlist */
|
||||
$playlist = Arr::get($injected, 'playlist');
|
||||
|
||||
return $user !== null
|
||||
? ($playlist?->user()->is($user) || PlaylistVisibility::PRIVATE !== $playlist?->visibility) && $user->can(CrudPermission::VIEW->format(PlaylistTrack::class))
|
||||
: PlaylistVisibility::PRIVATE !== $playlist?->visibility;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can view the model.
|
||||
*
|
||||
* @param User|null $user
|
||||
* @param array|null $injected
|
||||
* @return bool
|
||||
*
|
||||
* @noinspection PhpUnusedParameterInspection
|
||||
*/
|
||||
public function view(?User $user, ?array $injected = null): bool
|
||||
{
|
||||
/** @var Playlist|null $playlist */
|
||||
$playlist = Arr::get($injected, 'playlist');
|
||||
|
||||
return $user !== null
|
||||
? ($playlist?->user()->is($user) || PlaylistVisibility::PRIVATE !== $playlist?->visibility) && $user->can(CrudPermission::VIEW->format(PlaylistTrack::class))
|
||||
: PlaylistVisibility::PRIVATE !== $playlist?->visibility;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can create models.
|
||||
*
|
||||
* @param User $user
|
||||
* @param array|null $injected
|
||||
* @return bool
|
||||
*/
|
||||
public function create(User $user, ?array $injected = null): bool
|
||||
{
|
||||
/** @var Playlist|null $playlist */
|
||||
$playlist = Arr::get($injected, 'playlist');
|
||||
|
||||
return $playlist?->user()->is($user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can update the model.
|
||||
*
|
||||
* @param User $user
|
||||
* @param array $injected
|
||||
* @return bool
|
||||
*/
|
||||
public function update(User $user, array $injected): bool
|
||||
{
|
||||
/** @var Playlist|null $playlist */
|
||||
$playlist = Arr::get($injected, 'playlist');
|
||||
/** @var PlaylistTrack $track */
|
||||
$track = Arr::get($injected, PlaylistTrackMutator::ROUTE_SLUG);
|
||||
|
||||
return !$track->trashed() && $playlist?->user()->is($user) && $user->can(CrudPermission::UPDATE->format(PlaylistTrack::class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can delete the model.
|
||||
*
|
||||
* @param User $user
|
||||
* @param array $injected
|
||||
* @return bool
|
||||
*/
|
||||
public function delete(User $user, array $injected): bool
|
||||
{
|
||||
/** @var Playlist|null $playlist */
|
||||
$playlist = Arr::get($injected, 'playlist');
|
||||
/** @var PlaylistTrack $track */
|
||||
$track = Arr::get($injected, PlaylistTrackMutator::ROUTE_SLUG);
|
||||
|
||||
return !$track->trashed() && $playlist?->user()->is($user) && $user->can(CrudPermission::DELETE->format(PlaylistTrack::class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can restore the model.
|
||||
*
|
||||
* @param User $user
|
||||
* @param array $injected
|
||||
* @return bool
|
||||
*/
|
||||
public function restore(User $user, array $injected): bool
|
||||
{
|
||||
/** @var Playlist|null $playlist */
|
||||
$playlist = Arr::get($injected, 'playlist');
|
||||
/** @var PlaylistTrack $track */
|
||||
$track = Arr::get($injected, PlaylistTrackMutator::ROUTE_SLUG);
|
||||
|
||||
return $track->trashed() && $playlist?->user()->is($user) && $user->can(ExtendedCrudPermission::RESTORE->format(PlaylistTrack::class));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\GraphQL\Policies\List;
|
||||
|
||||
use App\Enums\Auth\CrudPermission;
|
||||
use App\Enums\Auth\ExtendedCrudPermission;
|
||||
use App\Enums\Models\List\PlaylistVisibility;
|
||||
use App\GraphQL\Mutations\List\PlaylistMutator;
|
||||
use App\GraphQL\Policies\BasePolicy;
|
||||
use App\Models\Auth\User;
|
||||
use App\Models\List\Playlist;
|
||||
use Illuminate\Support\Arr;
|
||||
|
||||
/**
|
||||
* Class PlaylistPolicy.
|
||||
*/
|
||||
class PlaylistPolicy extends BasePolicy
|
||||
{
|
||||
/**
|
||||
* Determine whether the user can view any models.
|
||||
*
|
||||
* @param User|null $user
|
||||
* @param array|null $injected
|
||||
* @return bool
|
||||
*/
|
||||
public function viewAny(?User $user, ?array $injected = null): bool
|
||||
{
|
||||
return $user === null || $user->can(CrudPermission::VIEW->format(Playlist::class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can view the model.
|
||||
*
|
||||
* @param User|null $user
|
||||
* @param array|null $injected
|
||||
* @return bool
|
||||
*/
|
||||
public function view(?User $user, ?array $injected = null): bool
|
||||
{
|
||||
/** @var Playlist $playlist */
|
||||
$playlist = Arr::get($injected, PlaylistMutator::ROUTE_SLUG);
|
||||
|
||||
return $user !== null
|
||||
? ($playlist->user()->is($user) || PlaylistVisibility::PRIVATE !== $playlist->visibility) && $user->can(CrudPermission::VIEW->format(Playlist::class))
|
||||
: PlaylistVisibility::PRIVATE !== $playlist->visibility;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can create models.
|
||||
*
|
||||
* @param User $user
|
||||
* @param array|null $injected
|
||||
* @return bool
|
||||
*/
|
||||
public function create(User $user, ?array $injected = null): bool
|
||||
{
|
||||
return $user->can(CrudPermission::CREATE->format(Playlist::class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can update the model.
|
||||
*
|
||||
* @param User $user
|
||||
* @param array $injected
|
||||
* @return bool
|
||||
*/
|
||||
public function update(User $user, array $injected): bool
|
||||
{
|
||||
/** @var Playlist $playlist */
|
||||
$playlist = Arr::get($injected, PlaylistMutator::ROUTE_SLUG);
|
||||
|
||||
return !$playlist->trashed() && $playlist->user()->is($user) && $user->can(CrudPermission::UPDATE->format(Playlist::class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can delete the model.
|
||||
*
|
||||
* @param User $user
|
||||
* @param array $injected
|
||||
* @return bool
|
||||
*/
|
||||
public function delete(User $user, array $injected): bool
|
||||
{
|
||||
/** @var Playlist $playlist */
|
||||
$playlist = Arr::get($injected, PlaylistMutator::ROUTE_SLUG);
|
||||
|
||||
return !$playlist->trashed() && $playlist->user()->is($user) && $user->can(CrudPermission::DELETE->format(Playlist::class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can restore the model.
|
||||
*
|
||||
* @param User $user
|
||||
* @param array $injected
|
||||
* @return bool
|
||||
*/
|
||||
public function restore(User $user, array $injected): bool
|
||||
{
|
||||
/** @var Playlist $playlist */
|
||||
$playlist = Arr::get($injected, PlaylistMutator::ROUTE_SLUG);
|
||||
|
||||
return $playlist->trashed() && $playlist->user()->is($user) && $user->can(ExtendedCrudPermission::RESTORE->format(Playlist::class));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\GraphQL\Policies\Wiki\Anime;
|
||||
|
||||
use App\GraphQL\Policies\BasePolicy;
|
||||
|
||||
/**
|
||||
* Class AnimeSynonymPolicy.
|
||||
*/
|
||||
class AnimeSynonymPolicy extends BasePolicy
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\GraphQL\Policies\Wiki\Anime;
|
||||
|
||||
use App\GraphQL\Policies\BasePolicy;
|
||||
|
||||
/**
|
||||
* Class AnimeThemePolicy.
|
||||
*/
|
||||
class AnimeThemePolicy extends BasePolicy
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\GraphQL\Policies\Wiki\Anime\Theme;
|
||||
|
||||
use App\GraphQL\Policies\BasePolicy;
|
||||
|
||||
/**
|
||||
* Class AnimeThemeEntryPolicy.
|
||||
*/
|
||||
class AnimeThemeEntryPolicy extends BasePolicy
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\GraphQL\Policies\Wiki;
|
||||
|
||||
use App\GraphQL\Policies\BasePolicy;
|
||||
|
||||
/**
|
||||
* Class AnimePolicy.
|
||||
*/
|
||||
class AnimePolicy extends BasePolicy
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\GraphQL\Policies\Wiki;
|
||||
|
||||
use App\GraphQL\Policies\BasePolicy;
|
||||
|
||||
/**
|
||||
* Class ArtistPolicy.
|
||||
*/
|
||||
class ArtistPolicy extends BasePolicy
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\GraphQL\Policies\Wiki;
|
||||
|
||||
use App\GraphQL\Policies\BasePolicy;
|
||||
|
||||
/**
|
||||
* Class AudioPolicy.
|
||||
*/
|
||||
class AudioPolicy extends BasePolicy
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\GraphQL\Policies\Wiki;
|
||||
|
||||
use App\GraphQL\Policies\BasePolicy;
|
||||
|
||||
/**
|
||||
* Class ExternalResourcePolicy.
|
||||
*/
|
||||
class ExternalResourcePolicy extends BasePolicy
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\GraphQL\Policies\Wiki;
|
||||
|
||||
use App\GraphQL\Policies\BasePolicy;
|
||||
|
||||
/**
|
||||
* Class GroupPolicy.
|
||||
*/
|
||||
class GroupPolicy extends BasePolicy
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\GraphQL\Policies\Wiki;
|
||||
|
||||
use App\GraphQL\Policies\BasePolicy;
|
||||
|
||||
/**
|
||||
* Class ImagePolicy.
|
||||
*/
|
||||
class ImagePolicy extends BasePolicy
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\GraphQL\Policies\Wiki;
|
||||
|
||||
use App\GraphQL\Policies\BasePolicy;
|
||||
|
||||
/**
|
||||
* Class SeriesPolicy.
|
||||
*/
|
||||
class SeriesPolicy extends BasePolicy
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\GraphQL\Policies\Wiki\Song;
|
||||
|
||||
use App\GraphQL\Policies\BasePolicy;
|
||||
|
||||
/**
|
||||
* Class MembershipPolicy.
|
||||
*/
|
||||
class MembershipPolicy extends BasePolicy
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\GraphQL\Policies\Wiki\Song;
|
||||
|
||||
use App\GraphQL\Policies\BasePolicy;
|
||||
|
||||
/**
|
||||
* Class PerformancePolicy.
|
||||
*/
|
||||
class PerformancePolicy extends BasePolicy
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\GraphQL\Policies\Wiki;
|
||||
|
||||
use App\GraphQL\Policies\BasePolicy;
|
||||
|
||||
/**
|
||||
* Class SongPolicy.
|
||||
*/
|
||||
class SongPolicy extends BasePolicy
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\GraphQL\Policies\Wiki;
|
||||
|
||||
use App\GraphQL\Policies\BasePolicy;
|
||||
|
||||
/**
|
||||
* Class StudioPolicy.
|
||||
*/
|
||||
class StudioPolicy extends BasePolicy
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\GraphQL\Policies\Wiki;
|
||||
|
||||
use App\GraphQL\Policies\BasePolicy;
|
||||
|
||||
/**
|
||||
* Class VideoScriptPolicy.
|
||||
*/
|
||||
class VideoScriptPolicy extends BasePolicy
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\GraphQL\Policies\Wiki;
|
||||
|
||||
use App\GraphQL\Policies\BasePolicy;
|
||||
|
||||
/**
|
||||
* Class VideoPolicy.
|
||||
*/
|
||||
class VideoPolicy extends BasePolicy
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\GraphQL\Queries;
|
||||
|
||||
use App\Models\Wiki\Anime;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Str;
|
||||
use Nuwave\Lighthouse\Execution\ResolveInfo;
|
||||
use Nuwave\Lighthouse\Support\Contracts\GraphQLContext;
|
||||
|
||||
/**
|
||||
* Class AnimeYear.
|
||||
*/
|
||||
class AnimeYear
|
||||
{
|
||||
/**
|
||||
* Return a value for the field.
|
||||
*
|
||||
* @param null $root Always null, since this field has no parent.
|
||||
* @param array $args The field arguments passed by the client.
|
||||
* @param GraphQLContext $context Shared between all fields.
|
||||
* @param ResolveInfo $resolveInfo Metadata for advanced query resolution.
|
||||
* @return mixed The result of resolving the field, matching what was promised in the schema.
|
||||
*/
|
||||
public function years(null $root, array $args, GraphQLContext $context, ResolveInfo $resolveInfo): mixed
|
||||
{
|
||||
return Anime::query()
|
||||
->distinct(Anime::ATTRIBUTE_YEAR)
|
||||
->orderBy(Anime::ATTRIBUTE_YEAR)
|
||||
->pluck(Anime::ATTRIBUTE_YEAR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a value for the field.
|
||||
*
|
||||
* @param null $root Always null, since this field has no parent.
|
||||
* @param array $args The field arguments passed by the client.
|
||||
* @param GraphQLContext $context Shared between all fields.
|
||||
* @param ResolveInfo $resolveInfo Metadata for advanced query resolution.
|
||||
* @return mixed The result of resolving the field, matching what was promised in the schema.
|
||||
*/
|
||||
public function year(null $root, array $args, GraphQLContext $context, ResolveInfo $resolveInfo): mixed
|
||||
{
|
||||
$year = Arr::get($args, 'year');
|
||||
|
||||
return Anime::query()
|
||||
->where(Anime::ATTRIBUTE_YEAR, $year)
|
||||
->orderBy(Anime::ATTRIBUTE_NAME)
|
||||
->get()
|
||||
->groupBy(fn (Anime $anime) => Str::lower($anime->season->localize()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\GraphQL\Queries;
|
||||
|
||||
use App\Models\List\Playlist;
|
||||
use App\Models\Wiki\Anime;
|
||||
use App\Models\Wiki\Anime\AnimeTheme;
|
||||
use App\Models\Wiki\Artist;
|
||||
use App\Models\Wiki\Series;
|
||||
use App\Models\Wiki\Song;
|
||||
use App\Models\Wiki\Studio;
|
||||
use App\Models\Wiki\Video;
|
||||
use Illuminate\Support\Arr;
|
||||
use Nuwave\Lighthouse\Execution\ResolveInfo;
|
||||
use Nuwave\Lighthouse\Support\Contracts\GraphQLContext;
|
||||
|
||||
/**
|
||||
* Class Search.
|
||||
*/
|
||||
class Search
|
||||
{
|
||||
/**
|
||||
* Return a value for the field.
|
||||
*
|
||||
* @param null $root Always null, since this field has no parent.
|
||||
* @param array $args The field arguments passed by the client.
|
||||
* @param GraphQLContext $context Shared between all fields.
|
||||
* @param ResolveInfo $resolveInfo Metadata for advanced query resolution.
|
||||
* @return mixed The result of resolving the field, matching what was promised in the schema.
|
||||
*/
|
||||
public function __invoke(null $root, array $args, GraphQLContext $context, ResolveInfo $resolveInfo): mixed
|
||||
{
|
||||
$result = [];
|
||||
$fields = $resolveInfo->getFieldSelection();
|
||||
|
||||
$term = Arr::get($args, 'search');
|
||||
$page = Arr::get($args, 'page');
|
||||
$perPage = Arr::get($args, 'perPage');
|
||||
|
||||
if (Arr::get($fields, 'anime')) {
|
||||
$result['anime'] = Anime::search($term)->paginate($perPage, $page)->items();
|
||||
}
|
||||
|
||||
if (Arr::get($fields, 'artists')) {
|
||||
$result['artists'] = Artist::search($term)->paginate($perPage, $page)->items();
|
||||
}
|
||||
|
||||
if (Arr::get($fields, 'animethemes')) {
|
||||
$result['animethemes'] = AnimeTheme::search($term)->paginate($perPage, $page)->items();
|
||||
}
|
||||
|
||||
if (Arr::get($fields, 'playlists')) {
|
||||
$result['playlists'] = Playlist::search($term)->paginate($perPage, $page)->items();
|
||||
}
|
||||
|
||||
if (Arr::get($fields, 'series')) {
|
||||
$result['series'] = Series::search($term)->paginate($perPage, $page)->items();
|
||||
}
|
||||
|
||||
if (Arr::get($fields, 'songs')) {
|
||||
$result['songs'] = Song::search($term)->paginate($perPage, $page)->items();
|
||||
}
|
||||
|
||||
if (Arr::get($fields, 'studios')) {
|
||||
$result['studios'] = Studio::search($term)->paginate($perPage, $page)->items();
|
||||
}
|
||||
|
||||
if (Arr::get($fields, 'videos')) {
|
||||
$result['videos'] = Video::search($term)->paginate($perPage, $page)->items();
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\GraphQL\Resolvers;
|
||||
|
||||
use GraphQL\Type\Definition\ResolveInfo;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Str;
|
||||
use Nuwave\Lighthouse\Support\Contracts\GraphQLContext;
|
||||
|
||||
/**
|
||||
* Class ExistsResolver.
|
||||
*/
|
||||
class ExistsResolver
|
||||
{
|
||||
/**
|
||||
* Resolve the relation exists field.
|
||||
*
|
||||
* @param Model $model
|
||||
* @param array $args
|
||||
* @param GraphQLContext $context
|
||||
* @param ResolveInfo $resolveInfo
|
||||
* @return mixed
|
||||
*/
|
||||
public function resolve(Model $model, array $args, GraphQLContext $context, ResolveInfo $resolveInfo): mixed
|
||||
{
|
||||
// Field expected to be {relation}Exists
|
||||
$relation = Str::remove('Exists', $resolveInfo->fieldName);
|
||||
|
||||
return $model->{$relation}->isNotEmpty();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\GraphQL\Resolvers;
|
||||
|
||||
use GraphQL\Type\Definition\ResolveInfo;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Nuwave\Lighthouse\Support\Contracts\GraphQLContext;
|
||||
|
||||
/**
|
||||
* Class ImplodeArrayResolver.
|
||||
*/
|
||||
class ImplodeArrayResolver
|
||||
{
|
||||
/**
|
||||
* Resolve the relation count field.
|
||||
*
|
||||
* @param Model $model
|
||||
* @param array $args
|
||||
* @param GraphQLContext $context
|
||||
* @param ResolveInfo $resolveInfo
|
||||
* @return mixed
|
||||
*/
|
||||
public function resolve(Model $model, array $args, GraphQLContext $context, ResolveInfo $resolveInfo): mixed
|
||||
{
|
||||
return implode('', $model->getAttribute($resolveInfo->fieldName));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\GraphQL\Resolvers;
|
||||
|
||||
use GraphQL\Type\Definition\ResolveInfo;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Str;
|
||||
use Nuwave\Lighthouse\Support\Contracts\GraphQLContext;
|
||||
|
||||
/**
|
||||
* Class PivotResolver.
|
||||
*/
|
||||
class PivotResolver
|
||||
{
|
||||
/**
|
||||
* Resolve the pivot field.
|
||||
*
|
||||
* @param array $root
|
||||
* @param array $args
|
||||
* @param GraphQLContext $context
|
||||
* @param ResolveInfo $resolveInfo
|
||||
* @return mixed
|
||||
*/
|
||||
public function resolve(array $root, array $args, GraphQLContext $context, ResolveInfo $resolveInfo): mixed
|
||||
{
|
||||
/** @var Model $model */
|
||||
$model = Arr::get($root, 'node');
|
||||
|
||||
$pivot = current($model->getRelations());
|
||||
|
||||
return $pivot->{Str::snake($resolveInfo->fieldName)};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\GraphQL\Resolvers;
|
||||
|
||||
use App\Contracts\Models\HasAggregateViews;
|
||||
use App\Models\Service\ViewAggregate;
|
||||
use GraphQL\Type\Definition\ResolveInfo;
|
||||
use Nuwave\Lighthouse\Support\Contracts\GraphQLContext;
|
||||
|
||||
/**
|
||||
* Class ViewsCountResolver.
|
||||
*/
|
||||
class ViewsCountResolver
|
||||
{
|
||||
/**
|
||||
* Resolve views count field.
|
||||
*
|
||||
* @param HasAggregateViews $viewable
|
||||
* @param array $args
|
||||
* @param GraphQLContext $context
|
||||
* @param ResolveInfo $resolveInfo
|
||||
* @return mixed
|
||||
*/
|
||||
public function resolve(HasAggregateViews $viewable, array $args, GraphQLContext $context, ResolveInfo $resolveInfo): mixed
|
||||
{
|
||||
/** @var ViewAggregate|null $view */
|
||||
/** @phpstan-ignore-next-line */
|
||||
$view = $viewable->viewAggregate;
|
||||
|
||||
return (int) $view?->value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
"Represents a site-wide message to be broadcasted on the homepage."
|
||||
type Announcement {
|
||||
"The primary key of the resource"
|
||||
id: Int! @rename(attribute: "announcement_id")
|
||||
"The announcement text"
|
||||
content: String!
|
||||
"The date that the resource was created"
|
||||
createdAt: DateTimeTz @rename(attribute: "created_at")
|
||||
"The date that the resource was last modified"
|
||||
updatedAt: DateTimeTz @rename(attribute: "updated_at")
|
||||
"The date that the resource was deleted"
|
||||
deletedAt: DateTimeTz @rename(attribute: "deleted_at")
|
||||
}
|
||||
|
||||
enum AnnouncementColumnsOrderable {
|
||||
ID @enum(value: "announcement_id")
|
||||
CONTENT
|
||||
CREATED_AT
|
||||
UPDATED_AT
|
||||
DELETED_AT
|
||||
}
|
||||
|
||||
extend type Query {
|
||||
"Returns a listing of announcement resources."
|
||||
announcements(
|
||||
createdAt_lesser: DateTimeTz @where(key: "created_at", operator: "<")
|
||||
createdAt_greater: DateTimeTz @where(key: "created_at", operator: ">")
|
||||
updatedAt_lesser: DateTimeTz @where(key: "updated_at", operator: "<")
|
||||
updatedAt_greater: DateTimeTz @where(key: "updated_at", operator: ">")
|
||||
deletedAt_lesser: DateTimeTz @where(key: "deleted_at", operator: "<")
|
||||
deletedAt_greater: DateTimeTz @where(key: "deleted_at", operator: ">")
|
||||
orderBy: _ @orderBy(columnsEnum: "AnnouncementColumnsOrderable")
|
||||
): [Announcement!]!
|
||||
@canModel(ability: "viewAny", injectArgs: true)
|
||||
@softDeletes
|
||||
@paginate
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
"""
|
||||
Represents a database dump of selected tables at a given point in time.
|
||||
|
||||
For example, the animethemes-db-dump-wiki-1663559663946.sql dump represents the database dump of wiki tables performed at 2022-09-19.
|
||||
"""
|
||||
type Dump {
|
||||
"The primary key of the resource"
|
||||
id: Int! @rename(attribute: "dump_id")
|
||||
"The path of the file in storage"
|
||||
path: String!
|
||||
"The URL to download the file from storage"
|
||||
link: String!
|
||||
"The date that the resource was created"
|
||||
createdAt: DateTimeTz @rename(attribute: "created_at")
|
||||
"The date that the resource was last modified"
|
||||
updatedAt: DateTimeTz @rename(attribute: "updated_at")
|
||||
"The date that the resource was deleted"
|
||||
deletedAt: DateTimeTz @rename(attribute: "deleted_at")
|
||||
}
|
||||
|
||||
enum DumpColumnsOrderable {
|
||||
ID @enum(value: "dump_id")
|
||||
PATH
|
||||
LINK
|
||||
CREATED_AT
|
||||
UPDATED_AT
|
||||
DELETED_AT
|
||||
}
|
||||
|
||||
extend type Query {
|
||||
"Returns a listing of dump resources given fields."
|
||||
dumps(
|
||||
createdAt_lesser: DateTimeTz @where(key: "created_at", operator: "<")
|
||||
createdAt_greater: DateTimeTz @where(key: "created_at", operator: ">")
|
||||
updatedAt_lesser: DateTimeTz @where(key: "updated_at", operator: "<")
|
||||
updatedAt_greater: DateTimeTz @where(key: "updated_at", operator: ">")
|
||||
deletedAt_lesser: DateTimeTz @where(key: "deleted_at", operator: "<")
|
||||
deletedAt_greater: DateTimeTz @where(key: "deleted_at", operator: ">")
|
||||
orderBy: _ @orderBy(columnsEnum: "DumpColumnsOrderable")
|
||||
): [Dump!]!
|
||||
@canModel(ability: "viewAny", injectArgs: true)
|
||||
@softDeletes
|
||||
@paginate
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
"""
|
||||
Represents a feature flag that enable/disable site functionalities.
|
||||
|
||||
For example, the 'allow_discord_notifications' feature enables/disables discord notifications for the configured bot.
|
||||
"""
|
||||
type Feature {
|
||||
"The primary key of the resource"
|
||||
id: Int! @rename(attribute: "feature_id")
|
||||
"The title of the resource"
|
||||
name: String!
|
||||
"The value of the resource"
|
||||
value: String!
|
||||
"The date that the resource was created"
|
||||
createdAt: DateTimeTz @rename(attribute: "created_at")
|
||||
"The date that the resource was last modified"
|
||||
updatedAt: DateTimeTz @rename(attribute: "updated_at")
|
||||
}
|
||||
|
||||
enum FeatureColumnsOrderable {
|
||||
ID @enum(value: "feature_id")
|
||||
NAME
|
||||
VALUE
|
||||
CREATED_AT
|
||||
UPDATED_AT
|
||||
}
|
||||
|
||||
extend type Query {
|
||||
"Returns a listing of feature resources given fields."
|
||||
features(
|
||||
createdAt_lesser: DateTimeTz @where(key: "created_at", operator: "<")
|
||||
createdAt_greater: DateTimeTz @where(key: "created_at", operator: ">")
|
||||
updatedAt_lesser: DateTimeTz @where(key: "updated_at", operator: "<")
|
||||
updatedAt_greater: DateTimeTz @where(key: "updated_at", operator: ">")
|
||||
orderBy: _ @orderBy(columnsEnum: "FeatureColumnsOrderable")
|
||||
): [Feature!]!
|
||||
@canModel(ability: "viewAny", injectArgs: true)
|
||||
@builder(method: "App\\GraphQL\\Builders\\Admin\\FeatureBuilder@index")
|
||||
@paginate
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
"Represents a video to be featured on the homepage of the site for a specified amount of time."
|
||||
type FeaturedTheme {
|
||||
"The primary key of the resource"
|
||||
id: Int! @rename(attribute: "featured_theme_id")
|
||||
"The start date of the resource"
|
||||
startAt: DateTimeTz! @rename(attribute: "start_at")
|
||||
"The end date of the resource"
|
||||
endAt: DateTimeTz! @rename(attribute: "end_at")
|
||||
animethemeentry: AnimeThemeEntry @belongsTo
|
||||
user: User @belongsTo
|
||||
video: Video @belongsTo
|
||||
"The date that the resource was created"
|
||||
createdAt: DateTimeTz @rename(attribute: "created_at")
|
||||
"The date that the resource was last modified"
|
||||
updatedAt: DateTimeTz @rename(attribute: "updated_at")
|
||||
"The date that the resource was deleted"
|
||||
deletedAt: DateTimeTz @rename(attribute: "deleted_at")
|
||||
}
|
||||
|
||||
enum FeaturedThemeColumnsOrderable {
|
||||
ID @enum(value: "featured_theme_id")
|
||||
START_AT
|
||||
END_AT
|
||||
CREATED_AT
|
||||
UPDATED_AT
|
||||
DELETED_AT
|
||||
}
|
||||
|
||||
extend type Query {
|
||||
"Returns the first featured theme where the current date is between start_at and end_at dates."
|
||||
currentfeaturedtheme: FeaturedTheme @find
|
||||
@canModel(ability: "viewAny", injectArgs: true)
|
||||
@builder(method: "App\\GraphQL\\Builders\\Admin\\FeaturedThemeBuilder@current")
|
||||
|
||||
"Returns a listing of featured theme resources given fields."
|
||||
featuredthemes(
|
||||
startAt_lesser: DateTimeTz @where(key: "start_at", operator: "<")
|
||||
startAt_greater: DateTimeTz @where(key: "start_at", operator: ">")
|
||||
endAt_lesser: DateTimeTz @where(key: "end_at", operator: "<")
|
||||
endAt_greater: DateTimeTz @where(key: "end_at", operator: ">")
|
||||
createdAt_lesser: DateTimeTz @where(key: "created_at", operator: "<")
|
||||
createdAt_greater: DateTimeTz @where(key: "created_at", operator: ">")
|
||||
updatedAt_lesser: DateTimeTz @where(key: "updated_at", operator: "<")
|
||||
updatedAt_greater: DateTimeTz @where(key: "updated_at", operator: ">")
|
||||
deletedAt_lesser: DateTimeTz @where(key: "deleted_at", operator: "<")
|
||||
deletedAt_greater: DateTimeTz @where(key: "deleted_at", operator: ">")
|
||||
orderBy: _ @orderBy(columnsEnum: "FeaturedThemeColumnsOrderable")
|
||||
): [FeaturedTheme!]!
|
||||
@canModel(ability: "viewAny", injectArgs: true)
|
||||
@builder(method: "App\\GraphQL\\Builders\\Admin\\FeaturedThemeBuilder@index")
|
||||
@softDeletes
|
||||
@paginate
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
"""
|
||||
Represents an assignable label for users and roles that authorizes a particular action in AnimeThemes.
|
||||
"""
|
||||
type Permission {
|
||||
"The primary key of the resource"
|
||||
id: Int!
|
||||
"The label of the resource"
|
||||
name: String!
|
||||
"The authentication guard of the resource"
|
||||
guardName: String! @rename(attribute: "guard_name")
|
||||
"The date that the resource was created"
|
||||
createdAt: DateTimeTz @rename(attribute: "created_at")
|
||||
"The date that the resource was last modified"
|
||||
updatedAt: DateTimeTz @rename(attribute: "updated_at")
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
"""
|
||||
Represents an assignable label for users that provides a configured group of permissions.
|
||||
"""
|
||||
type Role {
|
||||
"The primary key of the resource"
|
||||
id: Int! @rename(attribute: "role_id")
|
||||
"The hex representation of the color used to distinguish the resource"
|
||||
color: String!
|
||||
"The label of the resource"
|
||||
name: String!
|
||||
"Is the role assigned on account verification?"
|
||||
default: Boolean!
|
||||
"The authentication guard of the resource"
|
||||
guardName: String! @rename(attribute: "guard_name")
|
||||
"The weight assigned to the resource, where higher values correspond to higher priority"
|
||||
priority: Int!
|
||||
permissions: [Permission] @belongsToMany(type: CONNECTION, edgeType: RolePermissionEdge)
|
||||
"The date that the resource was created"
|
||||
createdAt: DateTimeTz @rename(attribute: "created_at")
|
||||
"The date that the resource was last modified"
|
||||
updatedAt: DateTimeTz @rename(attribute: "updated_at")
|
||||
}
|
||||
|
||||
type RolePermissionEdge {
|
||||
node: Permission!
|
||||
"The date that the resource was last modified"
|
||||
createdAt: DateTimeTz @field(resolver: "App\\GraphQL\\Resolvers\\PivotResolver@resolve")
|
||||
"The date that the resource was deleted"
|
||||
updatedAt: DateTimeTz @field(resolver: "App\\GraphQL\\Resolvers\\PivotResolver@resolve")
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
"Represents an AnimeThemes account."
|
||||
type User {
|
||||
"The username of the resource"
|
||||
name: String!
|
||||
playlists: [Playlist] @hasMany
|
||||
"The date that the resource was created"
|
||||
createdAt: DateTimeTz @rename(attribute: "created_at")
|
||||
"The date that the resource was last modified"
|
||||
updatedAt: DateTimeTz @rename(attribute: "updated_at")
|
||||
"The date that the resource was deleted"
|
||||
deletedAt: DateTimeTz @rename(attribute: "deleted_at")
|
||||
}
|
||||
|
||||
"Represents the currently authenticated user."
|
||||
type Me {
|
||||
"The primary key of the resource"
|
||||
id: Int
|
||||
"The username of the resource"
|
||||
name: String!
|
||||
"The email of the user"
|
||||
email: String!
|
||||
"The date the user verified their email"
|
||||
email_verified_at: DateTimeTz
|
||||
"The date the user confirmed their two-factor authentication"
|
||||
two_factor_confirmed_at: DateTimeTz
|
||||
notifications: [Notification] @morphMany
|
||||
playlists: [Playlist] @hasMany
|
||||
"The date that the resource was created"
|
||||
createdAt: DateTimeTz @rename(attribute: "created_at")
|
||||
"The date that the resource was last modified"
|
||||
updatedAt: DateTimeTz @rename(attribute: "updated_at")
|
||||
"The date that the resource was deleted"
|
||||
deletedAt: DateTimeTz @rename(attribute: "deleted_at")
|
||||
}
|
||||
|
||||
extend type Query {
|
||||
"Returns the data of the currently authenticated user."
|
||||
me: Me @auth
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
"""
|
||||
Represents a static markdown page used for guides and other documentation.
|
||||
|
||||
For example, the 'encoding/audio_normalization' page represents the documentation for audio normalization.
|
||||
"""
|
||||
type Page {
|
||||
"The primary key of the resource"
|
||||
id: Int! @rename(attribute: "page_id")
|
||||
"The primary title of the page"
|
||||
name: String!
|
||||
"The URL slug & route key of the resource"
|
||||
slug: String!
|
||||
"The body content of the resource"
|
||||
body: String
|
||||
"The date that the resource was created"
|
||||
createdAt: DateTimeTz @rename(attribute: "created_at")
|
||||
"The date that the resource was last modified"
|
||||
updatedAt: DateTimeTz @rename(attribute: "updated_at")
|
||||
"The date that the resource was deleted"
|
||||
deletedAt: DateTimeTz @rename(attribute: "deleted_at")
|
||||
}
|
||||
|
||||
enum PageColumnsOrderable {
|
||||
ID @enum(value: "page_id")
|
||||
NAME
|
||||
SLUG
|
||||
CREATED_AT
|
||||
UPDATED_AT
|
||||
DELETED_AT
|
||||
}
|
||||
|
||||
extend type Query {
|
||||
"Returns a listing of page resources given fields."
|
||||
pages(
|
||||
createdAt_lesser: DateTimeTz @where(key: "created_at", operator: "<")
|
||||
createdAt_greater: DateTimeTz @where(key: "created_at", operator: ">")
|
||||
updatedAt_lesser: DateTimeTz @where(key: "updated_at", operator: "<")
|
||||
updatedAt_greater: DateTimeTz @where(key: "updated_at", operator: ">")
|
||||
deletedAt_lesser: DateTimeTz @where(key: "deleted_at", operator: "<")
|
||||
deletedAt_greater: DateTimeTz @where(key: "deleted_at", operator: ">")
|
||||
orderBy: _ @orderBy(columnsEnum: "PageColumnsOrderable")
|
||||
): [Page!]!
|
||||
@canModel(ability: "viewAny", injectArgs: true)
|
||||
@softDeletes
|
||||
@paginate
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
"""
|
||||
Represents an anime entry on the external profile.
|
||||
|
||||
For example, Hibike Euphonium! is marked as completed on the profile AnimeThemes.
|
||||
"""
|
||||
type ExternalEntry {
|
||||
"The primary key of the resource"
|
||||
id: Int! @rename(attribute: "entry_id")
|
||||
"The score of the entry on the external site"
|
||||
score: Float
|
||||
"The favorite state of the entry on the external site"
|
||||
isFavorite: Boolean! @rename(attribute: "is_favorite")
|
||||
"The watch status of the entry on the external site"
|
||||
watchStatus: ExternalEntryWatchStatus! @rename(attribute: "watch_status") @localizedEnum
|
||||
anime: Anime @belongsTo
|
||||
externalprofile: ExternalProfile @belongsTo
|
||||
"The date that the resource was created"
|
||||
createdAt: DateTimeTz @rename(attribute: "created_at")
|
||||
"The date that the resource was last modified"
|
||||
updatedAt: DateTimeTz @rename(attribute: "updated_at")
|
||||
"The date that the resource was deleted"
|
||||
deletedAt: DateTimeTz @rename(attribute: "deleted_at")
|
||||
}
|
||||
|
||||
enum ExternalEntryColumnsOrderable {
|
||||
ID @enum(value: "entry_id")
|
||||
SCORE
|
||||
IS_FAVORITE
|
||||
WATCH_STATUS
|
||||
CREATED_AT
|
||||
UPDATED_AT
|
||||
DELETED_AT
|
||||
}
|
||||
|
||||
extend type Query {
|
||||
"Returns an external entry resource."
|
||||
externalentry(
|
||||
profile: Int! @bind(class: "App\\Models\\List\\ExternalProfile")
|
||||
id: Int! @bind(class: "App\\Models\\List\\External\\ExternalEntry")
|
||||
): ExternalEntry @first
|
||||
@canModel(ability: "view", injectArgs: true)
|
||||
|
||||
"Returns a listing of entries for the profile."
|
||||
externalentries(
|
||||
score_lesser: Int @where(key: "score", operator: "<")
|
||||
score_greater: Int @where(key: "score", operator: ">")
|
||||
watchStatus: [ExternalEntryWatchStatus] @in(key: "watch_status")
|
||||
createdAt_lesser: DateTimeTz @where(key: "created_at", operator: "<")
|
||||
createdAt_greater: DateTimeTz @where(key: "created_at", operator: ">")
|
||||
updatedAt_lesser: DateTimeTz @where(key: "updated_at", operator: "<")
|
||||
updatedAt_greater: DateTimeTz @where(key: "updated_at", operator: ">")
|
||||
deletedAt_lesser: DateTimeTz @where(key: "deleted_at", operator: "<")
|
||||
deletedAt_greater: DateTimeTz @where(key: "deleted_at", operator: ">")
|
||||
orderBy: _ @orderBy(columnsEnum: "ExternalEntryColumnsOrderable")
|
||||
): [ExternalEntry!]!
|
||||
@canModel(ability: "viewAny", injectArgs: true)
|
||||
@builder(method: "App\\GraphQL\\Builders\\List\\External\\ExternalEntryBuilder@index")
|
||||
@paginate
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
"""
|
||||
Represents an entry in a playlist.
|
||||
|
||||
For example, a "/r/anime's Best OPs and EDs of 2022" playlist may contain a track for the ParipiKoumei-OP1.webm video.
|
||||
"""
|
||||
type PlaylistTrack {
|
||||
"The primary key of the resource"
|
||||
id: String! @rename(attribute: "hashid")
|
||||
animethemeentry: AnimeThemeEntry @belongsTo
|
||||
next: PlaylistTrack @belongsTo
|
||||
playlist: Playlist @belongsTo
|
||||
previous: PlaylistTrack @belongsTo
|
||||
video: Video @belongsTo
|
||||
"The date that the resource was created"
|
||||
createdAt: DateTimeTz @rename(attribute: "created_at")
|
||||
"The date that the resource was last modified"
|
||||
updatedAt: DateTimeTz @rename(attribute: "updated_at")
|
||||
"The date that the resource was deleted"
|
||||
deletedAt: DateTimeTz @rename(attribute: "deleted_at")
|
||||
}
|
||||
|
||||
enum PlaylistTrackColumnsOrderable {
|
||||
ID @enum(value: "track_id")
|
||||
CREATED_AT
|
||||
UPDATED_AT
|
||||
DELETED_AT
|
||||
}
|
||||
|
||||
extend type Query {
|
||||
"Returns a playlist track resource."
|
||||
playlisttrack(
|
||||
playlist: String! @bind(class: "App\\Models\\List\\Playlist", column: "hashid")
|
||||
id: String! @bind(class: "App\\Models\\List\\Playlist\\PlaylistTrack", column: "hashid")
|
||||
): PlaylistTrack @first
|
||||
@canModel(ability: "view", injectArgs: true)
|
||||
|
||||
"Returns a listing of tracks for the playlist."
|
||||
playlisttracks(
|
||||
createdAt_lesser: DateTimeTz @where(key: "created_at", operator: "<")
|
||||
createdAt_greater: DateTimeTz @where(key: "created_at", operator: ">")
|
||||
updatedAt_lesser: DateTimeTz @where(key: "updated_at", operator: "<")
|
||||
updatedAt_greater: DateTimeTz @where(key: "updated_at", operator: ">")
|
||||
deletedAt_lesser: DateTimeTz @where(key: "deleted_at", operator: "<")
|
||||
deletedAt_greater: DateTimeTz @where(key: "deleted_at", operator: ">")
|
||||
orderBy: _ @orderBy(columnsEnum: "PlaylistTrackColumnsOrderable")
|
||||
): [PlaylistTrack!]!
|
||||
@canModel(ability: "viewAny", injectArgs: true)
|
||||
@builder(method: "App\\GraphQL\\Builders\\List\\Playlist\\PlaylistTrackBuilder@index")
|
||||
@paginate
|
||||
}
|
||||
|
||||
extend type Mutation @guard {
|
||||
createPlaylistTrack(
|
||||
entry_id: Int!
|
||||
video_id: Int!
|
||||
next: String
|
||||
previous: String
|
||||
playlist: String! @bind(class: "App\\Models\\List\\Playlist", column: "hashid")
|
||||
): PlaylistTrack!
|
||||
@canModel(ability: "create", injectArgs: true)
|
||||
@validator(class: "App\\GraphQL\\Validators\\Mutation\\List\\Playlist\\CreatePlaylistTrackValidator")
|
||||
@field(resolver: "App\\GraphQL\\Mutations\\List\\Playlist\\PlaylistTrackMutator@store")
|
||||
|
||||
|
||||
updatePlaylistTrack(
|
||||
id: String! @bind(class: "App\\Models\\List\\Playlist\\PlaylistTrack", column: "hashid")
|
||||
entry_id: Int
|
||||
video_id: Int
|
||||
next: String
|
||||
previous: String
|
||||
playlist: String! @bind(class: "App\\Models\\List\\Playlist", column: "hashid")
|
||||
): PlaylistTrack!
|
||||
@canModel(ability: "update", injectArgs: true)
|
||||
@validator(class: "App\\GraphQL\\Validators\\Mutation\\List\\Playlist\\UpdatePlaylistTrackValidator")
|
||||
@field(resolver: "App\\GraphQL\\Mutations\\List\\Playlist\\PlaylistTrackMutator@update")
|
||||
|
||||
|
||||
deletePlaylistTrack(
|
||||
id: String! @bind(class: "App\\Models\\List\\Playlist\\PlaylistTrack", column: "hashid")
|
||||
playlist: String! @bind(class: "App\\Models\\List\\Playlist", column: "hashid")
|
||||
): PlaylistTrack!
|
||||
@canModel(ability: "delete", injectArgs: true)
|
||||
@field(resolver: "App\\GraphQL\\Mutations\\List\\Playlist\\PlaylistTrackMutator@destroy")
|
||||
|
||||
|
||||
restorePlaylistTrack(
|
||||
id: String! @bind(class: "App\\Models\\List\\Playlist\\PlaylistTrack", column: "hashid")
|
||||
playlist: String! @bind(class: "App\\Models\\List\\Playlist", column: "hashid")
|
||||
): PlaylistTrack!
|
||||
@canModel(ability: "restore", injectArgs: true)
|
||||
@field(resolver: "App\\GraphQL\\Mutations\\List\\Playlist\\PlaylistTrackMutator@restore")
|
||||
|
||||
|
||||
forceDeletePlaylistTrack(
|
||||
id: String! @bind(class: "App\\Models\\List\\Playlist\\PlaylistTrack", column: "hashid")
|
||||
playlist: String! @bind(class: "App\\Models\\List\\Playlist", column: "hashid")
|
||||
): MessageResponse!
|
||||
@canModel(ability: "forceDelete", injectArgs: true, model: "App\\Models\\List\\Playlist\\PlaylisTrack")
|
||||
@field(resolver: "App\\GraphQL\\Mutations\\List\\Playlist\\PlaylistTrackMutator@forceDelete")
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
"Represents a user profile on the external site like MAL."
|
||||
type ExternalProfile {
|
||||
"The primary key of the resource"
|
||||
id: Int! @rename(attribute: "profile_id")
|
||||
"The title of the profile"
|
||||
name: String!
|
||||
"The site the profile belongs to"
|
||||
site: ExternalProfileSite! @localizedEnum
|
||||
"The state of who can see the profile"
|
||||
visibility: ExternalProfileVisibility! @localizedEnum
|
||||
externalentries: [ExternalEntry] @hasMany
|
||||
user: User @belongsTo
|
||||
"The date that the resource was created"
|
||||
createdAt: DateTimeTz @rename(attribute: "created_at")
|
||||
"The date that the resource was last modified"
|
||||
updatedAt: DateTimeTz @rename(attribute: "updated_at")
|
||||
"The date that the resource was deleted"
|
||||
deletedAt: DateTimeTz @rename(attribute: "deleted_at")
|
||||
}
|
||||
|
||||
enum ExternalProfileColumnsOrderable {
|
||||
ID @enum(value: "profile_id")
|
||||
NAME
|
||||
SITE
|
||||
VISIBILITY
|
||||
CREATED_AT
|
||||
UPDATED_AT
|
||||
DELETED_AT
|
||||
}
|
||||
|
||||
extend type Query @middleware(class: "App\\Http\\Middleware\\Api\\EnabledOnlyOnLocalhost") {
|
||||
"Returns an external profile resource."
|
||||
externalprofile(
|
||||
id: String! @bind(class: "App\\Models\\List\\ExternalProfile")
|
||||
): ExternalProfile @first
|
||||
@canModel(ability: "view", injectArgs: true)
|
||||
|
||||
"Returns a listing of external profile resources."
|
||||
externalprofiles(
|
||||
name: String @eq
|
||||
site: [ExternalProfileSite] @in
|
||||
visibility: [ExternalProfileVisibility] @in
|
||||
createdAt_lesser: DateTimeTz @where(key: "created_at", operator: "<")
|
||||
createdAt_greater: DateTimeTz @where(key: "created_at", operator: ">")
|
||||
updatedAt_lesser: DateTimeTz @where(key: "updated_at", operator: "<")
|
||||
updatedAt_greater: DateTimeTz @where(key: "updated_at", operator: ">")
|
||||
deletedAt_lesser: DateTimeTz @where(key: "deleted_at", operator: "<")
|
||||
deletedAt_greater: DateTimeTz @where(key: "deleted_at", operator: ">")
|
||||
orderBy: _ @orderBy(columnsEnum: "ExternalProfileColumnsOrderable")
|
||||
): [ExternalProfile!]!
|
||||
@canModel(ability: "viewAny", injectArgs: true)
|
||||
@builder(method: "App\\GraphQL\\Builders\\List\\ExternalProfileBuilder@index")
|
||||
@paginate
|
||||
}
|
||||
|
||||
extend type Mutation @guard @middleware(class: "App\\Http\\Middleware\\Api\\EnabledOnlyOnLocalhost") @feature(name: "App\\Features\\AllowExternalProfileManagement") {
|
||||
syncExternalProfile(
|
||||
id: Int! @bind(class: "App\\Models\\List\\ExternalProfile", column: "profile_id")
|
||||
): MessageResponse!
|
||||
@canModel(ability: "update", injectArgs: true, model: "App\\Models\\List\\ExternalProfile")
|
||||
@field(resolver: "App\\GraphQL\\Mutations\\List\\ExternalProfileMutator@sync")
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
"""
|
||||
Represents a list of ordered tracks intended for continuous playback.
|
||||
|
||||
For example, a "/r/anime's Best OPs and EDs of 2022" playlist may contain a collection of tracks allowing the continuous playback of Best OP and ED nominations for the /r/anime Awards.
|
||||
"""
|
||||
type Playlist {
|
||||
"The primary key of the resource"
|
||||
id: String! @rename(attribute: "hashid")
|
||||
"The title of the playlist"
|
||||
name: String!
|
||||
"The description of the playlist"
|
||||
description: String
|
||||
"The number of tracks belonging to the resource"
|
||||
tracksCount: Int! @count(relation: "tracks")
|
||||
"The existence of tracks belonging to the resource"
|
||||
tracksExists: Boolean! @with(relation: "tracks") @field(resolver: "App\\GraphQL\\Resolvers\\ExistsResolver@resolve")
|
||||
"The state of who can see the playlist"
|
||||
visibility: PlaylistVisibility! @localizedEnum
|
||||
"The number of views recorded for the resource"
|
||||
viewsCount: Int! @with(relation: "viewAggregate") @field(resolver: "App\\GraphQL\\Resolvers\\ViewsCountResolver@resolve")
|
||||
first: PlaylistTrack @belongsTo
|
||||
images: [Image] @belongsToMany(type: CONNECTION, edgeType: PlaylistImageEdge)
|
||||
last: PlaylistTrack @belongsTo
|
||||
tracks: [PlaylistTrack] @hasMany
|
||||
user: User @belongsTo
|
||||
"The date that the resource was created"
|
||||
createdAt: DateTimeTz @rename(attribute: "created_at")
|
||||
"The date that the resource was last modified"
|
||||
updatedAt: DateTimeTz @rename(attribute: "updated_at")
|
||||
"The date that the resource was deleted"
|
||||
deletedAt: DateTimeTz @rename(attribute: "deleted_at")
|
||||
}
|
||||
|
||||
type PlaylistImageEdge {
|
||||
node: Image!
|
||||
"The date that the resource was last modified"
|
||||
createdAt: DateTimeTz @field(resolver: "App\\GraphQL\\Resolvers\\PivotResolver@resolve")
|
||||
"The date that the resource was deleted"
|
||||
updatedAt: DateTimeTz @field(resolver: "App\\GraphQL\\Resolvers\\PivotResolver@resolve")
|
||||
}
|
||||
|
||||
enum PlaylistColumnsOrderable {
|
||||
ID @enum(value: "playlist_id")
|
||||
NAME
|
||||
DESCRIPTION
|
||||
VISIBILITY
|
||||
CREATED_AT
|
||||
UPDATED_AT
|
||||
DELETED_AT
|
||||
}
|
||||
|
||||
extend type Query {
|
||||
"Returns a playlist resource."
|
||||
playlist(
|
||||
id: String! @bind(class: "App\\Models\\List\\Playlist", column: "hashid")
|
||||
): Playlist @first
|
||||
@canModel(ability: "view", injectArgs: true)
|
||||
|
||||
"Returns a listing of playlist resources."
|
||||
playlists(
|
||||
name: String @eq
|
||||
visibility: [PlaylistVisibility] @in
|
||||
createdAt_lesser: DateTimeTz @where(key: "created_at", operator: "<")
|
||||
createdAt_greater: DateTimeTz @where(key: "created_at", operator: ">")
|
||||
updatedAt_lesser: DateTimeTz @where(key: "updated_at", operator: "<")
|
||||
updatedAt_greater: DateTimeTz @where(key: "updated_at", operator: ">")
|
||||
deletedAt_lesser: DateTimeTz @where(key: "deleted_at", operator: "<")
|
||||
deletedAt_greater: DateTimeTz @where(key: "deleted_at", operator: ">")
|
||||
orderBy: _ @orderBy(columnsEnum: "PlaylistColumnsOrderable")
|
||||
): [Playlist!]!
|
||||
@canModel(ability: "viewAny", injectArgs: true)
|
||||
@builder(method: "App\\GraphQL\\Builders\\List\\PlaylistBuilder@index")
|
||||
@paginate
|
||||
}
|
||||
|
||||
extend type Mutation @guard {
|
||||
createPlaylist(
|
||||
name: String!
|
||||
description: String
|
||||
visibility: PlaylistVisibility!
|
||||
): Playlist!
|
||||
@canModel(ability: "create")
|
||||
@validator(class: "App\\GraphQL\\Validators\\Mutation\\List\\CreatePlaylistValidator")
|
||||
@field(resolver: "App\\GraphQL\\Mutations\\List\\PlaylistMutator@store")
|
||||
|
||||
|
||||
updatePlaylist(
|
||||
id: String! @bind(class: "App\\Models\\List\\Playlist", column: "hashid")
|
||||
name: String
|
||||
description: String
|
||||
visibility: PlaylistVisibility
|
||||
): Playlist!
|
||||
@canModel(ability: "update", injectArgs: true)
|
||||
@validator(class: "App\\GraphQL\\Validators\\Mutation\\List\\UpdatePlaylistValidator")
|
||||
@field(resolver: "App\\GraphQL\\Mutations\\List\\PlaylistMutator@update")
|
||||
|
||||
|
||||
deletePlaylist(
|
||||
id: String! @bind(class: "App\\Models\\List\\Playlist", column: "hashid")
|
||||
): Playlist!
|
||||
@canModel(ability: "delete", injectArgs: true)
|
||||
@field(resolver: "App\\GraphQL\\Mutations\\List\\PlaylistMutator@destroy")
|
||||
|
||||
|
||||
restorePlaylist(
|
||||
id: String! @bind(class: "App\\Models\\List\\Playlist", column: "hashid")
|
||||
): Playlist!
|
||||
@canModel(ability: "restore", injectArgs: true)
|
||||
@field(resolver: "App\\GraphQL\\Mutations\\List\\PlaylistMutator@restore")
|
||||
|
||||
|
||||
forceDeletePlaylist(
|
||||
id: String! @bind(class: "App\\Models\\List\\Playlist", column: "hashid")
|
||||
): MessageResponse!
|
||||
@canModel(ability: "forceDelete", injectArgs: true, model: "App\\Models\\List\\Playlist")
|
||||
@field(resolver: "App\\GraphQL\\Mutations\\List\\PlaylistMutator@forceDelete")
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
"Represents the association between a playlist and an image."
|
||||
type PlaylistImage {
|
||||
playlist: Playlist!
|
||||
image: Image!
|
||||
"The date that the resource was created"
|
||||
createdAt: DateTimeTz @rename(attribute: "created_at")
|
||||
"The date that the resource was last modified"
|
||||
updatedAt: DateTimeTz @rename(attribute: "updated_at")
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
"Represents the association between an anime and an image."
|
||||
type AnimeImage {
|
||||
anime: Anime!
|
||||
image: Image!
|
||||
"The date that the resource was created"
|
||||
createdAt: DateTimeTz @rename(attribute: "created_at")
|
||||
"The date that the resource was last modified"
|
||||
updatedAt: DateTimeTz @rename(attribute: "updated_at")
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
"Represents the association between an anime and an external resource."
|
||||
type AnimeResource {
|
||||
anime: Anime!
|
||||
resource: ExternalResource!
|
||||
"Used to distinguish resources that map to the same anime"
|
||||
as: String
|
||||
"The date that the resource was created"
|
||||
createdAt: DateTimeTz @rename(attribute: "created_at")
|
||||
"The date that the resource was last modified"
|
||||
updatedAt: DateTimeTz @rename(attribute: "updated_at")
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
"Represents the association between an anime and a series."
|
||||
type AnimeSeries {
|
||||
anime: Anime!
|
||||
series: Series!
|
||||
"The date that the resource was created"
|
||||
createdAt: DateTimeTz @rename(attribute: "created_at")
|
||||
"The date that the resource was last modified"
|
||||
updatedAt: DateTimeTz @rename(attribute: "updated_at")
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
"Represents the association between an anime and a studio."
|
||||
type AnimeStudio {
|
||||
anime: Anime!
|
||||
studio: Studio!
|
||||
"The date that the resource was created"
|
||||
createdAt: DateTimeTz @rename(attribute: "created_at")
|
||||
"The date that the resource was last modified"
|
||||
updatedAt: DateTimeTz @rename(attribute: "updated_at")
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
"Represents the association between an anime theme entry and a video."
|
||||
type AnimeThemeEntryVideo {
|
||||
animethemeentry: AnimeThemeEntry!
|
||||
video: Video!
|
||||
"The date that the resource was created"
|
||||
createdAt: DateTimeTz @rename(attribute: "created_at")
|
||||
"The date that the resource was last modified"
|
||||
updatedAt: DateTimeTz @rename(attribute: "updated_at")
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
"Represents the association between an artist and an image."
|
||||
type ArtistImage {
|
||||
artist: Artist!
|
||||
image: Image!
|
||||
"Used to sort the artist images"
|
||||
depth: Int
|
||||
"The date that the resource was created"
|
||||
createdAt: DateTimeTz @rename(attribute: "created_at")
|
||||
"The date that the resource was last modified"
|
||||
updatedAt: DateTimeTz @rename(attribute: "updated_at")
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
"Represents the association of an artist and a group/unit."
|
||||
type ArtistMember {
|
||||
artist: Artist!
|
||||
member: Artist!
|
||||
"Used to distinguish member by alias"
|
||||
alias: String
|
||||
"Used to distinguish member by character"
|
||||
as: String
|
||||
"Used to extra annotation, like member role"
|
||||
notes: String
|
||||
"The date that the resource was created"
|
||||
createdAt: DateTimeTz @rename(attribute: "created_at")
|
||||
"The date that the resource was last modified"
|
||||
updatedAt: DateTimeTz @rename(attribute: "updated_at")
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
"Represents the association between an artist and an external resource."
|
||||
type ArtistResource {
|
||||
artist: Artist!
|
||||
resource: ExternalResource!
|
||||
"Used to distinguish resources that map to the same artist"
|
||||
as: String
|
||||
"The date that the resource was created"
|
||||
createdAt: DateTimeTz @rename(attribute: "created_at")
|
||||
"The date that the resource was last modified"
|
||||
updatedAt: DateTimeTz @rename(attribute: "updated_at")
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
"Represents the association between an song and an external resource."
|
||||
type SongResource {
|
||||
song: Song!
|
||||
resource: ExternalResource!
|
||||
"Used to distinguish resources that map to the same song"
|
||||
as: String
|
||||
"The date that the resource was created"
|
||||
createdAt: DateTimeTz @rename(attribute: "created_at")
|
||||
"The date that the resource was last modified"
|
||||
updatedAt: DateTimeTz @rename(attribute: "updated_at")
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
"Represents the association between a studio and an image."
|
||||
type StudioImage {
|
||||
studio: Studio!
|
||||
image: Image!
|
||||
"The date that the resource was created"
|
||||
createdAt: DateTimeTz @rename(attribute: "created_at")
|
||||
"The date that the resource was last modified"
|
||||
updatedAt: DateTimeTz @rename(attribute: "updated_at")
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
"Represents the association between a studio and an external resource."
|
||||
type StudioResource {
|
||||
studio: Studio!
|
||||
resource: ExternalResource!
|
||||
"Used to distinguish resources that map to the same studio"
|
||||
as: String
|
||||
"The date that the resource was created"
|
||||
createdAt: DateTimeTz @rename(attribute: "created_at")
|
||||
"The date that the resource was last modified"
|
||||
updatedAt: DateTimeTz @rename(attribute: "updated_at")
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
"Represents a notification that is sent to the user."
|
||||
type Notification {
|
||||
"The date that the user read the notification"
|
||||
readAt: DateTimeTz @rename(attribute: "read_at")
|
||||
"The JSON data of the notification"
|
||||
data: NotificationData!
|
||||
"The user the notification belongs to"
|
||||
user: User! @morphTo(relation: "notifiable")
|
||||
}
|
||||
|
||||
"Represents the JSON data of the notification"
|
||||
type NotificationData {
|
||||
"The title of the notification"
|
||||
title: String!
|
||||
"The content of the notification"
|
||||
body: String!
|
||||
"The image URL to display with the notification"
|
||||
image: String
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
"""
|
||||
Represents a version of an anime theme.
|
||||
|
||||
For example, the ED theme of the Bakemonogatari anime has three anime theme entries to represent three versions.
|
||||
"""
|
||||
type AnimeThemeEntry {
|
||||
"The primary key of the resource"
|
||||
id: Int! @rename(attribute: "entry_id")
|
||||
"The episodes that the theme is used for"
|
||||
episodes: String
|
||||
"Any additional information for this sequence"
|
||||
notes: String
|
||||
"Is not safe for work content included?"
|
||||
nsfw: Boolean!
|
||||
"Is content included that may spoil the viewer?"
|
||||
spoiler: Boolean!
|
||||
"The version number of the theme"
|
||||
version: Int
|
||||
animetheme: AnimeTheme @belongsTo
|
||||
videos: [Video] @belongsToMany(type: CONNECTION)
|
||||
"The date that the resource was created"
|
||||
createdAt: DateTimeTz @rename(attribute: "created_at")
|
||||
"The date that the resource was last modified"
|
||||
updatedAt: DateTimeTz @rename(attribute: "updated_at")
|
||||
"The date that the resource was deleted"
|
||||
deletedAt: DateTimeTz @rename(attribute: "deleted_at")
|
||||
}
|
||||
|
||||
"Default edge to use in simple belongs to many relationships"
|
||||
type AnimeThemeEntryEdge {
|
||||
node: AnimeThemeEntry!
|
||||
"The date that the resource was last modified"
|
||||
createdAt: DateTimeTz @field(resolver: "App\\GraphQL\\Resolvers\\PivotResolver@resolve")
|
||||
"The date that the resource was deleted"
|
||||
updatedAt: DateTimeTz @field(resolver: "App\\GraphQL\\Resolvers\\PivotResolver@resolve")
|
||||
}
|
||||
|
||||
enum AnimeThemeEntryColumnsOrderable {
|
||||
ID @enum(value: "entry_id")
|
||||
EPISODES
|
||||
NOTES
|
||||
NSFW
|
||||
SPOILER
|
||||
VERSION
|
||||
CREATED_AT
|
||||
UPDATED_AT
|
||||
DELETED_AT
|
||||
}
|
||||
|
||||
extend type Query {
|
||||
"Returns a listing of anime theme entry resources given fields."
|
||||
animethemeentries(
|
||||
isNsfw: Boolean @eq
|
||||
isSpoiler: Boolean @eq
|
||||
version_lesser: Int @where(key: "version", operator: "<")
|
||||
version_greater: Int @where(key: "version", operator: ">")
|
||||
createdAt_lesser: DateTimeTz @where(key: "created_at", operator: "<")
|
||||
createdAt_greater: DateTimeTz @where(key: "created_at", operator: ">")
|
||||
updatedAt_lesser: DateTimeTz @where(key: "updated_at", operator: "<")
|
||||
updatedAt_greater: DateTimeTz @where(key: "updated_at", operator: ">")
|
||||
deletedAt_lesser: DateTimeTz @where(key: "deleted_at", operator: "<")
|
||||
deletedAt_greater: DateTimeTz @where(key: "deleted_at", operator: ">")
|
||||
orderBy: _ @orderBy(columnsEnum: "AnimeThemeEntryColumnsOrderable")
|
||||
): [AnimeThemeEntry!]!
|
||||
@canModel(ability: "viewAny", injectArgs: true)
|
||||
@softDeletes
|
||||
@paginate
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
"""
|
||||
Represents an alternate title or common abbreviation for an anime.
|
||||
|
||||
For example, the anime Bakemonogatari has the anime synonym "Monstory".
|
||||
"""
|
||||
type AnimeSynonym {
|
||||
"The primary key of the resource"
|
||||
id: Int! @rename(attribute: "synonym_id")
|
||||
"The alternate title or common abbreviations"
|
||||
name: String!
|
||||
"The type of the synonym"
|
||||
type: AnimeSynonymType! @localizedEnum
|
||||
anime: Anime @belongsTo
|
||||
"The date that the resource was created"
|
||||
createdAt: DateTimeTz @rename(attribute: "created_at")
|
||||
"The date that the resource was last modified"
|
||||
updatedAt: DateTimeTz @rename(attribute: "updated_at")
|
||||
"The date that the resource was deleted"
|
||||
deletedAt: DateTimeTz @rename(attribute: "deleted_at")
|
||||
}
|
||||
|
||||
enum AnimeSynonymColumnsOrderable {
|
||||
ID @enum(value: "synonym_id")
|
||||
NAME
|
||||
TYPE
|
||||
CREATED_AT
|
||||
UPDATED_AT
|
||||
DELETED_AT
|
||||
}
|
||||
|
||||
extend type Query {
|
||||
"Returns a listing of anime synonym resources given fields."
|
||||
animesynonyms(
|
||||
type: [AnimeSynonymType] @in
|
||||
createdAt_lesser: DateTimeTz @where(key: "created_at", operator: "<")
|
||||
createdAt_greater: DateTimeTz @where(key: "created_at", operator: ">")
|
||||
updatedAt_lesser: DateTimeTz @where(key: "updated_at", operator: "<")
|
||||
updatedAt_greater: DateTimeTz @where(key: "updated_at", operator: ">")
|
||||
deletedAt_lesser: DateTimeTz @where(key: "deleted_at", operator: "<")
|
||||
deletedAt_greater: DateTimeTz @where(key: "deleted_at", operator: ">")
|
||||
orderBy: _ @orderBy(columnsEnum: "AnimeSynonymColumnsOrderable")
|
||||
): [AnimeSynonym!]!
|
||||
@canModel(ability: "viewAny", injectArgs: true)
|
||||
@softDeletes
|
||||
@paginate
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
"""
|
||||
Represents an OP or ED sequence for an anime.
|
||||
|
||||
For example, the anime Bakemonogatari has five OP anime themes and one ED anime theme.
|
||||
"""
|
||||
type AnimeTheme {
|
||||
"The primary key of the resource"
|
||||
id: Int! @rename(attribute: "theme_id")
|
||||
"The type of the sequence"
|
||||
type: ThemeType! @localizedEnum
|
||||
"The numeric ordering of the theme"
|
||||
sequence: Int
|
||||
anime: Anime @belongsTo
|
||||
animethemeentries: [AnimeThemeEntry] @hasMany
|
||||
group: ThemeGroup @belongsTo
|
||||
song: Song @belongsTo
|
||||
"The date that the resource was created"
|
||||
createdAt: DateTimeTz @rename(attribute: "created_at")
|
||||
"The date that the resource was last modified"
|
||||
updatedAt: DateTimeTz @rename(attribute: "updated_at")
|
||||
"The date that the resource was deleted"
|
||||
deletedAt: DateTimeTz @rename(attribute: "deleted_at")
|
||||
}
|
||||
|
||||
enum AnimeThemeColumnsOrderable {
|
||||
ID @enum(value: "theme_id")
|
||||
TYPE
|
||||
SEQUENCE
|
||||
CREATED_AT
|
||||
UPDATED_AT
|
||||
DELETED_AT
|
||||
}
|
||||
|
||||
extend type Query {
|
||||
"Returns a listing of anime theme resources given fields."
|
||||
animethemes(
|
||||
type: [ThemeType] @in
|
||||
sequence_lesser: Int @where(key: "sequence", operator: "<")
|
||||
sequence_greater: Int @where(key: "sequence", operator: ">")
|
||||
createdAt_lesser: DateTimeTz @where(key: "created_at", operator: "<")
|
||||
createdAt_greater: DateTimeTz @where(key: "created_at", operator: ">")
|
||||
updatedAt_lesser: DateTimeTz @where(key: "updated_at", operator: "<")
|
||||
updatedAt_greater: DateTimeTz @where(key: "updated_at", operator: ">")
|
||||
deletedAt_lesser: DateTimeTz @where(key: "deleted_at", operator: "<")
|
||||
deletedAt_greater: DateTimeTz @where(key: "deleted_at", operator: ">")
|
||||
orderBy: _ @orderBy(columnsEnum: "AnimeThemeColumnsOrderable")
|
||||
): [AnimeTheme!]!
|
||||
@canModel(ability: "viewAny", injectArgs: true)
|
||||
@softDeletes
|
||||
@paginate
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
"""
|
||||
Represents the link between an artist and a group related to the song credits.
|
||||
|
||||
For example, Sayuri Date is a member of Liella and has performed using the membership.
|
||||
"""
|
||||
type Membership {
|
||||
"The primary key of the resource"
|
||||
id: Int! @rename(attribute: "membership_id")
|
||||
"The alias the artist is using for this membership"
|
||||
alias: String
|
||||
"The character the artist is performing as"
|
||||
as: String
|
||||
group: Artist! @belongsTo(relation: "artist")
|
||||
member: Artist! @belongsTo
|
||||
performances: [Performance] @morphMany
|
||||
"The date that the resource was created"
|
||||
createdAt: DateTimeTz @rename(attribute: "created_at")
|
||||
"The date that the resource was last modified"
|
||||
updatedAt: DateTimeTz @rename(attribute: "updated_at")
|
||||
"The date that the resource was deleted"
|
||||
deletedAt: DateTimeTz @rename(attribute: "deleted_at")
|
||||
}
|
||||
|
||||
enum MembershipColumnsOrderable {
|
||||
ID @enum(value: "membership_id")
|
||||
ALIAS
|
||||
AS
|
||||
CREATED_AT
|
||||
UPDATED_AT
|
||||
DELETED_AT
|
||||
}
|
||||
|
||||
extend type Query {
|
||||
"Returns a listing of membership resources given fields."
|
||||
memberships(
|
||||
alias: String @eq
|
||||
as: String @eq
|
||||
createdAt_lesser: DateTimeTz @where(key: "created_at", operator: "<")
|
||||
createdAt_greater: DateTimeTz @where(key: "created_at", operator: ">")
|
||||
updatedAt_lesser: DateTimeTz @where(key: "updated_at", operator: "<")
|
||||
updatedAt_greater: DateTimeTz @where(key: "updated_at", operator: ">")
|
||||
deletedAt_lesser: DateTimeTz @where(key: "deleted_at", operator: "<")
|
||||
deletedAt_greater: DateTimeTz @where(key: "deleted_at", operator: ">")
|
||||
orderBy: _ @orderBy(columnsEnum: "MembershipColumnsOrderable")
|
||||
): [Membership!]!
|
||||
@canModel(ability: "viewAny", injectArgs: true)
|
||||
@softDeletes
|
||||
@paginate
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
"""
|
||||
Represents the link between a song and an artist or membership.
|
||||
|
||||
For example, Liella has performed using memberships, with its members credited.
|
||||
"""
|
||||
type Performance {
|
||||
"The primary key of the resource"
|
||||
id: Int! @rename(attribute: "performance_id")
|
||||
"The song the artist is performing"
|
||||
song: Song @belongsTo
|
||||
"The artist or membership performing"
|
||||
artist: PerformanceArtistUnion! @morphTo
|
||||
"The alias the artist is using for this performance"
|
||||
alias: String
|
||||
"The character the artist is performing as"
|
||||
as: String
|
||||
"The date that the resource was created"
|
||||
createdAt: DateTimeTz @rename(attribute: "created_at")
|
||||
"The date that the resource was last modified"
|
||||
updatedAt: DateTimeTz @rename(attribute: "updated_at")
|
||||
"The date that the resource was deleted"
|
||||
deletedAt: DateTimeTz @rename(attribute: "deleted_at")
|
||||
}
|
||||
|
||||
"Represents the resource type performing"
|
||||
union PerformanceArtistUnion = Artist | Membership
|
||||
|
||||
enum PerformanceColumnsOrderable {
|
||||
ID @enum(value: "performance_id")
|
||||
ALIAS
|
||||
AS
|
||||
CREATED_AT
|
||||
UPDATED_AT
|
||||
DELETED_AT
|
||||
}
|
||||
|
||||
extend type Query {
|
||||
"Returns a listing of performance resources given fields."
|
||||
performances(
|
||||
alias: String @eq
|
||||
as: String @eq
|
||||
hasSong: [WhereHasConditions!] @whereHasConditions(relation: "song", columns: ["title"])
|
||||
createdAt_lesser: DateTimeTz @where(key: "created_at", operator: "<")
|
||||
createdAt_greater: DateTimeTz @where(key: "created_at", operator: ">")
|
||||
updatedAt_lesser: DateTimeTz @where(key: "updated_at", operator: "<")
|
||||
updatedAt_greater: DateTimeTz @where(key: "updated_at", operator: ">")
|
||||
deletedAt_lesser: DateTimeTz @where(key: "deleted_at", operator: "<")
|
||||
deletedAt_greater: DateTimeTz @where(key: "deleted_at", operator: ">")
|
||||
orderBy: _ @orderBy(columnsEnum: "PerformanceColumnsOrderable")
|
||||
): [Performance!]!
|
||||
@canModel(ability: "viewAny", injectArgs: true)
|
||||
@softDeletes
|
||||
@paginate
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
"""
|
||||
Represents an encoding script used to produce a video.
|
||||
|
||||
For example, the 2009/Summer/Bakemonogatari-OP1.txt video script represents the encoding script of the Bakemonogatari-OP1.webm video.
|
||||
"""
|
||||
type VideoScript {
|
||||
"The primary key of the resource"
|
||||
id: Int! @rename(attribute: "script_id")
|
||||
"The path of the file in storage"
|
||||
path: String!
|
||||
"The URL to download the file from storage"
|
||||
link: String!
|
||||
video: Video @hasOne
|
||||
"The date that the resource was created"
|
||||
createdAt: DateTimeTz @rename(attribute: "created_at")
|
||||
"The date that the resource was last modified"
|
||||
updatedAt: DateTimeTz @rename(attribute: "updated_at")
|
||||
"The date that the resource was deleted"
|
||||
deletedAt: DateTimeTz @rename(attribute: "deleted_at")
|
||||
}
|
||||
|
||||
enum VideoScriptColumnsOrderable {
|
||||
ID @enum(value: "script_id")
|
||||
PATH
|
||||
LINK
|
||||
CREATED_AT
|
||||
UPDATED_AT
|
||||
DELETED_AT
|
||||
}
|
||||
|
||||
extend type Query {
|
||||
"Returns a listing of script resources given fields."
|
||||
scripts(
|
||||
createdAt_lesser: DateTimeTz @where(key: "created_at", operator: "<")
|
||||
createdAt_greater: DateTimeTz @where(key: "created_at", operator: ">")
|
||||
updatedAt_lesser: DateTimeTz @where(key: "updated_at", operator: "<")
|
||||
updatedAt_greater: DateTimeTz @where(key: "updated_at", operator: ">")
|
||||
deletedAt_lesser: DateTimeTz @where(key: "deleted_at", operator: "<")
|
||||
deletedAt_greater: DateTimeTz @where(key: "deleted_at", operator: ">")
|
||||
orderBy: _ @orderBy(columnsEnum: "VideoScriptColumnsOrderable")
|
||||
): [VideoScript!]!
|
||||
@canModel(ability: "viewAny", injectArgs: true)
|
||||
@softDeletes
|
||||
@paginate
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
"""
|
||||
Represents a production with at least one opening or ending sequence.
|
||||
|
||||
For example, Bakemonogatari is an anime production with five opening sequences and one ending sequence."
|
||||
"""
|
||||
type Anime {
|
||||
"The primary key of the resource"
|
||||
id: Int! @rename(attribute: "anime_id")
|
||||
"The media format of the anime"
|
||||
mediaFormat: AnimeMediaFormat @rename(attribute: "media_format") @localizedEnum
|
||||
"The primary title of the anime"
|
||||
name: String!
|
||||
"The premiere season of the anime"
|
||||
season: AnimeSeason @localizedEnum
|
||||
"The URL slug & route key of the resource"
|
||||
slug: String!
|
||||
"The brief summary of the anime"
|
||||
synopsis: String
|
||||
"The premiere year of the anime"
|
||||
year: Int
|
||||
animesynonyms: [AnimeSynonym] @hasMany
|
||||
animethemes: [AnimeTheme] @hasMany
|
||||
images: [Image]! @belongsToMany(type: CONNECTION)
|
||||
resources: [ExternalResource]! @belongsToMany(type: CONNECTION)
|
||||
series: [Series]! @belongsToMany(type: CONNECTION)
|
||||
studios: [Studio]! @belongsToMany(type: CONNECTION)
|
||||
"The date that the resource was created"
|
||||
createdAt: DateTimeTz @rename(attribute: "created_at")
|
||||
"The date that the resource was last modified"
|
||||
updatedAt: DateTimeTz @rename(attribute: "updated_at")
|
||||
"The date that the resource was deleted"
|
||||
deletedAt: DateTimeTz @rename(attribute: "deleted_at")
|
||||
}
|
||||
|
||||
"Default edge to use in simple belongs to many relationships"
|
||||
type AnimeEdge {
|
||||
node: Anime!
|
||||
"The date that the resource was last modified"
|
||||
createdAt: DateTimeTz @field(resolver: "App\\GraphQL\\Resolvers\\PivotResolver@resolve")
|
||||
"The date that the resource was deleted"
|
||||
updatedAt: DateTimeTz @field(resolver: "App\\GraphQL\\Resolvers\\PivotResolver@resolve")
|
||||
}
|
||||
|
||||
type AnimeYear {
|
||||
winter: [Anime]
|
||||
spring: [Anime]
|
||||
summer: [Anime]
|
||||
fall: [Anime]
|
||||
}
|
||||
|
||||
enum AnimeColumnsOrderable {
|
||||
ID @enum(value: "anime_id")
|
||||
NAME
|
||||
MEDIA_FORMAT
|
||||
SEASON
|
||||
SLUG
|
||||
YEAR
|
||||
CREATED_AT
|
||||
UPDATED_AT
|
||||
DELETED_AT
|
||||
}
|
||||
|
||||
enum HasResources {
|
||||
SITE
|
||||
EXTERNAL_ID
|
||||
}
|
||||
|
||||
extend type Query {
|
||||
"Returns a listing of anime resources given fields."
|
||||
animes(
|
||||
search: String @search
|
||||
name: String @where(operator: "like")
|
||||
mediaFormat: [AnimeMediaFormat] @in(key: "media_format")
|
||||
season: [AnimeSeason] @in
|
||||
slug: String @eq
|
||||
year_in: [Int] @in(key: "year")
|
||||
year_notin: [Int] @notIn(key: "year")
|
||||
year_lesser: Int @where(key: "year", operator: "<")
|
||||
year_greater: Int @where(key: "year", operator: ">")
|
||||
where: _ @whereConditions(columns: ["name"])
|
||||
whereHas: [WhereHasConditions!] @whereHasConditions(columns: ["*"])
|
||||
hasResources: [WhereHasConditions!] @whereHasConditions(columnsEnum: "HasResources")
|
||||
createdAt_lesser: DateTimeTz @where(key: "created_at", operator: "<")
|
||||
createdAt_greater: DateTimeTz @where(key: "created_at", operator: ">")
|
||||
updatedAt_lesser: DateTimeTz @where(key: "updated_at", operator: "<")
|
||||
updatedAt_greater: DateTimeTz @where(key: "updated_at", operator: ">")
|
||||
deletedAt_lesser: DateTimeTz @where(key: "deleted_at", operator: "<")
|
||||
deletedAt_greater: DateTimeTz @where(key: "deleted_at", operator: ">")
|
||||
orderBy: _ @orderBy(columnsEnum: "AnimeColumnsOrderable")
|
||||
): [Anime!]!
|
||||
@canModel(ability: "viewAny", injectArgs: true)
|
||||
@softDeletes
|
||||
@paginate
|
||||
|
||||
"Returns a listing of anime resources for a given year grouped by season and ordered by name."
|
||||
animeyear(year: Int!): AnimeYear
|
||||
@canModel(ability: "viewAny", model: "App\\Models\\Wiki\\Anime", injectArgs: true)
|
||||
@field(resolver: "App\\GraphQL\\Queries\\AnimeYear@year")
|
||||
|
||||
"Returns a list of unique years from all anime resources."
|
||||
animeyears: [Int!]!
|
||||
@canModel(ability: "viewAny", model: "App\\Models\\Wiki\\Anime", injectArgs: true)
|
||||
@field(resolver: "App\\GraphQL\\Queries\\AnimeYear@years")
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
"""
|
||||
Represents a musical performer of anime sequences.
|
||||
|
||||
For example, Chiwa Saitou is the musical performer of the Bakemonogatari OP1 theme, among many others.
|
||||
"""
|
||||
type Artist {
|
||||
"The primary key of the resource"
|
||||
id: Int! @rename(attribute: "artist_id")
|
||||
"The primary title of the artist"
|
||||
name: String!
|
||||
"The URL slug & route key of the resource"
|
||||
slug: String!
|
||||
"The brief information of the resource"
|
||||
information: String
|
||||
groups: [Artist] @belongsToMany(type: CONNECTION, edgeType: ArtistMemberEdge)
|
||||
images: [Image] @belongsToMany(type: CONNECTION, edgeType: ArtistImageEdge)
|
||||
members: [Artist] @belongsToMany(type: CONNECTION, edgeType: ArtistMemberEdge)
|
||||
memberships: [Membership] @hasMany
|
||||
performances: [Performance] @morphMany
|
||||
resources: [ExternalResource]! @belongsToMany(type: CONNECTION)
|
||||
"The date that the resource was created"
|
||||
createdAt: DateTimeTz @rename(attribute: "created_at")
|
||||
"The date that the resource was last modified"
|
||||
updatedAt: DateTimeTz @rename(attribute: "updated_at")
|
||||
"The date that the resource was deleted"
|
||||
deletedAt: DateTimeTz @rename(attribute: "deleted_at")
|
||||
}
|
||||
|
||||
"Default edge to use in simple belongs to many relationships"
|
||||
type ArtistEdge {
|
||||
node: Artist!
|
||||
"The date that the resource was last modified"
|
||||
createdAt: DateTimeTz @field(resolver: "App\\GraphQL\\Resolvers\\PivotResolver@resolve")
|
||||
"The date that the resource was deleted"
|
||||
updatedAt: DateTimeTz @field(resolver: "App\\GraphQL\\Resolvers\\PivotResolver@resolve")
|
||||
}
|
||||
|
||||
"Artist Member has extra pivots"
|
||||
type ArtistMemberEdge {
|
||||
node: Artist!
|
||||
"Used to distinguish member by alias"
|
||||
alias: String @field(resolver: "App\\GraphQL\\Resolvers\\PivotResolver@resolve")
|
||||
"Used to distinguish member by character"
|
||||
as: String @field(resolver: "App\\GraphQL\\Resolvers\\PivotResolver@resolve")
|
||||
"Used to extra annotation, like member role"
|
||||
notes: String @field(resolver: "App\\GraphQL\\Resolvers\\PivotResolver@resolve")
|
||||
}
|
||||
|
||||
"Artist Image has an extra pivot that others image relationships don't"
|
||||
type ArtistImageEdge {
|
||||
node: Image!
|
||||
"Used to sort the artist images"
|
||||
depth: Int @field(resolver: "App\\GraphQL\\Resolvers\\PivotResolver@resolve")
|
||||
"The date that the resource was last modified"
|
||||
createdAt: DateTimeTz @field(resolver: "App\\GraphQL\\Resolvers\\PivotResolver@resolve")
|
||||
"The date that the resource was deleted"
|
||||
updatedAt: DateTimeTz @field(resolver: "App\\GraphQL\\Resolvers\\PivotResolver@resolve")
|
||||
}
|
||||
|
||||
enum ArtistColumnsOrderable {
|
||||
ID @enum(value: "artist_id")
|
||||
NAME
|
||||
SLUG
|
||||
CREATED_AT
|
||||
UPDATED_AT
|
||||
DELETED_AT
|
||||
}
|
||||
|
||||
extend type Query {
|
||||
"Returns a listing of artist resources given fields."
|
||||
artists(
|
||||
createdAt_lesser: DateTimeTz @where(key: "created_at", operator: "<")
|
||||
createdAt_greater: DateTimeTz @where(key: "created_at", operator: ">")
|
||||
updatedAt_lesser: DateTimeTz @where(key: "updated_at", operator: "<")
|
||||
updatedAt_greater: DateTimeTz @where(key: "updated_at", operator: ">")
|
||||
deletedAt_lesser: DateTimeTz @where(key: "deleted_at", operator: "<")
|
||||
deletedAt_greater: DateTimeTz @where(key: "deleted_at", operator: ">")
|
||||
orderBy: _ @orderBy(columnsEnum: "ArtistColumnsOrderable")
|
||||
): [Artist!]!
|
||||
@canModel(ability: "viewAny", injectArgs: true)
|
||||
@softDeletes
|
||||
@paginate
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
"""
|
||||
Represents the audio track of a video.
|
||||
|
||||
For example, the audio Bakemonogatari-OP1.ogg represents the audio track of the Bakemonogatari-OP1.webm video.
|
||||
"""
|
||||
type Audio {
|
||||
"The primary key of the resource"
|
||||
id: Int! @rename(attribute: "audio_id")
|
||||
"The basename of the file in storage"
|
||||
basename: String!
|
||||
"The filename of the file in storage"
|
||||
filename: String!
|
||||
"The media type of the file in storage"
|
||||
mimetype: String!
|
||||
"The path of the file in storage"
|
||||
path: String!
|
||||
"The size of the file in storage in Bytes"
|
||||
size: Int!
|
||||
"The URL to stream the file from storage"
|
||||
link: String!
|
||||
"The number of views recorded for the resource"
|
||||
viewsCount: Int! @with(relation: "viewAggregate") @field(resolver: "App\\GraphQL\\Resolvers\\ViewsCountResolver@resolve")
|
||||
videos: [Video] @hasMany
|
||||
"The date that the resource was created"
|
||||
createdAt: DateTimeTz @rename(attribute: "created_at")
|
||||
"The date that the resource was last modified"
|
||||
updatedAt: DateTimeTz @rename(attribute: "updated_at")
|
||||
"The date that the resource was deleted"
|
||||
deletedAt: DateTimeTz @rename(attribute: "deleted_at")
|
||||
}
|
||||
|
||||
enum AudioColumnsOrderable {
|
||||
ID @enum(value: "audio_id")
|
||||
FILENAME
|
||||
BASENAME
|
||||
SIZE
|
||||
CREATED_AT
|
||||
UPDATED_AT
|
||||
DELETED_AT
|
||||
}
|
||||
|
||||
extend type Query {
|
||||
"Returns a listing of audio resources given fields."
|
||||
audios(
|
||||
size_lesser: Int @where(key: "size", operator: "<")
|
||||
size_greater: Int @where(key: "size", operator: ">")
|
||||
createdAt_lesser: DateTimeTz @where(key: "created_at", operator: "<")
|
||||
createdAt_greater: DateTimeTz @where(key: "created_at", operator: ">")
|
||||
updatedAt_lesser: DateTimeTz @where(key: "updated_at", operator: "<")
|
||||
updatedAt_greater: DateTimeTz @where(key: "updated_at", operator: ">")
|
||||
deletedAt_lesser: DateTimeTz @where(key: "deleted_at", operator: "<")
|
||||
deletedAt_greater: DateTimeTz @where(key: "deleted_at", operator: ">")
|
||||
orderBy: _ @orderBy(columnsEnum: "AudioColumnsOrderable")
|
||||
): [Audio!]!
|
||||
@canModel(ability: "viewAny", injectArgs: true)
|
||||
@softDeletes
|
||||
@paginate
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
"""
|
||||
Represents a site with supplementary information for another resource such as an anime or artist.
|
||||
|
||||
For example, the Bakemonogatari anime has MyAnimeList, AniList and AniDB resources.
|
||||
"""
|
||||
type ExternalResource {
|
||||
"The primary key of the resource"
|
||||
id: Int! @rename(attribute: "resource_id")
|
||||
"The primary key of the resource in the external site"
|
||||
externalId: Int @rename(attribute: "external_id")
|
||||
"The URL of the external site"
|
||||
link: String!
|
||||
"The external site that the resource belongs to"
|
||||
site: ResourceSite! @localizedEnum
|
||||
anime: [Anime] @belongsToMany(type: CONNECTION, edgeType: ExternalResourceAnimeEdge)
|
||||
artists: [Artist] @belongsToMany(type: CONNECTION, edgeType: ExternalResourceArtistEdge)
|
||||
songs: [Song] @belongsToMany(type: CONNECTION, edgeType: ExternalResourceSongEdge)
|
||||
studios: [Studio] @belongsToMany(type: CONNECTION, edgeType: ExternalResourceStudioEdge)
|
||||
"The date that the resource was created"
|
||||
createdAt: DateTimeTz @rename(attribute: "created_at")
|
||||
"The date that the resource was last modified"
|
||||
updatedAt: DateTimeTz @rename(attribute: "updated_at")
|
||||
"The date that the resource was deleted"
|
||||
deletedAt: DateTimeTz @rename(attribute: "deleted_at")
|
||||
}
|
||||
|
||||
"Default edge to use in simple belongs to many relationships"
|
||||
type ExternalResourceEdge {
|
||||
node: ExternalResource!
|
||||
"Used to distinguish resources that map to the same resource"
|
||||
as: String @field(resolver: "App\\GraphQL\\Resolvers\\PivotResolver@resolve")
|
||||
"The date that the resource was last modified"
|
||||
createdAt: DateTimeTz @field(resolver: "App\\GraphQL\\Resolvers\\PivotResolver@resolve")
|
||||
"The date that the resource was deleted"
|
||||
updatedAt: DateTimeTz @field(resolver: "App\\GraphQL\\Resolvers\\PivotResolver@resolve")
|
||||
}
|
||||
|
||||
"External Resource has an extra pivot field"
|
||||
type ExternalResourceAnimeEdge {
|
||||
node: Anime!
|
||||
"Used to distinguish resources that map to the same anime"
|
||||
as: String @field(resolver: "App\\GraphQL\\Resolvers\\PivotResolver@resolve")
|
||||
"The date that the resource was last modified"
|
||||
createdAt: DateTimeTz @field(resolver: "App\\GraphQL\\Resolvers\\PivotResolver@resolve")
|
||||
"The date that the resource was deleted"
|
||||
updatedAt: DateTimeTz @field(resolver: "App\\GraphQL\\Resolvers\\PivotResolver@resolve")
|
||||
}
|
||||
|
||||
"External Resource has an extra pivot field"
|
||||
type ExternalResourceArtistEdge {
|
||||
node: Artist!
|
||||
"Used to distinguish resources that map to the same artist"
|
||||
as: String @field(resolver: "App\\GraphQL\\Resolvers\\PivotResolver@resolve")
|
||||
"The date that the resource was last modified"
|
||||
createdAt: DateTimeTz @field(resolver: "App\\GraphQL\\Resolvers\\PivotResolver@resolve")
|
||||
"The date that the resource was deleted"
|
||||
updatedAt: DateTimeTz @field(resolver: "App\\GraphQL\\Resolvers\\PivotResolver@resolve")
|
||||
}
|
||||
|
||||
"External Resource has an extra pivot field"
|
||||
type ExternalResourceSongEdge {
|
||||
node: Song!
|
||||
"Used to distinguish resources that map to the same song"
|
||||
as: String @field(resolver: "App\\GraphQL\\Resolvers\\PivotResolver@resolve")
|
||||
"The date that the resource was last modified"
|
||||
createdAt: DateTimeTz @field(resolver: "App\\GraphQL\\Resolvers\\PivotResolver@resolve")
|
||||
"The date that the resource was deleted"
|
||||
updatedAt: DateTimeTz @field(resolver: "App\\GraphQL\\Resolvers\\PivotResolver@resolve")
|
||||
}
|
||||
|
||||
"External Resource has an extra pivot field"
|
||||
type ExternalResourceStudioEdge {
|
||||
node: Studio!
|
||||
"Used to distinguish resources that map to the same studio"
|
||||
as: String @field(resolver: "App\\GraphQL\\Resolvers\\PivotResolver@resolve")
|
||||
"The date that the resource was last modified"
|
||||
createdAt: DateTimeTz @field(resolver: "App\\GraphQL\\Resolvers\\PivotResolver@resolve")
|
||||
"The date that the resource was deleted"
|
||||
updatedAt: DateTimeTz @field(resolver: "App\\GraphQL\\Resolvers\\PivotResolver@resolve")
|
||||
}
|
||||
|
||||
enum ExternalResourceColumnsOrderable {
|
||||
ID @enum(value: "resource_id")
|
||||
SITE
|
||||
EXTERNAL_ID
|
||||
LINK
|
||||
CREATED_AT
|
||||
UPDATED_AT
|
||||
DELETED_AT
|
||||
}
|
||||
|
||||
extend type Query {
|
||||
"Returns a listing of resources given fields."
|
||||
externalresources(
|
||||
externalId: Int @eq
|
||||
site: [ResourceSite] @in
|
||||
createdAt_lesser: DateTimeTz @where(key: "created_at", operator: "<")
|
||||
createdAt_greater: DateTimeTz @where(key: "created_at", operator: ">")
|
||||
updatedAt_lesser: DateTimeTz @where(key: "updated_at", operator: "<")
|
||||
updatedAt_greater: DateTimeTz @where(key: "updated_at", operator: ">")
|
||||
deletedAt_lesser: DateTimeTz @where(key: "deleted_at", operator: "<")
|
||||
deletedAt_greater: DateTimeTz @where(key: "deleted_at", operator: ">")
|
||||
orderBy: _ @orderBy(columnsEnum: "ExternalResourceColumnsOrderable")
|
||||
): [ExternalResource!]!
|
||||
@canModel(ability: "viewAny", injectArgs: true)
|
||||
@softDeletes
|
||||
@paginate
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
"""
|
||||
Represents the group that accompanies a Theme.
|
||||
|
||||
For example, English Version is the group for english dubbed Theme.
|
||||
"""
|
||||
type ThemeGroup @model(class: "App\\Models\\Wiki\\Group") {
|
||||
"The primary key of the resource"
|
||||
id: Int! @rename(attribute: "group_id")
|
||||
"The name of the group"
|
||||
name: String!
|
||||
"The slug of the group"
|
||||
slug: String!
|
||||
animethemes: [AnimeTheme] @hasMany
|
||||
"The date that the resource was created"
|
||||
createdAt: DateTimeTz @rename(attribute: "created_at")
|
||||
"The date that the resource was last modified"
|
||||
updatedAt: DateTimeTz @rename(attribute: "updated_at")
|
||||
"The date that the resource was deleted"
|
||||
deletedAt: DateTimeTz @rename(attribute: "deleted_at")
|
||||
}
|
||||
|
||||
enum ThemeGroupColumnsOrderable {
|
||||
ID @enum(value: "group_id")
|
||||
NAME
|
||||
SLUG
|
||||
CREATED_AT
|
||||
UPDATED_AT
|
||||
DELETED_AT
|
||||
}
|
||||
|
||||
extend type Query {
|
||||
"Returns a listing of theme groups resources given fields."
|
||||
themegroups(
|
||||
createdAt_lesser: DateTimeTz @where(key: "created_at", operator: "<")
|
||||
createdAt_greater: DateTimeTz @where(key: "created_at", operator: ">")
|
||||
updatedAt_lesser: DateTimeTz @where(key: "updated_at", operator: "<")
|
||||
updatedAt_greater: DateTimeTz @where(key: "updated_at", operator: ">")
|
||||
deletedAt_lesser: DateTimeTz @where(key: "deleted_at", operator: "<")
|
||||
deletedAt_greater: DateTimeTz @where(key: "deleted_at", operator: ">")
|
||||
orderBy: _ @orderBy(columnsEnum: "ThemeGroupColumnsOrderable")
|
||||
): [ThemeGroup!]!
|
||||
|
||||
@canModel(ability: "viewAny", injectArgs: true)
|
||||
@softDeletes
|
||||
@paginate
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
"""
|
||||
Represents a visual component for another resource such as an anime or artist.
|
||||
|
||||
For example, the Bakemonogatari anime has two images to represent small and large cover images.
|
||||
"""
|
||||
type Image {
|
||||
"The primary key of the resource"
|
||||
id: Int! @rename(attribute: "image_id")
|
||||
"The component that the resource is intended for"
|
||||
facet: ImageFacet! @localizedEnum
|
||||
"The path of the file in storage"
|
||||
path: String!
|
||||
"The URL to stream the file from storage"
|
||||
link: String!
|
||||
anime: [Anime] @belongsToMany(type: CONNECTION)
|
||||
artists: [Artist] @belongsToMany(type: CONNECTION, edgeType: ImageArtistEdge)
|
||||
studios: [Studio] @belongsToMany(type: CONNECTION)
|
||||
"The date that the resource was created"
|
||||
createdAt: DateTimeTz @rename(attribute: "created_at")
|
||||
"The date that the resource was last modified"
|
||||
updatedAt: DateTimeTz @rename(attribute: "updated_at")
|
||||
"The date that the resource was deleted"
|
||||
deletedAt: DateTimeTz @rename(attribute: "deleted_at")
|
||||
}
|
||||
|
||||
"Default edge to use in simple belongs to many relationships"
|
||||
type ImageEdge {
|
||||
node: Image!
|
||||
"The date that the resource was last modified"
|
||||
createdAt: DateTimeTz @field(resolver: "App\\GraphQL\\Resolvers\\PivotResolver@resolve")
|
||||
"The date that the resource was deleted"
|
||||
updatedAt: DateTimeTz @field(resolver: "App\\GraphQL\\Resolvers\\PivotResolver@resolve")
|
||||
}
|
||||
|
||||
"Image Artist has an extra pivot that others image relationships don't"
|
||||
type ImageArtistEdge {
|
||||
node: Artist!
|
||||
"Used to sort the resource images"
|
||||
depth: Int @field(resolver: "App\\GraphQL\\Resolvers\\PivotResolver@resolve")
|
||||
"The date that the resource was last modified"
|
||||
createdAt: DateTimeTz @field(resolver: "App\\GraphQL\\Resolvers\\PivotResolver@resolve")
|
||||
"The date that the resource was deleted"
|
||||
updatedAt: DateTimeTz @field(resolver: "App\\GraphQL\\Resolvers\\PivotResolver@resolve")
|
||||
}
|
||||
|
||||
enum ImageColumnsOrderable {
|
||||
ID @enum(value: "image_id")
|
||||
FACET
|
||||
PATH
|
||||
CREATED_AT
|
||||
UPDATED_AT
|
||||
DELETED_AT
|
||||
}
|
||||
|
||||
extend type Query {
|
||||
"Returns a listing of image resources given fields."
|
||||
images(
|
||||
facet: [ImageFacet] @in
|
||||
createdAt_lesser: DateTimeTz @where(key: "created_at", operator: "<")
|
||||
createdAt_greater: DateTimeTz @where(key: "created_at", operator: ">")
|
||||
updatedAt_lesser: DateTimeTz @where(key: "updated_at", operator: "<")
|
||||
updatedAt_greater: DateTimeTz @where(key: "updated_at", operator: ">")
|
||||
deletedAt_lesser: DateTimeTz @where(key: "deleted_at", operator: "<")
|
||||
deletedAt_greater: DateTimeTz @where(key: "deleted_at", operator: ">")
|
||||
orderBy: _ @orderBy(columnsEnum: "ImageColumnsOrderable")
|
||||
): [Image!]!
|
||||
@canModel(ability: "viewAny", injectArgs: true)
|
||||
@softDeletes
|
||||
@paginate
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
"""
|
||||
Represents a collection of related anime.
|
||||
|
||||
For example, the Monogatari series is the collection of the Bakemonogatari anime and its related productions.
|
||||
"""
|
||||
type Series {
|
||||
"The primary key of the resource"
|
||||
id: Int! @rename(attribute: "series_id")
|
||||
"The primary title of the series"
|
||||
name: String!
|
||||
"The URL slug & route key of the resource"
|
||||
slug: String!
|
||||
anime: [Anime] @belongsToMany(type: CONNECTION)
|
||||
"The date that the resource was created"
|
||||
createdAt: DateTimeTz @rename(attribute: "created_at")
|
||||
"The date that the resource was last modified"
|
||||
updatedAt: DateTimeTz @rename(attribute: "updated_at")
|
||||
"The date that the resource was deleted"
|
||||
deletedAt: DateTimeTz @rename(attribute: "deleted_at")
|
||||
}
|
||||
|
||||
"Default edge to use in simple belongs to many relationships"
|
||||
type SeriesEdge {
|
||||
node: Series!
|
||||
"The date that the resource was last modified"
|
||||
createdAt: DateTimeTz @field(resolver: "App\\GraphQL\\Resolvers\\PivotResolver@resolve")
|
||||
"The date that the resource was deleted"
|
||||
updatedAt: DateTimeTz @field(resolver: "App\\GraphQL\\Resolvers\\PivotResolver@resolve")
|
||||
}
|
||||
|
||||
enum SeriesColumnsOrderable {
|
||||
ID @enum(value: "series_id")
|
||||
NAME
|
||||
SLUG
|
||||
CREATED_AT
|
||||
UPDATED_AT
|
||||
DELETED_AT
|
||||
}
|
||||
|
||||
extend type Query {
|
||||
"Returns a listing of series resources given fields."
|
||||
series(
|
||||
createdAt_lesser: DateTimeTz @where(key: "created_at", operator: "<")
|
||||
createdAt_greater: DateTimeTz @where(key: "created_at", operator: ">")
|
||||
updatedAt_lesser: DateTimeTz @where(key: "updated_at", operator: "<")
|
||||
updatedAt_greater: DateTimeTz @where(key: "updated_at", operator: ">")
|
||||
deletedAt_lesser: DateTimeTz @where(key: "deleted_at", operator: "<")
|
||||
deletedAt_greater: DateTimeTz @where(key: "deleted_at", operator: ">")
|
||||
orderBy: _ @orderBy(columnsEnum: "SeriesColumnsOrderable")
|
||||
): [Series!]!
|
||||
@canModel(ability: "viewAny", injectArgs: true)
|
||||
@softDeletes
|
||||
@paginate
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
"""
|
||||
Represents the composition that accompanies an AnimeTheme.
|
||||
|
||||
For example, Staple Stable is the song for the Bakemonogatari OP1 AnimeTheme.
|
||||
"""
|
||||
type Song {
|
||||
"The primary key of the resource"
|
||||
id: Int! @rename(attribute: "song_id")
|
||||
"The name of the composition"
|
||||
title: String
|
||||
animethemes: [AnimeTheme] @hasMany
|
||||
performances: [Performance] @hasMany
|
||||
resources: ExternalResourceConnection! @belongsToMany(type: CONNECTION)
|
||||
"The date that the resource was created"
|
||||
createdAt: DateTimeTz @rename(attribute: "created_at")
|
||||
"The date that the resource was last modified"
|
||||
updatedAt: DateTimeTz @rename(attribute: "updated_at")
|
||||
"The date that the resource was deleted"
|
||||
deletedAt: DateTimeTz @rename(attribute: "deleted_at")
|
||||
}
|
||||
|
||||
"Default edge to use in simple belongs to many relationships"
|
||||
type SongEdge {
|
||||
node: Song!
|
||||
"The date that the resource was last modified"
|
||||
createdAt: DateTimeTz @field(resolver: "App\\GraphQL\\Resolvers\\PivotResolver@resolve")
|
||||
"The date that the resource was deleted"
|
||||
updatedAt: DateTimeTz @field(resolver: "App\\GraphQL\\Resolvers\\PivotResolver@resolve")
|
||||
}
|
||||
|
||||
enum SongColumnsOrderable {
|
||||
ID @enum(value: "song_id")
|
||||
TITLE
|
||||
CREATED_AT
|
||||
UPDATED_AT
|
||||
DELETED_AT
|
||||
}
|
||||
|
||||
extend type Query {
|
||||
"Returns a listing of song resources given fields."
|
||||
songs(
|
||||
title: String @eq
|
||||
createdAt_lesser: DateTimeTz @where(key: "created_at", operator: "<")
|
||||
createdAt_greater: DateTimeTz @where(key: "created_at", operator: ">")
|
||||
updatedAt_lesser: DateTimeTz @where(key: "updated_at", operator: "<")
|
||||
updatedAt_greater: DateTimeTz @where(key: "updated_at", operator: ">")
|
||||
deletedAt_lesser: DateTimeTz @where(key: "deleted_at", operator: "<")
|
||||
deletedAt_greater: DateTimeTz @where(key: "deleted_at", operator: ">")
|
||||
orderBy: _ @orderBy(columnsEnum: "SongColumnsOrderable")
|
||||
): [Song!]!
|
||||
@canModel(ability: "viewAny", injectArgs: true)
|
||||
@softDeletes
|
||||
@paginate
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
"""
|
||||
Represents a company that produces anime.
|
||||
|
||||
For example, Shaft is the studio that produced the anime Bakemonogatari.
|
||||
"""
|
||||
type Studio {
|
||||
"The primary key of the resource"
|
||||
id: Int! @rename(attribute: "studio_id")
|
||||
"The primary title of the studio"
|
||||
name: String!
|
||||
"The URL slug & route key of the resource"
|
||||
slug: String!
|
||||
anime: [Anime] @belongsToMany(type: CONNECTION)
|
||||
images: [Image] @belongsToMany(type: CONNECTION)
|
||||
resources: [ExternalResource] @belongsToMany(type: CONNECTION)
|
||||
"The date that the resource was created"
|
||||
createdAt: DateTimeTz @rename(attribute: "created_at")
|
||||
"The date that the resource was last modified"
|
||||
updatedAt: DateTimeTz @rename(attribute: "updated_at")
|
||||
"The date that the resource was deleted"
|
||||
deletedAt: DateTimeTz @rename(attribute: "deleted_at")
|
||||
}
|
||||
|
||||
"Default edge to use in simple belongs to many relationships"
|
||||
type StudioEdge {
|
||||
node: Studio!
|
||||
"The date that the resource was last modified"
|
||||
createdAt: DateTimeTz @field(resolver: "App\\GraphQL\\Resolvers\\PivotResolver@resolve")
|
||||
"The date that the resource was deleted"
|
||||
updatedAt: DateTimeTz @field(resolver: "App\\GraphQL\\Resolvers\\PivotResolver@resolve")
|
||||
}
|
||||
|
||||
enum StudioColumnsOrderable {
|
||||
ID @enum(value: "studio_id")
|
||||
NAME
|
||||
SLUG
|
||||
CREATED_AT
|
||||
UPDATED_AT
|
||||
DELETED_AT
|
||||
}
|
||||
|
||||
extend type Query {
|
||||
"Returns a listing of studio resources given fields."
|
||||
studios(
|
||||
createdAt_lesser: DateTimeTz @where(key: "created_at", operator: "<")
|
||||
createdAt_greater: DateTimeTz @where(key: "created_at", operator: ">")
|
||||
updatedAt_lesser: DateTimeTz @where(key: "updated_at", operator: "<")
|
||||
updatedAt_greater: DateTimeTz @where(key: "updated_at", operator: ">")
|
||||
deletedAt_lesser: DateTimeTz @where(key: "deleted_at", operator: "<")
|
||||
deletedAt_greater: DateTimeTz @where(key: "deleted_at", operator: ">")
|
||||
orderBy: _ @orderBy(columnsEnum: "StudioColumnsOrderable")
|
||||
): [Studio!]!
|
||||
@canModel(ability: "viewAny", injectArgs: true)
|
||||
@softDeletes
|
||||
@paginate
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
"""
|
||||
Represents a WebM of an anime theme.
|
||||
|
||||
For example, the video Bakemonogatari-OP1.webm represents the WebM of the Bakemonogatari OP1 theme.
|
||||
"""
|
||||
type Video {
|
||||
"The primary key of the resource"
|
||||
id: Int! @rename(attribute: "video_id")
|
||||
"The basename of the file in storage"
|
||||
basename: String!
|
||||
"The filename of the file in storage"
|
||||
filename: String!
|
||||
"Does the video include subtitles of song lyrics?"
|
||||
lyrics: Boolean!
|
||||
"The media type of the file in storage"
|
||||
mimetype: String
|
||||
"Is the video creditless?"
|
||||
nc: Boolean!
|
||||
"The degree to which the sequence and episode content overlap"
|
||||
overlap: VideoOverlap @localizedEnum
|
||||
"The path of the file in storage"
|
||||
path: String!
|
||||
"The frame height of the file in storage"
|
||||
resolution: Int
|
||||
"The size of the file in storage in Bytes"
|
||||
size: Int
|
||||
"Where did this video come from?"
|
||||
source: VideoSource @localizedEnum
|
||||
"Does the video include subtitles of dialogue?"
|
||||
subbed: Boolean!
|
||||
"Is the video an uncensored version of a censored sequence?"
|
||||
uncen: Boolean!
|
||||
"The attributes used to distinguish the file within the context of a theme"
|
||||
tags: String @field(resolver: "App\\GraphQL\\Resolvers\\ImplodeArrayResolver@resolve")
|
||||
"The URL to stream the file from storage"
|
||||
link: String!
|
||||
"The number of views recorded for the resource"
|
||||
viewsCount: Int! @with(relation: "viewAggregate") @field(resolver: "App\\GraphQL\\Resolvers\\ViewsCountResolver@resolve")
|
||||
animethemeentries: [AnimeThemeEntry] @belongsToMany(type: CONNECTION)
|
||||
videoscript: VideoScript @hasOne
|
||||
"The date that the resource was created"
|
||||
createdAt: DateTimeTz @rename(attribute: "created_at")
|
||||
"The date that the resource was last modified"
|
||||
updatedAt: DateTimeTz @rename(attribute: "updated_at")
|
||||
"The date that the resource was deleted"
|
||||
deletedAt: DateTimeTz @rename(attribute: "deleted_at")
|
||||
}
|
||||
|
||||
"Default edge to use in simple belongs to many relationships"
|
||||
type VideoEdge {
|
||||
node: Video!
|
||||
"The date that the resource was last modified"
|
||||
createdAt: DateTimeTz @field(resolver: "App\\GraphQL\\Resolvers\\PivotResolver@resolve")
|
||||
"The date that the resource was deleted"
|
||||
updatedAt: DateTimeTz @field(resolver: "App\\GraphQL\\Resolvers\\PivotResolver@resolve")
|
||||
}
|
||||
|
||||
enum VideoColumnsOrderable {
|
||||
ID @enum(value: "video_id")
|
||||
FILENAME
|
||||
BASENAME
|
||||
LYRICS
|
||||
NC
|
||||
OVERLAP
|
||||
RESOLUTION
|
||||
SIZE
|
||||
SOURCE
|
||||
SUBBED
|
||||
TAGS
|
||||
UNCEN
|
||||
CREATED_AT
|
||||
UPDATED_AT
|
||||
DELETED_AT
|
||||
}
|
||||
|
||||
extend type Query {
|
||||
"Returns a listing of video resources given fields."
|
||||
videos(
|
||||
isLyrics: Boolean @eq
|
||||
isNc: Boolean @eq
|
||||
isSubbed: Boolean @eq
|
||||
isUncen: Boolean @eq
|
||||
overlap: [VideoOverlap] @in
|
||||
source: [VideoSource] @in
|
||||
resolution_in: [Int] @in(key: "resolution")
|
||||
resolution_lesser: Int @where(key: "resolution", operator: "<")
|
||||
resolution_greater: Int @where(key: "resolution", operator: ">")
|
||||
size_lesser: Int @where(key: "size", operator: "<")
|
||||
size_greater: Int @where(key: "size", operator: ">")
|
||||
createdAt_lesser: DateTimeTz @where(key: "created_at", operator: "<")
|
||||
createdAt_greater: DateTimeTz @where(key: "created_at", operator: ">")
|
||||
updatedAt_lesser: DateTimeTz @where(key: "updated_at", operator: "<")
|
||||
updatedAt_greater: DateTimeTz @where(key: "updated_at", operator: ">")
|
||||
deletedAt_lesser: DateTimeTz @where(key: "deleted_at", operator: "<")
|
||||
deletedAt_greater: DateTimeTz @where(key: "deleted_at", operator: ">")
|
||||
orderBy: _ @orderBy(columnsEnum: "VideoColumnsOrderable")
|
||||
): [Video!]!
|
||||
@canModel(ability: "viewAny", injectArgs: true)
|
||||
@softDeletes
|
||||
@paginate
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
"A datetime and timezone string in ISO 8601 format `Y-m-dTH:i:sP`, e.g. `2020-04-20T13:53:12+02:00`."
|
||||
scalar DateTimeTz @scalar(class: "Nuwave\\Lighthouse\\Schema\\Types\\Scalars\\DateTimeTz")
|
||||
|
||||
"Indicates what fields are available at the top level of a query operation."
|
||||
type Query @middleware(class: "App\\GraphQL\\Middleware\\MaxCount") {
|
||||
"Returns a listing of resources that match a given search term."
|
||||
search(search: String @search, perPage: Int, page: Int): Search!
|
||||
@field(resolver: "App\\GraphQL\\Queries\\Search")
|
||||
}
|
||||
|
||||
type Search {
|
||||
anime: [Anime!]!
|
||||
artists: [Artist!]!
|
||||
animethemes: [AnimeTheme!]!
|
||||
playlists: [Playlist!]!
|
||||
series: [Series!]!
|
||||
songs: [Song!]!
|
||||
studios: [Studio!]!
|
||||
videos: [Video!]!
|
||||
}
|
||||
|
||||
type MessageResponse {
|
||||
message: String
|
||||
}
|
||||
|
||||
input WhereHasConditions {
|
||||
relation: String!
|
||||
where: [WhereConditions!]
|
||||
AND: [WhereHasConditions!]
|
||||
OR: [WhereHasConditions!]
|
||||
}
|
||||
|
||||
#import Admin/*.graphql
|
||||
#import Auth/*.graphql
|
||||
#import Document/*.graphql
|
||||
#import List/*.graphql
|
||||
#import List/External/*.graphql
|
||||
#import List/Playlist/*.graphql
|
||||
#import User/*.graphql
|
||||
#import Wiki/*.graphql
|
||||
#import Wiki/Anime/*.graphql
|
||||
#import Wiki/Anime/Theme/*.graphql
|
||||
#import Wiki/Song/*.graphql
|
||||
#import Wiki/Video/*.graphql
|
||||
|
||||
#import Pivot/List/*.graphql
|
||||
#import Pivot/Wiki/*.graphql
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\GraphQL\Types\Definition;
|
||||
|
||||
use Attribute;
|
||||
|
||||
#[Attribute(Attribute::TARGET_ALL)]
|
||||
class Hidden
|
||||
{
|
||||
public function __construct(
|
||||
public bool $hidden = true,
|
||||
) {}
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\GraphQL\Types;
|
||||
|
||||
use App\GraphQL\Types\Definition\Hidden;
|
||||
use Exception;
|
||||
use GraphQL\Language\AST\EnumTypeDefinitionNode;
|
||||
use GraphQL\Type\Definition\Deprecated;
|
||||
use GraphQL\Type\Definition\Description;
|
||||
use GraphQL\Type\Definition\EnumType as BaseEnumType;
|
||||
use GraphQL\Utils\PhpDoc;
|
||||
use ReflectionClass;
|
||||
use ReflectionClassConstant;
|
||||
use UnitEnum;
|
||||
|
||||
/**
|
||||
* Class EnumType
|
||||
*/
|
||||
class EnumType extends BaseEnumType
|
||||
{
|
||||
public const MULTIPLE_DESCRIPTIONS_DISALLOWED = 'Using more than 1 Description attribute is not supported.';
|
||||
public const MULTIPLE_DEPRECATIONS_DISALLOWED = 'Using more than 1 Deprecated attribute is not supported.';
|
||||
|
||||
/**
|
||||
* The enum class.
|
||||
*
|
||||
* @var class-string<UnitEnum>
|
||||
*/
|
||||
protected string $enumClass;
|
||||
|
||||
public function __construct(
|
||||
string $enumClass,
|
||||
?string $name = null,
|
||||
?string $description = null,
|
||||
?EnumTypeDefinitionNode $astNode = null,
|
||||
?array $extensionASTNodes = null
|
||||
) {
|
||||
$this->enumClass = $enumClass;
|
||||
$reflection = new \ReflectionEnum($enumClass);
|
||||
|
||||
$enumDefinitions = [];
|
||||
foreach ($enumClass::cases() as $case) {
|
||||
if ($this->hidden($reflection->getCase($case->name))) {
|
||||
continue;
|
||||
}
|
||||
$enumDefinitions[$case->name] = [
|
||||
'value' => $case->value,
|
||||
'description' => $this->extractDescription($reflection->getCase($case->name)),
|
||||
'deprecationReason' => $this->deprecationReason($reflection->getCase($case->name)),
|
||||
];
|
||||
}
|
||||
|
||||
parent::__construct([
|
||||
'name' => $name ?? $this->baseName($enumClass),
|
||||
'values' => $enumDefinitions,
|
||||
'description' => $description ?? $this->extractDescription($reflection),
|
||||
'astNode' => $astNode,
|
||||
'extensionASTNodes' => $extensionASTNodes,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $value
|
||||
* @return string
|
||||
*/
|
||||
public function serialize($value): string
|
||||
{
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param class-string $class
|
||||
* @return string
|
||||
*/
|
||||
protected function baseName(string $class): string
|
||||
{
|
||||
$parts = explode('\\', $class);
|
||||
|
||||
return end($parts);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ReflectionClassConstant|ReflectionClass<UnitEnum> $reflection
|
||||
* @return string|null
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function extractDescription(ReflectionClassConstant|ReflectionClass $reflection): ?string
|
||||
{
|
||||
$attributes = $reflection->getAttributes(Description::class);
|
||||
|
||||
if (count($attributes) === 1) {
|
||||
return $attributes[0]->newInstance()->description;
|
||||
}
|
||||
|
||||
if (count($attributes) > 1) {
|
||||
throw new Exception(self::MULTIPLE_DESCRIPTIONS_DISALLOWED);
|
||||
}
|
||||
|
||||
$comment = $reflection->getDocComment();
|
||||
$unpadded = PhpDoc::unpad($comment);
|
||||
|
||||
return PhpDoc::unwrap($unpadded);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ReflectionClassConstant $reflection
|
||||
* @return string|null
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function deprecationReason(ReflectionClassConstant $reflection): ?string
|
||||
{
|
||||
$attributes = $reflection->getAttributes(Deprecated::class);
|
||||
|
||||
if (count($attributes) === 1) {
|
||||
return $attributes[0]->newInstance()->reason;
|
||||
}
|
||||
|
||||
if (count($attributes) > 1) {
|
||||
throw new Exception(self::MULTIPLE_DEPRECATIONS_DISALLOWED);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the enum case should be hidden.
|
||||
*
|
||||
* @param ReflectionClassConstant $reflection
|
||||
* @return bool
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function hidden(ReflectionClassConstant $reflection): bool
|
||||
{
|
||||
$attributes = $reflection->getAttributes(Hidden::class);
|
||||
|
||||
if (count($attributes) === 1) {
|
||||
return $attributes[0]->newInstance()->hidden;
|
||||
}
|
||||
|
||||
if (count($attributes) > 1) {
|
||||
throw new Exception(self::MULTIPLE_DESCRIPTIONS_DISALLOWED);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\GraphQL\Validators\Mutation\List;
|
||||
|
||||
use App\Enums\Models\List\PlaylistVisibility;
|
||||
use App\Models\List\Playlist;
|
||||
use App\Rules\ModerationRule;
|
||||
use Illuminate\Validation\Rules\Enum;
|
||||
use Nuwave\Lighthouse\Validation\Validator;
|
||||
|
||||
/**
|
||||
* Class CreatePlaylistValidator.
|
||||
*/
|
||||
class CreatePlaylistValidator extends Validator
|
||||
{
|
||||
/**
|
||||
* Specify validation rules for the arguments.
|
||||
*
|
||||
* @return array<string, array<int, mixed>>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
Playlist::ATTRIBUTE_NAME => [
|
||||
'required',
|
||||
'string',
|
||||
'max:192',
|
||||
new ModerationRule(),
|
||||
],
|
||||
Playlist::ATTRIBUTE_DESCRIPTION => [
|
||||
'nullable',
|
||||
'string',
|
||||
'max:1000',
|
||||
new ModerationRule(),
|
||||
],
|
||||
Playlist::ATTRIBUTE_VISIBILITY => [
|
||||
'required',
|
||||
new Enum(PlaylistVisibility::class),
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user