Skip to content

Commit

Permalink
feat(hub): add support for content warnings (#2952)
Browse files Browse the repository at this point in the history
  • Loading branch information
wescopeland authored Dec 30, 2024
1 parent 4a96cf5 commit def5b3d
Show file tree
Hide file tree
Showing 35 changed files with 902 additions and 32 deletions.
17 changes: 17 additions & 0 deletions app/Community/Controllers/UserSettingsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,11 @@
use App\Data\UserData;
use App\Data\UserPermissionsData;
use App\Enums\Permissions;
use App\Enums\UserPreference;
use App\Http\Controller;
use App\Models\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Inertia\Inertia;
use Inertia\Response as InertiaResponse;
Expand Down Expand Up @@ -124,6 +126,21 @@ public function updateLocale(UpdateLocaleRequest $request): JsonResponse
return response()->json(['success' => true]);
}

// TODO migrate to $user->preferences blob
public function enableSuppressMatureContentWarning(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();

$currentPreferences = (int) $user->getAttribute('websitePrefs');
$newPreferences = $currentPreferences | (1 << UserPreference::Site_SuppressMatureContentWarning);

$user->websitePrefs = $newPreferences;
$user->save();

return response()->json(['success' => true]);
}

// TODO migrate to $user->preferences blob
public function updatePreferences(UpdateWebsitePrefsRequest $request): JsonResponse
{
Expand Down
3 changes: 3 additions & 0 deletions app/Community/RouteServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,9 @@ protected function mapWebRoutes(): void
'middleware' => ['auth'],
'prefix' => 'internal-api/settings',
], function () {
Route::patch('/preferences/content-warning', [UserSettingsController::class, 'enableSuppressMatureContentWarning'])
->name('api.settings.preferences.suppress-mature-content-warning');

Route::put('profile', [UserSettingsController::class, 'updateProfile'])->name('api.settings.profile.update');
Route::put('locale', [UserSettingsController::class, 'updateLocale'])->name('api.settings.locale.update');
Route::put('preferences', [UserSettingsController::class, 'updatePreferences'])->name('api.settings.preferences.update');
Expand Down
6 changes: 5 additions & 1 deletion app/Data/UserData.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,10 @@ public function __construct(
public Lazy|string|null $visibleRole = null,
public Lazy|int|null $websitePrefs = null,

#[TypeScriptType(['prefersAbsoluteDates' => 'boolean'])]
#[TypeScriptType([
'shouldAlwaysBypassContentWarnings' => 'boolean',
'prefersAbsoluteDates' => 'boolean',
])]
public Lazy|array|null $preferences = [],
#[LiteralTypeScriptType('App.Models.UserRole[]')]
public Lazy|array|null $roles = [],
Expand Down Expand Up @@ -82,6 +85,7 @@ public static function fromUser(User $user): self
motto: Lazy::create(fn () => $user->Motto),
preferences: Lazy::create(
fn () => [
'shouldAlwaysBypassContentWarnings' => $user->should_always_bypass_content_warnings,
'prefersAbsoluteDates' => $user->prefers_absolute_dates,
]
),
Expand Down
16 changes: 16 additions & 0 deletions app/Filament/Resources/HubResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use App\Filament\Resources\HubResource\RelationManagers\GamesRelationManager;
use App\Filament\Resources\HubResource\RelationManagers\ParentHubsRelationManager;
use App\Models\GameSet;
use App\Models\User;
use App\Platform\Enums\GameSetType;
use App\Support\Rules\NoEmoji;
use Filament\Forms;
Expand All @@ -20,6 +21,7 @@
use Filament\Tables;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\Auth;

class HubResource extends Resource
{
Expand Down Expand Up @@ -57,6 +59,11 @@ public static function infolist(Infolist $infolist): Infolist
Infolists\Components\TextEntry::make('title')
->label('Title'),

Infolists\Components\TextEntry::make('has_mature_content')
->label('Has Mature Content')
->formatStateUsing(fn (bool $state): string => $state ? 'Yes' : 'No')
->color(fn (bool $state): string => $state ? 'danger' : ''),

BreadcrumbPreview::make('breadcrumbs')
->label('Breadcrumb Preview')
->columnSpanFull(),
Expand All @@ -74,6 +81,9 @@ public static function infolist(Infolist $infolist): Infolist

public static function form(Form $form): Form
{
/** @var User $user */
$user = Auth::user();

return $form
->schema([
Forms\Components\Section::make('Primary Details')
Expand All @@ -85,6 +95,12 @@ public static function form(Form $form): Form
->minLength(2)
->maxLength(80)
->rules([new NoEmoji()]),

Forms\Components\Toggle::make('has_mature_content')
->label('Has Mature Content')
->helperText('CAUTION: If this is enabled, players will get a warning when opening any game in the hub!')
->default(false)
->visible(fn ($record) => $user->can('toggleHasMatureContent', $record)),
]),

Forms\Components\Section::make('Internal Notes')
Expand Down
5 changes: 5 additions & 0 deletions app/Models/Game.php
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,11 @@ public function getCanonicalUrlAttribute(): string
return route('game.show', [$this, $this->getSlugAttribute()]);
}

public function getHasMatureContentAttribute(): bool
{
return $this->gameSets()->where('has_mature_content', true)->exists();
}

public function getLastUpdatedAttribute(): Carbon
{
return $this->last_achievement_update ?? $this->Updated;
Expand Down
7 changes: 5 additions & 2 deletions app/Models/GameSet.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,15 @@ class GameSet extends BaseModel
'game_id',
'internal_notes',
'image_asset_path',
'has_mature_content',
'title',
'type',
'updated_at',
'user_id',
];

protected $casts = [
'has_mature_content' => 'boolean',
'type' => GameSetType::class,
];

Expand Down Expand Up @@ -148,9 +150,10 @@ public function getActivitylogOptions(): LogOptions
{
return LogOptions::defaults()
->logOnly([
'title',
'internal_notes',
'has_mature_content',
'image_asset_path',
'internal_notes',
'title',
])
->logOnlyDirty()
->dontSubmitEmptyLogs();
Expand Down
5 changes: 5 additions & 0 deletions app/Models/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,11 @@ public function getPermissionsAttribute(): int
return $this->attributes['Permissions'];
}

public function getShouldAlwaysBypassContentWarningsAttribute(): bool
{
return BitSet($this->getAttribute('websitePrefs'), UserPreference::Site_SuppressMatureContentWarning);
}

public function getPrefersAbsoluteDatesAttribute(): bool
{
return BitSet($this->getAttribute('websitePrefs'), UserPreference::Forum_ShowAbsoluteDates);
Expand Down
1 change: 1 addition & 0 deletions app/Platform/Actions/BuildGameSetRelatedHubsAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ public function execute(GameSet $gameSet): array
'title',
'image_asset_path',
'type',
'has_mature_content',
'updated_at',
])
->withCount([
Expand Down
4 changes: 3 additions & 1 deletion app/Platform/Actions/BuildHubBreadcrumbsAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use App\Models\GameSet;
use App\Platform\Data\GameSetData;
use App\Platform\Enums\GameSetType;
use Carbon\Carbon;
use Illuminate\Support\Facades\Cache;

/**
Expand Down Expand Up @@ -163,7 +164,8 @@ public function execute(GameSet $gameSet): array
badgeUrl: media_asset($data['image_asset_path']),
gameCount: 0,
linkCount: 0,
updatedAt: new \Carbon\Carbon($data['updated_at']),
updatedAt: new Carbon($data['updated_at']),
hasMatureContent: false, // doesn't matter, this is just a breadcrumb
),
$cachedData ?? [],
);
Expand Down
2 changes: 1 addition & 1 deletion app/Platform/Controllers/HubController.php
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ public function show(GameListRequest $request, ?GameSet $gameSet): InertiaRespon
$can = UserPermissionsData::fromUser($user)->include('develop', 'manageGameSets');

$props = new HubPagePropsData(
hub: GameSetData::from($gameSet)->include('title', 'badgeUrl', 'updatedAt'),
hub: GameSetData::from($gameSet)->include('title', 'badgeUrl', 'updatedAt', 'hasMatureContent'),
relatedHubs: (new BuildGameSetRelatedHubsAction())->execute($gameSet),
breadcrumbs: (new BuildHubBreadcrumbsAction())->execute($gameSet),
paginatedGameListEntries: $paginatedData,
Expand Down
3 changes: 3 additions & 0 deletions app/Platform/Data/GameSetData.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use App\Platform\Enums\GameSetType;
use Carbon\Carbon;
use Spatie\LaravelData\Data;
use Spatie\LaravelData\Lazy;
use Spatie\TypeScriptTransformer\Attributes\TypeScript;

#[TypeScript('GameSet')]
Expand All @@ -21,6 +22,7 @@ public function __construct(
public int $gameCount,
public int $linkCount,
public Carbon $updatedAt,
public Lazy|bool $hasMatureContent,
) {
}

Expand All @@ -37,6 +39,7 @@ public static function fromGameSetWithCounts(GameSet $gameSet): self
gameCount: $gameSet->games_count ?? 0,
linkCount: $gameSet->link_count ?? 0,
updatedAt: $gameSet->updated_at,
hasMatureContent: Lazy::create(fn () => $gameSet->has_mature_content),
);
}
}
8 changes: 8 additions & 0 deletions app/Policies/GameSetPolicy.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,12 @@ public function forceDelete(User $user, GameSet $gameSet): bool
{
return false;
}

public function toggleHasMatureContent(User $user, GameSet $gameSet): bool
{
return $user->hasAnyRole([
Role::ADMINISTRATOR,
Role::DEVELOPER_STAFF,
]);
}
}
23 changes: 23 additions & 0 deletions database/migrations/2024_12_18_000000_update_game_sets_tables.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

declare(strict_types=1);

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class() extends Migration {
public function up(): void
{
Schema::table('game_sets', function (Blueprint $table) {
$table->boolean('has_mature_content')->default(false)->after('definition');
});
}

public function down(): void
{
Schema::table('game_sets', function (Blueprint $table) {
$table->dropColumn('has_mature_content');
});
}
};
7 changes: 6 additions & 1 deletion lang/en_US.json
Original file line number Diff line number Diff line change
Expand Up @@ -512,5 +512,10 @@
"Remember my view": "Remember my view",
"Moderation Comments - {{user}}": "Moderation Comments - {{user}}",
"Moderation Comments": "Moderation Comments",
"Columns": "Columns"
"Mature Content Warning": "Mature Content Warning",
"This page may contain content that is not appropriate for all ages.": "This page may contain content that is not appropriate for all ages.",
"Are you sure you want to view this page?": "Are you sure you want to view this page?",
"Yes, and don't ask again": "Yes, and don't ask again",
"Columns": "Columns",
"Yes, I'm an adult": "Yes, I'm an adult"
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"@floating-ui/dom": "^1.5.1",
"@hookform/resolvers": "^3.9.0",
"@inertiajs/core": "^1.2.0",
"@radix-ui/react-alert-dialog": "^1.1.4",
"@radix-ui/react-checkbox": "^1.1.1",
"@radix-ui/react-dialog": "^1.1.2",
"@radix-ui/react-dropdown-menu": "^2.1.1",
Expand Down
Loading

0 comments on commit def5b3d

Please sign in to comment.