Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions app/Api/RouteServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ private function apiRoutes(): void
->only('index', 'show')
->readOnly()
->relationships(function ($relationships) {
$relationships->hasMany('comments')->readOnly();
$relationships->hasMany('playerAchievements')->readOnly();
});

Expand All @@ -128,6 +129,7 @@ private function apiRoutes(): void
->only('index', 'show')
->readOnly()
->relationships(function ($relationships) {
$relationships->hasMany('comments')->readOnly();
$relationships->hasMany('hashes')->readOnly();
});

Expand Down Expand Up @@ -158,6 +160,7 @@ private function apiRoutes(): void
$relationships->hasMany('playerAchievements')->readOnly();
$relationships->hasMany('playerAchievementSets')->readOnly();
$relationships->hasMany('playerGames')->readOnly();
$relationships->hasMany('wallComments')->readOnly();
});
});
});
Expand Down
1 change: 1 addition & 0 deletions app/Api/V2/Achievements/AchievementSchema.php
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ public function fields(): array
BelongsTo::make('developer')->type('users')->readOnly(),

HasOne::make('achievementSet')->type('achievement-sets')->readOnly(),
HasMany::make('comments', 'visibleComments')->type('comments')->cannotEagerLoad()->readOnly(),
HasMany::make('games')->type('games')->readOnly(),
HasMany::make('playerAchievements')->type('player-achievements')->cannotEagerLoad()->readOnly(),

Expand Down
65 changes: 65 additions & 0 deletions app/Api/V2/Comments/CommentResource.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<?php

declare(strict_types=1);

namespace App\Api\V2\Comments;

use App\Api\V2\BaseJsonApiResource;
use App\Models\Comment;
use App\Models\User;
use Illuminate\Http\Request;
use LaravelJsonApi\Core\Document\Links;

/**
* @property Comment $resource
*/
class CommentResource extends BaseJsonApiResource
{
/**
* Get the resource's attributes.
*
* @param Request|null $request
*/
public function attributes($request): iterable
{
return [
'authorAvatarUrl' => $this->authorAvatarUrl(),
'authorDisplayName' => $this->resource->getAttribute('author_display_name') ?? $this->resource->user->display_name,
'authorId' => $this->resource->getAttribute('author_ulid') ?? $this->resource->user->ulid,
'body' => $this->resource->body,
'permalink' => $this->resource->url,
'submittedAt' => $this->resource->created_at,
];
}

/**
* Get the resource's relationships.
*
* @param Request|null $request
*/
public function relationships($request): iterable
{
return [
'author' => $this->relation('author', 'user')->withoutLinks()->showDataIfLoaded(),
];
}

/**
* @param Request|null $request
*/
public function links($request): Links
{
return new Links();
}

private function authorAvatarUrl(): string
{
$authorUsername = $this->resource->getAttribute('author_username');

if ($authorUsername) {
return (new User(['username' => $authorUsername]))->avatar_url;
}

return $this->resource->user->avatar_url;
}
}
97 changes: 97 additions & 0 deletions app/Api/V2/Comments/CommentSchema.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
<?php

declare(strict_types=1);

namespace App\Api\V2\Comments;

use App\Models\Comment;
use App\Models\User;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Http\Request;
use LaravelJsonApi\Eloquent\Contracts\Paginator;
use LaravelJsonApi\Eloquent\Fields\DateTime;
use LaravelJsonApi\Eloquent\Fields\ID;
use LaravelJsonApi\Eloquent\Fields\Relations\BelongsTo;
use LaravelJsonApi\Eloquent\Fields\Str;
use LaravelJsonApi\Eloquent\Filters\WhereIdIn;
use LaravelJsonApi\Eloquent\Pagination\PagePagination;
use LaravelJsonApi\Eloquent\Schema;

class CommentSchema extends Schema
{
/**
* The model the schema corresponds to.
*/
public static string $model = Comment::class;

/**
* Default pagination parameters when client doesn't provide any.
* This prevents unbounded result sets.
*/
protected ?array $defaultPagination = ['number' => 1];

/**
* Default sort order when client doesn't provide any.
*/
protected $defaultSort = 'submittedAt';

/**
* Get the resource type.
*/
public static function type(): string
{
return 'comments';
}

/**
* Get the resource fields.
*/
public function fields(): array
{
return [
ID::make(),

Str::make('body')->readOnly(),
Str::make('authorAvatarUrl')->readOnly(),
Str::make('authorDisplayName')->readOnly(),
Str::make('authorId')->readOnly(),
Str::make('permalink')->readOnly(),
DateTime::make('submittedAt', 'created_at')->sortable()->readOnly(),

BelongsTo::make('author', 'user')->type('users')->readOnly(),
];
}

/**
* Get the resource filters.
*/
public function filters(): array
{
return [
WhereIdIn::make($this),
];
}

/**
* Get the resource paginator.
*/
public function pagination(): ?Paginator
{
return PagePagination::make()
->withDefaultPerPage(50);
}

/**
* @param Relation<Comment, User, mixed> $query
* @return Relation<Comment, User, mixed>
*/
public function relatableQuery(?Request $request, Relation $query): Relation
{
return $query
->notAutomated()
->whereHas('user')
->withAggregate('user as author_display_name', 'display_name')
->withAggregate('user as author_username', 'username')
->withAggregate('user as author_ulid', 'ulid');
}
}
30 changes: 30 additions & 0 deletions app/Api/V2/Controllers/UserController.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
use App\Api\V2\UserAwards\UserAwardKind;
use App\Models\PlayerBadge;
use App\Models\User;
use App\Policies\UserCommentPolicy;
use LaravelJsonApi\Core\Exceptions\JsonApiException;
use LaravelJsonApi\Core\Pagination\Page;
use LaravelJsonApi\Core\Responses\RelatedResponse;
use LaravelJsonApi\Laravel\Http\Controllers\Actions;
Expand Down Expand Up @@ -57,4 +59,32 @@ protected function readRelatedAwards(
->withMeta($meta)
->withQueryParameters($request);
}

protected function readingWallComments(
User $user,
ResourceQuery $request,
): void {
$this->abortIfWallCommentsAreHidden($user, $request);
}

protected function readingRelatedWallComments(
User $user,
ResourceQuery $request,
): void {
$this->abortIfWallCommentsAreHidden($user, $request);
}

private function abortIfWallCommentsAreHidden(User $user, ResourceQuery $request): void
{
if ((new UserCommentPolicy())->viewAny($request->user(), $user)) {
return;
}

throw JsonApiException::error([
'status' => '404',
'code' => 'not_found',
'title' => 'Not Found',
'detail' => "No comments found for user {$user->display_name}.",
]);
}
}
1 change: 1 addition & 0 deletions app/Api/V2/Games/GameSchema.php
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ public function fields(): array
BelongsTo::make('system')->readOnly(),

BelongsToMany::make('achievementSets')->readOnly(),
HasMany::make('comments', 'visibleComments')->type('comments')->cannotEagerLoad()->readOnly(),
HasMany::make('hashes')->type('game-hashes')->readOnly(),

// TODO implement relationship endpoints to enable links
Expand Down
1 change: 1 addition & 0 deletions app/Api/V2/Server.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ protected function allSchemas(): array
return [
Achievements\AchievementSchema::class,
AchievementSets\AchievementSetSchema::class,
Comments\CommentSchema::class,
EventAwards\EventAwardSchema::class,
Events\EventSchema::class,
GameHashes\GameHashSchema::class,
Expand Down
2 changes: 1 addition & 1 deletion app/Api/V2/Users/UserSchema.php
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ public function fields(): array
HasMany::make('playerAchievements')->type('player-achievements')->cannotEagerLoad()->readOnly(),
HasMany::make('playerAchievementSets')->type('player-achievement-sets')->cannotEagerLoad()->readOnly(),
HasMany::make('playerGames')->type('player-games')->cannotEagerLoad()->readOnly(),
HasMany::make('wallComments', 'visibleComments')->type('comments')->cannotEagerLoad()->readOnly(),
HasMany::make('awards', 'playerBadges')
->type('user-awards')
->cannotEagerLoad()
Expand All @@ -116,7 +117,6 @@ public function fields(): array
// - followers (BelongsToMany User) - users following this user
// - authoredAchievements (HasMany Achievement)
// - claims (HasMany AchievementSetClaim)
// - wall comments (HasMany Comment, commentable_type=user.comment, commentable_id=self)
];
}

Expand Down
5 changes: 5 additions & 0 deletions app/Policies/AchievementPolicy.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,11 @@ public function view(?User $user, Achievement $achievement): bool
return true;
}

public function viewComments(?User $user, Achievement $achievement): bool
{
return true;
}

public function viewPlayerAchievements(?User $user, Achievement $achievement): bool
{
return true;
Expand Down
5 changes: 5 additions & 0 deletions app/Policies/GamePolicy.php
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,11 @@ public function view(?User $user, Game $game): bool
return true;
}

public function viewComments(?User $user, Game $game): bool
{
return true;
}

public function viewHashes(?User $user, Game $game): bool
{
return true;
Expand Down
8 changes: 8 additions & 0 deletions app/Policies/UserPolicy.php
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,14 @@ public function viewPlayerGames(?User $user, User $model): bool
return true;
}

public function viewWallComments(?User $user, User $model): bool
{
// This is only to facilitate the V2 Web API.
// Disabled or banned walls are hidden by the V2 controller hooks so both
// related-resource and relationship-linkage routes return JSON:API 404s.
return true;
}

public function create(User $user): bool
{
// nobody creates users just like that.
Expand Down
Loading
Loading