diff --git a/.github/actions/tasks/install-composer-deps/action.yml b/.github/actions/install-composer-deps/action.yml similarity index 100% rename from .github/actions/tasks/install-composer-deps/action.yml rename to .github/actions/install-composer-deps/action.yml diff --git a/.github/actions/tasks/install-npm-deps/action.yml b/.github/actions/install-npm-deps/action.yml similarity index 100% rename from .github/actions/tasks/install-npm-deps/action.yml rename to .github/actions/install-npm-deps/action.yml diff --git a/.github/actions/tasks/install-php/action.yml b/.github/actions/install-php/action.yml similarity index 100% rename from .github/actions/tasks/install-php/action.yml rename to .github/actions/install-php/action.yml diff --git a/.github/actions/recipes/deploy/action.yml b/.github/actions/recipes/deploy/action.yml deleted file mode 100644 index 4b3703bbf..000000000 --- a/.github/actions/recipes/deploy/action.yml +++ /dev/null @@ -1,33 +0,0 @@ -name: Deploy -description: Deploys the current branch to the web server - -inputs: - keep-releases: - description: "Max number of releases stored (for rollback purposes)" - required: true - branch: - description: "Name of git branch to deploy" - required: true - -runs: - using: composite - steps: - - name: Install PHP - uses: ./.github/actions/tasks/install-php - - - name: Install Composer dependencies - shell: bash - run: composer install - - - name: Deploy - uses: deployphp/action@6242095e7207facf115ac4439760356bc52760ac - env: - DEPLOY_BRANCH: ${{ inputs.branch }} - DEPLOY_HOST: ${{ env.DEPLOY_HOST }} - DEPLOY_USER: ${{ env.DEPLOY_USER }} - DEPLOY_PATH: ${{ env.DEPLOY_PATH }} - DEPLOY_DISCORD_CHANNEL_ID: ${{ env.DEPLOY_DISCORD_CHANNEL_ID }} - DEPLOY_DISCORD_CHANNEL_TOKEN: ${{ env.DEPLOY_DISCORD_CHANNEL_TOKEN }} - with: - private-key: ${{ env.DEPLOY_PRIVATE_KEY }} - dep: "deploy -o keep_releases=${{ inputs.keep-releases }}" diff --git a/.github/workflows/__deploy.yml b/.github/workflows/__deploy.yml new file mode 100644 index 000000000..463a7fc0f --- /dev/null +++ b/.github/workflows/__deploy.yml @@ -0,0 +1,41 @@ +name: Deploy + +on: + workflow_call: + inputs: + branch: + required: true + type: string + keep-releases: + required: true + type: number + environment: + required: true + type: string + +jobs: + deploy: + runs-on: ubuntu-latest + environment: ${{ inputs.environment }} + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + + - name: Install PHP + uses: ./.github/actions/install-php + + - name: Install Composer dependencies + run: composer install + + - name: Deploy ${{ inputs.branch }} branch + uses: deployphp/action@6242095e7207facf115ac4439760356bc52760ac + env: + DEPLOY_BRANCH: ${{ inputs.branch }} + DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }} + DEPLOY_USER: ${{ secrets.DEPLOY_USER }} + DEPLOY_PATH: ${{ secrets.DEPLOY_PATH }} + DEPLOY_DISCORD_CHANNEL_ID: ${{ secrets.DEPLOY_DISCORD_CHANNEL_ID }} + DEPLOY_DISCORD_CHANNEL_TOKEN: ${{ secrets.DEPLOY_DISCORD_CHANNEL_TOKEN }} + with: + private-key: ${{ secrets.DEPLOY_PRIVATE_KEY }} + dep: "deploy -o keep_releases=${{ inputs.keep-releases }}" + diff --git a/.github/workflows/deploy-dev.yml b/.github/workflows/deploy-dev.yml index a30a766bc..23ea48daf 100644 --- a/.github/workflows/deploy-dev.yml +++ b/.github/workflows/deploy-dev.yml @@ -12,21 +12,10 @@ concurrency: jobs: deploy: - runs-on: ubuntu-latest - environment: dev - steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - - - name: Deploy dev branch - uses: ./.github/actions/recipes/deploy - env: - DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }} - DEPLOY_USER: ${{ secrets.DEPLOY_USER }} - DEPLOY_PATH: ${{ secrets.DEPLOY_PATH }} - DEPLOY_PRIVATE_KEY: ${{ secrets.DEPLOY_PRIVATE_KEY }} - DEPLOY_DISCORD_CHANNEL_ID: ${{ secrets.DEPLOY_DISCORD_CHANNEL_ID }} - DEPLOY_DISCORD_CHANNEL_TOKEN: ${{ secrets.DEPLOY_DISCORD_CHANNEL_TOKEN }} - with: - branch: main - keep-releases: 3 + uses: ./.github/workflows/__deploy.yml + secrets: inherit + with: + environment: dev + branch: main + keep-releases: 3 diff --git a/.github/workflows/deploy-production.yml b/.github/workflows/deploy-production.yml index f06a6fdf6..914d74252 100644 --- a/.github/workflows/deploy-production.yml +++ b/.github/workflows/deploy-production.yml @@ -25,23 +25,12 @@ concurrency: jobs: deploy: - runs-on: ubuntu-latest - environment: production - steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - - - name: Deploy release branch - uses: ./.github/actions/recipes/deploy - env: - DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }} - DEPLOY_USER: ${{ secrets.DEPLOY_USER }} - DEPLOY_PATH: ${{ secrets.DEPLOY_PATH }} - DEPLOY_PRIVATE_KEY: ${{ secrets.DEPLOY_PRIVATE_KEY }} - DEPLOY_DISCORD_CHANNEL_ID: ${{ secrets.DEPLOY_DISCORD_CHANNEL_ID }} - DEPLOY_DISCORD_CHANNEL_TOKEN: ${{ secrets.DEPLOY_DISCORD_CHANNEL_TOKEN }} - with: - branch: release - keep-releases: 5 + uses: ./.github/workflows/__deploy.yml + secrets: inherit + with: + environment: production + branch: release + keep-releases: 5 tag: runs-on: ubuntu-latest diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d41942a97..82c67b095 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -10,7 +10,6 @@ concurrency: jobs: unit-test: runs-on: ubuntu-latest - services: mariadb: image: mariadb:11.0.5 @@ -26,21 +25,20 @@ jobs: --health-interval=10s --health-timeout=5s --health-retries=3 - steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - name: Install PHP - uses: ./.github/actions/tasks/install-php + uses: ./.github/actions/install-php - name: Install Composer dependencies - uses: ./.github/actions/tasks/install-composer-deps + uses: ./.github/actions/install-composer-deps - name: Prepare .env file run: cp .env.ci .env - name: Install npm dependencies - uses: ./.github/actions/tasks/install-npm-deps + uses: ./.github/actions/install-npm-deps - name: Calculate front-end asset hash id: get-assets-cache diff --git a/README.md b/README.md index 462e90edf..f0ed8b58d 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,6 @@

License: MPL 2.0 Build status - Linter status

--- diff --git a/app/Core/Domains/Environment/Environment.php b/app/Core/Domains/Environment/Environment.php index 2ae64d7cf..7376aca79 100644 --- a/app/Core/Domains/Environment/Environment.php +++ b/app/Core/Domains/Environment/Environment.php @@ -4,9 +4,7 @@ final class Environment { - private function __construct() - { - } + private function __construct() {} public static function getLevel(): EnvironmentLevel { diff --git a/app/Core/Domains/Mojang/Api/MojangPlayerApi.php b/app/Core/Domains/Mojang/Api/MojangPlayerApi.php deleted file mode 100644 index eaa0c5a5d..000000000 --- a/app/Core/Domains/Mojang/Api/MojangPlayerApi.php +++ /dev/null @@ -1,183 +0,0 @@ -client->request('GET', 'https://api.mojang.com/users/profiles/minecraft/'.$name, [ - 'query' => [ - 'at' => $time, - ], - ]); - } catch (ClientException $e) { - if ($e->getCode() === 429) { - throw new TooManyRequestsException('rate_limited', 'Too many requests sent to the Mojang API'); - } - throw $e; - } - - // if no player exists, return null - if ($response->getStatusCode() === 204) { - return null; - } - - $body = json_decode($response->getBody()); - - return new MojangPlayer( - $body->id, - $body->name, - isset($body->legacy), - isset($body->demo) - ); - } - - /** - * Retrieves the UUID for the person who first registered - * the given name, regardless of who currently owns it now. - * - * @param $name - * @return MojangPlayer - * @throws TooManyRequestsException - */ - public function getOriginalOwnerUuidOf(string $name): ?MojangPlayer - { - return $this->getUuidOf($name, 0); - } - - /** - * Retrieves UUIDs for every name in the given array, in a - * single lookup. - * - * The API only allows a max of 10 names per lookup. - * - * @return MinecraftPlayer[] - * @throws TooManyRequestsException - */ - public function getUuidBatchOf(array $names): ?array - { - if (count($names) === 0 || count($names) > 10) { - throw new \Exception('Batch must contain between 1 and 10 names to search'); - } - - // Just in case a dictionary was given to us, use only the values - $names = array_values($names); - - // Strip empty names from the batch or else the API will return an error - $names = array_filter($names, fn ($name) => ! empty($name)); - - $response = null; - try { - $response = $this->client->request('POST', 'https://api.mojang.com/profiles/minecraft', [ - 'json' => $names, - ]); - } catch (ClientException $e) { - if ($e->getCode() === 429) { - throw new TooManyRequestsException('rate_limited', 'Too many requests sent to the Mojang API'); - } - throw $e; - } - - $data = json_decode($response->getBody()); - if (count($data) === 0) { - return []; - } - - return collect($data) - ->keyBy(function ($player) { - return $player->name; - }) - ->map(function ($player) { - return new MojangPlayer( - str_replace('-', '', $player->id), - $player->name, - isset($body->legacy), - isset($body->demo) - ); - }) - ->toArray(); - } - - /** - * Returns all the usernames this user has used in the past and - * the one they are using currently. - * - * The UUID must be given without hyphens. - * - * @param $uuid - * @return array|null - * @throws TooManyRequestsException - */ - public function getNameHistoryOf($uuid): ?MojangPlayerNameHistory - { - $response = null; - try { - $response = $this->client->request('GET', 'https://api.mojang.com/user/profiles/'.$uuid.'/names'); - } catch (ClientException $e) { - if ($e->getCode() === 429) { - throw new TooManyRequestsException('rate_limited', 'Too many requests sent to the Mojang API'); - } - throw $e; - } - - // if no player exists, return null - if ($response->getStatusCode() === 204) { - return null; - } - - return new MojangPlayerNameHistory( - json_decode($response->getBody()) - ); - } - - /** - * Returns all the usernames this user has used in the past and - * the one they are using currently. - * - * Performs two lookups as the original API can only be queried using an UUID. - * - * @param $name - * @return array|null - * @throws TooManyRequestsException - */ - public function getNameHistoryByNameOf($name): ?MojangPlayerNameHistory - { - $player = $this->getUuidOf($name); - if ($player !== null) { - return $this->getNameHistoryOf($player->getUuid()); - } - - return null; - } -} diff --git a/app/Core/Domains/Mojang/Data/MojangPlayer.php b/app/Core/Domains/Mojang/Data/MojangPlayer.php deleted file mode 100644 index eb2e31192..000000000 --- a/app/Core/Domains/Mojang/Data/MojangPlayer.php +++ /dev/null @@ -1,46 +0,0 @@ -uuid; - } - - /** - * Player's in-game name. - */ - public function getAlias(): string - { - return $this->alias; - } - - /** - * Whether the account has not migrated to a Mojang account. - */ - public function isLegacyAccount(): bool - { - return $this->isLegacyAccount; - } - - /** - * Whether the account is a free account (ie. unpaid). - */ - public function isDemoAccount(): bool - { - return $this->isDemoAccount; - } -} diff --git a/app/Core/Domains/Mojang/Data/MojangPlayerNameChange.php b/app/Core/Domains/Mojang/Data/MojangPlayerNameChange.php deleted file mode 100644 index 126549de8..000000000 --- a/app/Core/Domains/Mojang/Data/MojangPlayerNameChange.php +++ /dev/null @@ -1,61 +0,0 @@ -alias = $alias; - $this->changedToAt = $changedToAt; - $this->isCurrent = $isCurrent; - } - - public function getAlias(): string - { - return $this->alias; - } - - public function getChangeDate(): ?int - { - if ($this->changedToAt !== null) { - return $this->changedToAt / 1000; - } - - return null; - } - - public function isCurrentAlias(): bool - { - return $this->isCurrent; - } - - public function isOriginalAlias(): bool - { - return $this->changedToAt === null; - } -} diff --git a/app/Core/Domains/Mojang/Data/MojangPlayerNameHistory.php b/app/Core/Domains/Mojang/Data/MojangPlayerNameHistory.php deleted file mode 100644 index 2b191c0ad..000000000 --- a/app/Core/Domains/Mojang/Data/MojangPlayerNameHistory.php +++ /dev/null @@ -1,34 +0,0 @@ - - */ - private $nameChanges = []; - - public function __construct(array $nameChanges) - { - for ($i = 0; $i < count($nameChanges); $i++) { - $nameChange = $nameChanges[$i]; - $this->nameChanges[] = new MojangPlayerNameChange( - $nameChange->name, - property_exists($nameChange, 'changedToAt') ? $nameChange->changedToAt : null, - $i + 1 === count($nameChanges) - ); - } - } - - /** - * @return array - */ - public function getNameChanges(): array - { - return $this->nameChanges; - } -} diff --git a/app/Domains/BanAppeals/Exceptions/EmailRequiredException.php b/app/Domains/BanAppeals/Exceptions/EmailRequiredException.php deleted file mode 100644 index a4c311ec9..000000000 --- a/app/Domains/BanAppeals/Exceptions/EmailRequiredException.php +++ /dev/null @@ -1,15 +0,0 @@ - __('validation.required', ['attribute' => 'email'])] - ); - } -} diff --git a/app/Domains/BanAppeals/UseCases/CreateBanAppeal.php b/app/Domains/BanAppeals/UseCases/CreateBanAppeal.php index 827a9efc1..988ab6e1d 100644 --- a/app/Domains/BanAppeals/UseCases/CreateBanAppeal.php +++ b/app/Domains/BanAppeals/UseCases/CreateBanAppeal.php @@ -3,7 +3,6 @@ namespace App\Domains\BanAppeals\UseCases; use App\Domains\BanAppeals\Data\BanAppealStatus; -use App\Domains\BanAppeals\Exceptions\EmailRequiredException; use App\Domains\BanAppeals\Notifications\BanAppealConfirmationNotification; use App\Models\Account; use App\Models\BanAppeal; @@ -11,36 +10,24 @@ final class CreateBanAppeal { - /** - * Returns whether an account owns the player associated with a ban - * - * @param GamePlayerBan $ban - * @param Account|null $account - * @return bool - */ - public function isAccountVerified(GamePlayerBan $ban, ?Account $account): bool - { - return ($account?->is($ban->bannedPlayer->account)) ?? false; - } - - /** - * @throws EmailRequiredException - */ public function execute( - GamePlayerBan $ban, - string $explanation, - ?Account $loggedInAccount, - ?string $email + int $banId, + string $email, + string $minecraftUuid, + string $dateOfBan, + ?string $banReason, + string $unbanReason, + ?Account $account, ): BanAppeal { - $isAccountVerified = $this->isAccountVerified($ban, $loggedInAccount); - if (! $isAccountVerified && $email === null) { - throw new EmailRequiredException(); - } + $ban = GamePlayerBan::find($banId); $banAppeal = BanAppeal::create([ - 'game_ban_id' => $ban->getKey(), - 'is_account_verified' => $isAccountVerified, - 'explanation' => $explanation, + 'game_ban_id' => $ban?->getKey(), + 'account_id' => $account?->getKey(), + 'minecraft_uuid' => $minecraftUuid, + 'date_of_ban' => $dateOfBan, + 'ban_reason' => $banReason, + 'unban_reason' => $unbanReason, 'email' => $email, 'status' => BanAppealStatus::PENDING, ]); diff --git a/app/Domains/Bans/UseCases/LookupPlayerBan.php b/app/Domains/Bans/UseCases/LookupPlayerBan.php deleted file mode 100644 index d9b67a6e5..000000000 --- a/app/Domains/Bans/UseCases/LookupPlayerBan.php +++ /dev/null @@ -1,38 +0,0 @@ -mojangPlayerApi->getUuidOf($username); - - if ($mojangPlayer === null) { - return null; - } - - $mcPlayer = MinecraftPlayer::where('uuid', $mojangPlayer->getUuid())->first(); - if ($mcPlayer === null) { - return null; - } - - $gamePlayerBan = GamePlayerBan::where('banned_player_id', $mcPlayer->getKey()) - ->active() - ->first(); - - if ($gamePlayerBan === null) { - return null; - } - - return $gamePlayerBan; - } -} diff --git a/app/Http/Controllers/Front/BanAppeal/BanAppealController.php b/app/Http/Controllers/Front/BanAppeal/BanAppealController.php index a5c2d8d60..94d9bd256 100644 --- a/app/Http/Controllers/Front/BanAppeal/BanAppealController.php +++ b/app/Http/Controllers/Front/BanAppeal/BanAppealController.php @@ -2,102 +2,19 @@ namespace App\Http\Controllers\Front\BanAppeal; -use App\Domains\BanAppeals\Exceptions\EmailRequiredException; -use App\Domains\BanAppeals\UseCases\CreateBanAppeal; use App\Http\Controllers\WebController; -use App\Http\Requests\StoreBanAppealRequest; use App\Models\BanAppeal; -use App\Models\GamePlayerBan; -use Illuminate\Auth\Access\AuthorizationException; use Illuminate\Http\Request; -use Illuminate\Http\Response; +use Illuminate\Support\Facades\Gate; class BanAppealController extends WebController { - /** - * Display a listing of the resource. - */ - public function index(Request $request) - { - $bans = $request->user()?->gamePlayerBans() - ->with(['banAppeals', 'bannerPlayer', 'bannedPlayer']) - ->latest()->get() ?? collect(); - - return view('front.pages.ban-appeal.index')->with([ - 'bans' => $bans, - ]); - } - - /** - * Show the form for creating a new resource. - */ - public function create(GamePlayerBan $ban, Request $request, CreateBanAppeal $useCase) - { - if (! $ban->isActive()) { - return abort(404); - } - - $existingAppeal = $ban->banAppeals()->pending()->first(); - if ($existingAppeal) { - return view('front.pages.ban-appeal.error-pending')->with([ - 'existingAppeal' => $existingAppeal, - ]); - } - - $bannedPlayer = $ban->bannedPlayer; - $banHistory = $bannedPlayer->gamePlayerBans() - ->with(['bannerPlayer', 'bannedPlayer']) - ->latest()->get(); - - return view('front.pages.ban-appeal.create')->with([ - 'player' => $bannedPlayer, - 'activegamePlayerBan' => $ban, - 'banHistory' => $banHistory, - 'accountVerified' => $useCase->isAccountVerified($ban, $request->user()), - ]); - } - - /** - * Store a newly created resource in storage. - * - * @param GamePlayerBan $ban - * @param StoreBanAppealRequest $request - * @param CreateBanAppeal $useCase - * @return Response - */ - public function store(GamePlayerBan $ban, StoreBanAppealRequest $request, CreateBanAppeal $useCase) - { - try { - $banAppeal = $useCase->execute( - ban: $ban, - explanation: $request->get('explanation'), - loggedInAccount: $request->user(), - email: $request->get('email'), - ); - } catch (EmailRequiredException $e) { - $e->throwAsValidationException(); - } - - return redirect($banAppeal->showLink()); - } - - /** - * Display the specified resource. - * - * @param BanAppeal $banAppeal - * @param Request $request - * @return Response - * - * @throws AuthorizationException - */ public function show(BanAppeal $banAppeal, Request $request) { + // Allow access via magic link, otherwise authenticate with policy if (! $request->hasValidSignature()) { - $this->authorize('view', $banAppeal); + Gate::authorize('view', $banAppeal); } - - return view('front.pages.ban-appeal.show')->with([ - 'banAppeal' => $banAppeal, - ]); + return view('front.pages.ban-appeal.show', compact('banAppeal')); } } diff --git a/app/Http/Controllers/Front/BanAppeal/BanAppealFormController.php b/app/Http/Controllers/Front/BanAppeal/BanAppealFormController.php new file mode 100644 index 000000000..e672e1123 --- /dev/null +++ b/app/Http/Controllers/Front/BanAppeal/BanAppealFormController.php @@ -0,0 +1,48 @@ + null]); + } + + public function show(Request $request, GamePlayerBan $ban) + { + return view('front.pages.ban-appeal.form', compact('ban')); + } + + public function store( + Request $request, + CaptchaRule $captchaRule, + CreateBanAppeal $useCase, + ) { + $validated = $request->validate([ + 'captcha-response' => ['required', $captchaRule], + 'minecraft_uuid' => 'required', + 'date_of_ban' => 'required', + 'ban_id' => ['nullable', 'integer'], + 'email' => ['required', 'email'], + 'ban_reason' => 'required', + 'unban_reason' => 'required', + ]); + $banAppeal = $useCase->execute( + banId: $validated['ban_id'], + email: $validated['email'], + minecraftUuid: $validated['minecraft_uuid'], + dateOfBan: $validated['date_of_ban'], + banReason: $validated['ban_reason'], + unbanReason: $validated['unban_reason'], + account: $request->user(), + ); + return redirect($banAppeal->showLink()); + } +} diff --git a/app/Http/Controllers/Front/BanAppeal/BanAppealSearchController.php b/app/Http/Controllers/Front/BanAppeal/BanAppealSearchController.php new file mode 100644 index 000000000..d8b38b52c --- /dev/null +++ b/app/Http/Controllers/Front/BanAppeal/BanAppealSearchController.php @@ -0,0 +1,38 @@ +user(); + if ($user !== null) { + $activeBans = $user->gamePlayerBans()->active()->get(); + } + + $query = $request->input('query'); + $pipes = [ + new LikeFilter('alias', $query, relationship: 'bannedPlayer'), + ]; + $bans = Pipeline::send(GamePlayerBan::query()) + ->through($pipes) + ->thenReturn() + ->with(['bannedPlayer', 'bannerPlayer']) + ->active() + ->latest() + ->paginate(25); + + return view('front.pages.ban-appeal.search', [ + 'active_bans' => $activeBans ?? collect(), + 'bans' => $bans, + 'query' => $query, + ]); + } +} diff --git a/app/Http/Controllers/Front/BanAppeal/BanLookupController.php b/app/Http/Controllers/Front/BanAppeal/BanLookupController.php deleted file mode 100644 index df740663e..000000000 --- a/app/Http/Controllers/Front/BanAppeal/BanLookupController.php +++ /dev/null @@ -1,29 +0,0 @@ -execute($request->get('username')); - if ($ban === null) { - throw ValidationException::withMessages([ - 'error' => ['This player has no active bans.'], - ]); - } - return redirect()->route('front.appeal.create', $ban); - } catch (TooManyRequestsException) { - throw ValidationException::withMessages([ - 'error' => ['The Mojang API is too busy currently. Please try again later'], - ]); - } - } -} diff --git a/app/Http/Controllers/Front/BanlistController.php b/app/Http/Controllers/Front/BanlistController.php index de8500383..48a516292 100644 --- a/app/Http/Controllers/Front/BanlistController.php +++ b/app/Http/Controllers/Front/BanlistController.php @@ -3,36 +3,36 @@ namespace App\Http\Controllers\Front; use App\Http\Controllers\WebController; +use App\Http\Filters\LikeFilter; use App\Models\GamePlayerBan; use Illuminate\Http\Request; +use Illuminate\Support\Facades\Pipeline; final class BanlistController extends WebController { public function index(Request $request) { - $bans = GamePlayerBan::active() - ->with(['bannedPlayer', 'bannerPlayer']) - ->latest(); - - if ($request->has('query') && !empty($request->input('query'))) { - $query = $request->input('query'); - $bans = GamePlayerBan::search($query)->constrain($bans); - } else { - $query = null; - } + $query = $request->input('query'); - $bans = $bans->paginate(50); + $pipes = [ + new LikeFilter('alias', $query, relationship: 'bannedPlayer'), + ]; + $bans = Pipeline::send(GamePlayerBan::query()) + ->through($pipes) + ->thenReturn() + ->with(['bannedPlayer', 'bannerPlayer']) + ->active() + ->latest() + ->paginate(50); - return view('front.pages.banlist') - ->with([ - 'bans' => $bans, - 'query' => $query, - ]); + return view( + 'front.pages.bans.index', + compact('bans', 'query'), + ); } public function show(Request $request, GamePlayerBan $ban) { - return view('front.pages.ban') - ->with(['ban' => $ban]); + return view('front.pages.bans.show', compact('ban')); } } diff --git a/app/Http/Controllers/Manage/Accounts/AccountBadgeController.php b/app/Http/Controllers/Manage/Accounts/AccountBadgeController.php index 99fb16c1e..c845a4719 100644 --- a/app/Http/Controllers/Manage/Accounts/AccountBadgeController.php +++ b/app/Http/Controllers/Manage/Accounts/AccountBadgeController.php @@ -2,8 +2,8 @@ namespace App\Http\Controllers\Manage\Accounts; -use App\Domains\Manage\RendersManageApp; use App\Domains\MinecraftEventBus\Events\MinecraftPlayerUpdated; +use App\Http\Controllers\Manage\RendersManageApp; use App\Models\Account; use App\Models\Badge; use Illuminate\Http\Request; diff --git a/app/Http/Controllers/Manage/Accounts/AccountController.php b/app/Http/Controllers/Manage/Accounts/AccountController.php index 98b3202ae..add871ccc 100644 --- a/app/Http/Controllers/Manage/Accounts/AccountController.php +++ b/app/Http/Controllers/Manage/Accounts/AccountController.php @@ -3,8 +3,8 @@ namespace App\Http\Controllers\Manage\Accounts; use App\Core\Rules\DiscourseUsernameRule; -use App\Domains\Manage\RendersManageApp; use App\Domains\Registration\UseCases\CreateUnactivatedAccount; +use App\Http\Controllers\Manage\RendersManageApp; use App\Http\Controllers\WebController; use App\Http\Filters\EqualFilter; use App\Http\Filters\LikeFilter; diff --git a/app/Http/Controllers/Manage/Accounts/AccountGroupController.php b/app/Http/Controllers/Manage/Accounts/AccountGroupController.php index 7cd528346..cc6b8102f 100644 --- a/app/Http/Controllers/Manage/Accounts/AccountGroupController.php +++ b/app/Http/Controllers/Manage/Accounts/AccountGroupController.php @@ -2,7 +2,7 @@ namespace App\Http\Controllers\Manage\Accounts; -use App\Domains\Manage\RendersManageApp; +use App\Http\Controllers\Manage\RendersManageApp; use App\Http\Controllers\WebController; use App\Models\Account; use App\Models\Group; diff --git a/app/Http/Controllers/Manage/Accounts/AccountPlayerController.php b/app/Http/Controllers/Manage/Accounts/AccountPlayerController.php index 65ddb72c8..d5c3e53c5 100644 --- a/app/Http/Controllers/Manage/Accounts/AccountPlayerController.php +++ b/app/Http/Controllers/Manage/Accounts/AccountPlayerController.php @@ -4,7 +4,7 @@ use App\Core\Domains\MinecraftUUID\Data\MinecraftUUID; use App\Core\Domains\MinecraftUUID\Rules\MinecraftUUIDRule; -use App\Domains\Manage\RendersManageApp; +use App\Http\Controllers\Manage\RendersManageApp; use App\Http\Controllers\WebController; use App\Models\Account; use App\Models\MinecraftPlayer; diff --git a/app/Http/Controllers/Manage/Badges/BadgeController.php b/app/Http/Controllers/Manage/Badges/BadgeController.php index f034eedac..b0b5ddc07 100644 --- a/app/Http/Controllers/Manage/Badges/BadgeController.php +++ b/app/Http/Controllers/Manage/Badges/BadgeController.php @@ -2,7 +2,7 @@ namespace App\Http\Controllers\Manage\Badges; -use App\Domains\Manage\RendersManageApp; +use App\Http\Controllers\Manage\RendersManageApp; use App\Http\Controllers\WebController; use App\Models\Badge; use Illuminate\Http\Request; diff --git a/app/Http/Controllers/Manage/Bans/GameIPBanController.php b/app/Http/Controllers/Manage/Bans/GameIPBanController.php index 260c3b693..0aace4ad7 100644 --- a/app/Http/Controllers/Manage/Bans/GameIPBanController.php +++ b/app/Http/Controllers/Manage/Bans/GameIPBanController.php @@ -4,8 +4,8 @@ use App\Core\Domains\MinecraftUUID\Data\MinecraftUUID; use App\Core\Domains\MinecraftUUID\Rules\MinecraftUUIDRule; -use App\Domains\Manage\RendersManageApp; use App\Domains\MinecraftEventBus\Events\IpAddressBanned; +use App\Http\Controllers\Manage\RendersManageApp; use App\Http\Controllers\WebController; use App\Models\GameIPBan; use App\Models\MinecraftPlayer; diff --git a/app/Http/Controllers/Manage/Bans/GamePlayerBanController.php b/app/Http/Controllers/Manage/Bans/GamePlayerBanController.php index 65547ee69..7ffca1687 100644 --- a/app/Http/Controllers/Manage/Bans/GamePlayerBanController.php +++ b/app/Http/Controllers/Manage/Bans/GamePlayerBanController.php @@ -5,8 +5,8 @@ use App\Core\Domains\MinecraftUUID\Data\MinecraftUUID; use App\Core\Domains\MinecraftUUID\Rules\MinecraftUUIDRule; use App\Domains\Bans\Data\UnbanType; -use App\Domains\Manage\RendersManageApp; use App\Domains\MinecraftEventBus\Events\MinecraftUuidBanned; +use App\Http\Controllers\Manage\RendersManageApp; use App\Http\Controllers\WebController; use App\Models\GamePlayerBan; use App\Models\MinecraftPlayer; diff --git a/app/Http/Controllers/Manage/Donations/DonationController.php b/app/Http/Controllers/Manage/Donations/DonationController.php index a33ad3ef0..711fcb783 100644 --- a/app/Http/Controllers/Manage/Donations/DonationController.php +++ b/app/Http/Controllers/Manage/Donations/DonationController.php @@ -2,7 +2,7 @@ namespace App\Http\Controllers\Manage\Donations; -use App\Domains\Manage\RendersManageApp; +use App\Http\Controllers\Manage\RendersManageApp; use App\Http\Controllers\WebController; use App\Models\Donation; use Illuminate\Http\Request; diff --git a/app/Http/Controllers/Manage/Groups/GroupAccountController.php b/app/Http/Controllers/Manage/Groups/GroupAccountController.php index bc967f805..0513d1d91 100644 --- a/app/Http/Controllers/Manage/Groups/GroupAccountController.php +++ b/app/Http/Controllers/Manage/Groups/GroupAccountController.php @@ -2,7 +2,7 @@ namespace App\Http\Controllers\Manage\Groups; -use App\Domains\Manage\RendersManageApp; +use App\Http\Controllers\Manage\RendersManageApp; use App\Http\Controllers\WebController; use App\Models\Account; use App\Models\Group; diff --git a/app/Http/Controllers/Manage/Groups/GroupController.php b/app/Http/Controllers/Manage/Groups/GroupController.php index 1663a7aa9..b59523800 100644 --- a/app/Http/Controllers/Manage/Groups/GroupController.php +++ b/app/Http/Controllers/Manage/Groups/GroupController.php @@ -2,7 +2,7 @@ namespace App\Http\Controllers\Manage\Groups; -use App\Domains\Manage\RendersManageApp; +use App\Http\Controllers\Manage\RendersManageApp; use App\Http\Controllers\WebController; use App\Models\Account; use App\Models\Group; diff --git a/app/Http/Controllers/Manage/HomeController.php b/app/Http/Controllers/Manage/HomeController.php index eeca9f9a7..fbb7aa106 100644 --- a/app/Http/Controllers/Manage/HomeController.php +++ b/app/Http/Controllers/Manage/HomeController.php @@ -2,7 +2,6 @@ namespace App\Http\Controllers\Manage; -use App\Domains\Manage\RendersManageApp; use App\Http\Controllers\WebController; use Illuminate\Http\Request; diff --git a/app/Http/Controllers/Manage/Minecraft/MinecraftConfigController.php b/app/Http/Controllers/Manage/Minecraft/MinecraftConfigController.php index b65886943..84625286f 100644 --- a/app/Http/Controllers/Manage/Minecraft/MinecraftConfigController.php +++ b/app/Http/Controllers/Manage/Minecraft/MinecraftConfigController.php @@ -2,8 +2,8 @@ namespace App\Http\Controllers\Manage\Minecraft; -use App\Domains\Manage\RendersManageApp; use App\Domains\MinecraftEventBus\Events\MinecraftConfigUpdated; +use App\Http\Controllers\Manage\RendersManageApp; use App\Http\Controllers\WebController; use App\Models\MinecraftConfig; use Illuminate\Http\Request; diff --git a/app/Http/Controllers/Manage/Minecraft/MinecraftWarpController.php b/app/Http/Controllers/Manage/Minecraft/MinecraftWarpController.php index 79989db86..ef9322405 100644 --- a/app/Http/Controllers/Manage/Minecraft/MinecraftWarpController.php +++ b/app/Http/Controllers/Manage/Minecraft/MinecraftWarpController.php @@ -3,7 +3,7 @@ namespace App\Http\Controllers\Manage\Minecraft; use App\Core\Domains\MinecraftCoordinate\ValidatesCoordinates; -use App\Domains\Manage\RendersManageApp; +use App\Http\Controllers\Manage\RendersManageApp; use App\Http\Controllers\WebController; use App\Models\MinecraftWarp; use Illuminate\Http\RedirectResponse; diff --git a/app/Http/Controllers/Manage/Players/MinecraftPlayerController.php b/app/Http/Controllers/Manage/Players/MinecraftPlayerController.php index c796906e2..7f4ba9b29 100644 --- a/app/Http/Controllers/Manage/Players/MinecraftPlayerController.php +++ b/app/Http/Controllers/Manage/Players/MinecraftPlayerController.php @@ -5,9 +5,8 @@ use App\Core\Domains\MinecraftUUID\Data\MinecraftUUID; use App\Core\Domains\MinecraftUUID\Rules\MinecraftUUIDRule; use App\Core\Domains\MinecraftUUID\UseCases\LookupMinecraftUUID; -use App\Domains\Manage\RendersManageApp; +use App\Http\Controllers\Manage\RendersManageApp; use App\Http\Controllers\WebController; -use App\Http\Filters\EqualFilter; use App\Http\Filters\LikeFilter; use App\Models\MinecraftPlayer; use Illuminate\Http\Request; diff --git a/app/Domains/Manage/RendersManageApp.php b/app/Http/Controllers/Manage/RendersManageApp.php similarity index 89% rename from app/Domains/Manage/RendersManageApp.php rename to app/Http/Controllers/Manage/RendersManageApp.php index 284e6127a..83ce56527 100644 --- a/app/Domains/Manage/RendersManageApp.php +++ b/app/Http/Controllers/Manage/RendersManageApp.php @@ -1,6 +1,6 @@ load([ + 'account', 'gamePlayerBan.bannerPlayer', 'gamePlayerBan.bannedPlayer', 'deciderPlayer', diff --git a/app/Http/Controllers/Review/BuilderRanks/BuilderRanksController.php b/app/Http/Controllers/Review/BuilderRanks/BuilderRanksController.php index c6d7495ac..57262dfba 100644 --- a/app/Http/Controllers/Review/BuilderRanks/BuilderRanksController.php +++ b/app/Http/Controllers/Review/BuilderRanks/BuilderRanksController.php @@ -5,7 +5,7 @@ use App\Domains\BuilderRankApplications\Data\ApplicationStatus; use App\Domains\BuilderRankApplications\UseCases\ApproveBuildRankApplication; use App\Domains\BuilderRankApplications\UseCases\DenyBuildRankApplication; -use App\Domains\Review\RendersReviewApp; +use App\Http\Controllers\Review\RendersReviewApp; use App\Http\Controllers\WebController; use App\Models\BuilderRankApplication; use App\Models\Group; diff --git a/app/Http/Controllers/Review/HomeController.php b/app/Http/Controllers/Review/HomeController.php index 0341bff8f..203033ab8 100644 --- a/app/Http/Controllers/Review/HomeController.php +++ b/app/Http/Controllers/Review/HomeController.php @@ -2,7 +2,6 @@ namespace App\Http\Controllers\Review; -use App\Domains\Review\RendersReviewApp; use App\Http\Controllers\WebController; use Illuminate\Http\Request; diff --git a/app/Domains/Review/RendersReviewApp.php b/app/Http/Controllers/Review/RendersReviewApp.php similarity index 89% rename from app/Domains/Review/RendersReviewApp.php rename to app/Http/Controllers/Review/RendersReviewApp.php index 454fa6baf..f3dcc6630 100644 --- a/app/Domains/Review/RendersReviewApp.php +++ b/app/Http/Controllers/Review/RendersReviewApp.php @@ -1,6 +1,6 @@ value) { return $next($query); } - $query->where($this->column, 'like', "%$this->value%"); + if (! empty($this->relationship)) { + $query->whereHas($this->relationship, function ($it) { + $it->where($this->column, 'like', "%$this->value%"); + }); + } else { + $query->where($this->column, 'like', "%$this->value%"); + } return $next($query); } diff --git a/app/Http/Requests/StoreBanAppealRequest.php b/app/Http/Requests/StoreBanAppealRequest.php deleted file mode 100644 index de503a068..000000000 --- a/app/Http/Requests/StoreBanAppealRequest.php +++ /dev/null @@ -1,31 +0,0 @@ - - */ - public function rules() - { - return [ - 'explanation' => 'required', - 'email' => 'nullable|email', - ]; - } -} diff --git a/app/Models/BanAppeal.php b/app/Models/BanAppeal.php index ca44b00cc..c35ee38b3 100644 --- a/app/Models/BanAppeal.php +++ b/app/Models/BanAppeal.php @@ -26,12 +26,24 @@ class BanAppeal extends Model implements LinkableAuditModel protected $fillable = [ 'game_ban_id', - 'is_account_verified', - 'explanation', + 'account_id', 'email', + 'minecraft_uuid', + 'date_of_ban', + 'ban_reason', + 'unban_reason', 'status', ]; + public function account(): BelongsTo + { + return $this->belongsTo( + related: Account::class, + foreignKey: 'account_id', + ownerKey: 'account_id', + ); + } + public function gamePlayerBan(): BelongsTo { return $this->belongsTo( diff --git a/app/Policies/BanAppealPolicy.php b/app/Policies/BanAppealPolicy.php index bc31e99b2..9469aaa22 100644 --- a/app/Policies/BanAppealPolicy.php +++ b/app/Policies/BanAppealPolicy.php @@ -31,9 +31,7 @@ public function viewAny(Account $account): bool */ public function view(Account $account, BanAppeal $banAppeal): bool { - return $account->is( - $banAppeal->gamePlayerBan->bannedPlayer->account - ); + return $account->is($banAppeal->account); } /** diff --git a/database/factories/BanAppealFactory.php b/database/factories/BanAppealFactory.php index 1b3a43e4d..e3e4bad3e 100644 --- a/database/factories/BanAppealFactory.php +++ b/database/factories/BanAppealFactory.php @@ -26,9 +26,11 @@ class BanAppealFactory extends Factory public function definition(): array { return [ - 'explanation' => $this->faker->paragraph, + 'minecraft_uuid' => $this->faker->uuid, + 'date_of_ban' => $this->faker->dateTime, + 'ban_reason' => $this->faker->paragraph, + 'unban_reason' => $this->faker->paragraph, 'status' => BanAppealStatus::PENDING, - 'is_account_verified' => false, 'email' => $this->faker->email, ]; } diff --git a/database/migrations/2025_04_06_065852_update_ban_appeals.php b/database/migrations/2025_04_06_065852_update_ban_appeals.php new file mode 100644 index 000000000..e8d0a8d07 --- /dev/null +++ b/database/migrations/2025_04_06_065852_update_ban_appeals.php @@ -0,0 +1,51 @@ +unsignedInteger('account_id')->nullable()->after('game_ban_id'); + $table->text('ban_reason')->nullable()->after('email'); + $table->renameColumn('explanation', 'unban_reason'); + $table->string('date_of_ban')->nullable()->after('email'); + $table->string('minecraft_uuid')->after('account_id'); + }); + + $appeals = BanAppeal::get(); + foreach ($appeals as $appeal) { + $ban = $appeal->gamePlayerBan; + $player = $ban->bannedPlayer; + $account = $player?->account; + + if ($appeal->is_account_verified) { + $appeal->account_id = $account->getKey(); + $appeal->email = $account->email; + } + $appeal->minecraft_uuid = $player?->uuid; + $appeal->ban_reason = $ban->reason; + $appeal->date_of_ban = $ban->created_at; + $appeal->save(); + } + + Schema::table('ban_appeals', function (Blueprint $table) { + $table->dropColumn('is_account_verified'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + // No return + } +}; diff --git a/resources/js/manage/Data/BanAppeal.ts b/resources/js/manage/Data/BanAppeal.ts index ea18075d6..ad547c928 100644 --- a/resources/js/manage/Data/BanAppeal.ts +++ b/resources/js/manage/Data/BanAppeal.ts @@ -1,13 +1,16 @@ import { BanAppealStatus } from './BanAppealStatus' import { Player } from './Player' import { PlayerBan } from './PlayerBan' +import { Account } from './Account' export interface BanAppeal { id: number, - explanation: string, + minecraft_uuid: string, + ban_reason?: string, + unban_reason: string, email: string, status: BanAppealStatus, - is_account_verified: boolean, + account?: Account, game_player_ban: PlayerBan, created_at: string, updated_at: string, diff --git a/resources/js/review/Pages/BanAppeals/BanAppealShow.vue b/resources/js/review/Pages/BanAppeals/BanAppealShow.vue index cf2cf6a6c..0b4c0e8ee 100644 --- a/resources/js/review/Pages/BanAppeals/BanAppealShow.vue +++ b/resources/js/review/Pages/BanAppeals/BanAppealShow.vue @@ -96,9 +96,22 @@ function submit() {
-
Submitted by account?
+
Minecraft UUID
- {{ banAppeal.is_account_verified ? 'Yes' : 'No' }} + {{ banAppeal.minecraft_uuid }} +
+
+
+
Account
+
+ +

{{ banAppeal.account.username }}

+
+ Guest
@@ -179,8 +192,21 @@ function submit() {

Ban Appeal

-
- {{ banAppeal.explanation }} +
+
+

Date of Ban

+ {{ banAppeal.date_of_ban }} +
+ +
+

Ban Reason

+ {{ banAppeal.ban_reason }} +
+ +
+

Why should you be unbaned?

+ {{ banAppeal.unban_reason }} +
diff --git a/resources/sass/front.scss b/resources/sass/front.scss new file mode 100644 index 000000000..82a3ec556 --- /dev/null +++ b/resources/sass/front.scss @@ -0,0 +1,21 @@ +@charset "utf-8"; + +// -- Deprecated -- +@forward "front/command"; +@forward "front/modal"; + +@import url('https://fonts.googleapis.com/css2?family=Bebas+Neue&family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap'); + +$font-header: 'Bebas Neue', sans-serif; +$font-body: 'Inter', sans-serif; + +body { + font-family: $font-body; + background-color: hsl(0, 0%, 94%); +} +// --------------- + + +@tailwind base; +@tailwind components; +@tailwind utilities; diff --git a/resources/sass/front/molecules/_command.scss b/resources/sass/front/_command.scss similarity index 53% rename from resources/sass/front/molecules/_command.scss rename to resources/sass/front/_command.scss index ed8f1cf29..398d76e8c 100644 --- a/resources/sass/front/molecules/_command.scss +++ b/resources/sass/front/_command.scss @@ -1,9 +1,12 @@ +@use "sass:color"; + +// TODO: convert this to a blade component span.command { $bg: #f8f8f8; background-color: $bg; border-radius: 5px; - border: 1px solid darken($bg, 10%); + border: 1px solid color.scale($bg, $lightness: -10%, $space: oklch); padding: 0.2em 0.4em; font-weight: 500; font-size: 0.9em; diff --git a/resources/sass/front/molecules/_modal.scss b/resources/sass/front/_modal.scss similarity index 96% rename from resources/sass/front/molecules/_modal.scss rename to resources/sass/front/_modal.scss index 07711cf3e..2bc100c28 100644 --- a/resources/sass/front/molecules/_modal.scss +++ b/resources/sass/front/_modal.scss @@ -19,12 +19,12 @@ box-shadow: 0 4px 10px hsla(0, 0%, 0%, 15%), inset 0 -4px 0 hsla(0, 0%, 0%, 25%); - @media screen and (min-width: $screen-m) { + @media screen and (min-width: 768px) { max-width: 50vw; max-height: 90vh; } - @media screen and (max-width: $screen-m) { + @media screen and (max-width: 768px) { max-width: 90vw; max-height: 80vh; } diff --git a/resources/sass/front/elements/_body.scss b/resources/sass/front/elements/_body.scss deleted file mode 100644 index bd56b5ccf..000000000 --- a/resources/sass/front/elements/_body.scss +++ /dev/null @@ -1,17 +0,0 @@ -* { - box-sizing: border-box; -} - -html, body { - height: 100%; - min-height: 100%; -} - -body { - overflow-x: hidden; - background-color: $color-lightest-grey; - font-family: $font-body; - font-size: 16px; - -webkit-font-smoothing: auto; - -moz-osx-font-smoothing: auto; -} diff --git a/resources/sass/front/elements/_button.scss b/resources/sass/front/elements/_button.scss deleted file mode 100644 index 2bc7ef50c..000000000 --- a/resources/sass/front/elements/_button.scss +++ /dev/null @@ -1,59 +0,0 @@ -.button { - border-radius: 5px; - border-color: #FF842A; - border-style: solid; - text-decoration: none; - text-shadow: none; - text-align: center; - font-weight: bold; - padding: 0.8em 0.75em; - display: inline-block; - text-transform: uppercase; -} - -.button.button--display { - font-family: $font-header; - font-weight: 400; - text-transform: uppercase; - font-size: 2em; - padding: 0.4em 1.5em 0.3em 1.5em; -} - -.button.button--block { - display: block; - width: 100%; -} - -.button.button--filled { - color: #fff; - border-width: 0; - background-color: #FF842A; - box-shadow: 0 4px 10px hsla(0, 0%, 0%, 15%), - inset 0 -3px 0 hsla(0, 0%, 0%, 15%); -} - -.button.button--secondary { - background-color: $color-secondary; -} - -.button.button--outlined { - color: #FF842A; - border-width: 2px; - box-shadow: 0 4px 10px hsla(0, 0%, 0%, 15%), - inset 0 4px 10px hsla(0, 0%, 0%, 15%); - text-shadow: none; -} - -.button.button--is-small { - font-size: 12px; -} - -.button.button--has-icon-right { - svg { - margin-left: 0.25em; - } -} - -button.button:hover { - cursor: pointer; -} diff --git a/resources/sass/front/foundation/_colors.scss b/resources/sass/front/foundation/_colors.scss deleted file mode 100644 index b65f3a3e6..000000000 --- a/resources/sass/front/foundation/_colors.scss +++ /dev/null @@ -1,29 +0,0 @@ -// Legacy - will be deleted -$color-primary: hsl(206, 80%, 48%); -$color-secondary: hsl(20, 12%, 29%); -$color-accent: hsl(40, 98%, 49%); -$color-light: hsl(14, 10%, 40%); -$color-lightest: hsl(14, 10%, 74%); -$color-basic: darken(#fff, 10%); -$color-white: #fff; - -$color-success: hsl(133.4,60.9%,33.1%); -$color-error: #b10e1e; -$color-warning: #e6cf01; - -$color-heading-primary: hsl(0, 0%, 15%); -$color-heading-contrast: #fff; - -$color-text-primary: hsl(0, 0%, 20%); -$color-text-link: #3577F8; // TODO: convert to hsl -$color-text-accent: $color-accent; - -$color-button-accent: $color-accent; - -$color-lightest-grey: hsl(0, 0%, 94%); - - -$alert-color-error: #f84637; -$alert-color-success: #00aa00; -$alert-color-warning: #665c00; -$alert-color-info: #585454; diff --git a/resources/sass/front/foundation/_dimensions.scss b/resources/sass/front/foundation/_dimensions.scss deleted file mode 100644 index e3c947429..000000000 --- a/resources/sass/front/foundation/_dimensions.scss +++ /dev/null @@ -1,6 +0,0 @@ -$screen-m: 768px; -$screen-l: 1024px; -$screen-xl: 1300px; - -$nav-height: 40px; -$footer-height: 55px; diff --git a/resources/sass/front/foundation/_typography.scss b/resources/sass/front/foundation/_typography.scss deleted file mode 100644 index 6009d1399..000000000 --- a/resources/sass/front/foundation/_typography.scss +++ /dev/null @@ -1,6 +0,0 @@ -@import url('https://fonts.googleapis.com/css2?family=Bebas+Neue&family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap'); - -$font-header: 'Bebas Neue', sans-serif; -$font-body: 'Inter', sans-serif; - -$tracking-wide: 0.025em; diff --git a/resources/sass/front/front.scss b/resources/sass/front/front.scss deleted file mode 100644 index b5e85a99a..000000000 --- a/resources/sass/front/front.scss +++ /dev/null @@ -1,23 +0,0 @@ -@charset "utf-8"; - -@tailwind base; -@tailwind components; -@tailwind utilities; - - -// --- WARNING: everything below here is deprecated --- -@import "foundation/colors"; -@import "foundation/dimensions"; -@import "foundation/typography"; - -@import "elements/body"; -@import "elements/button"; - -@import "molecules/command"; -@import "molecules/form-row"; -@import "molecules/game-account"; -@import "molecules/game-ban"; -@import "molecules/message"; -@import "molecules/modal"; - -@import "organisms/page.form"; diff --git a/resources/sass/front/molecules/_form-row.scss b/resources/sass/front/molecules/_form-row.scss deleted file mode 100644 index 5246cc329..000000000 --- a/resources/sass/front/molecules/_form-row.scss +++ /dev/null @@ -1,50 +0,0 @@ -.form-row { - label, input { - display: block; - } - - .textfield { - width: 100%; - } - - .textfield--is-mfa { - width: auto; - } - - input[type="checkbox"] { - display: inline; - margin-right: 0.5rem; - } - - &--emphasise-checkbox { - margin-top: 1rem; - margin-bottom: 1rem; - } - - p.help-text { - font-size: 0.8em; - margin: 0; - } -} - -.form { - width: 100%; - - .form-row:first-of-type label { - margin-top: 2rem; - } - - .form-row:not(:last-child) { - margin-bottom: 1rem; - } - - button { - margin-top: 0.5rem; - } - - &__description { - margin-top: 0.5rem; - line-height: 1.5; - color: $color-text-primary; - } -} diff --git a/resources/sass/front/molecules/_game-account.scss b/resources/sass/front/molecules/_game-account.scss deleted file mode 100644 index 3bf9d58ff..000000000 --- a/resources/sass/front/molecules/_game-account.scss +++ /dev/null @@ -1,53 +0,0 @@ -.game-account { - display: flex; - border: 1px solid #ccc; - padding: 5px; - border-radius: 5px; - - &--filled { - background-color: white; - box-shadow: inset 0 -2px 0 rgba(0, 0, 0, 0.25); - padding: 7px; - } - - &__avatar { - margin-right: 0.6rem; - } - - &__game { - text-transform: uppercase; - color: lighten($color-text-primary, 10%); - letter-spacing: $tracking-wide; - font-size: 0.8em; - margin-bottom: 3px; - } - - &__alias { - font-size: 1.1em; - font-weight: bold; - margin-bottom: 5px; - } - - &__id { - font-family: monospace; - font-size: 0.75rem; - } - - &__actions { - margin-top: 10px; - - button { - margin-top: 0; - } - } -} - - -@media screen and (min-width: $screen-m) { - .game-account-grid { - display: grid; - grid-template-columns: repeat(2, minmax(0, 1fr)); - gap: 1rem; - } -} - diff --git a/resources/sass/front/molecules/_game-ban.scss b/resources/sass/front/molecules/_game-ban.scss deleted file mode 100644 index b01a8dec1..000000000 --- a/resources/sass/front/molecules/_game-ban.scss +++ /dev/null @@ -1,117 +0,0 @@ -.game-ban { - border: 1px solid #ccc; - border-radius: 5px; - background-color: white; - box-shadow: inset 0 -2px 0 rgba(0, 0, 0, 0.25); - - &__info { - display: flex; - align-items: center; - padding: 7px; - border-bottom: 1px solid $color-lightest; - } - - &__avatar { - margin-right: 0.6rem; - } - - &__meta { - text-transform: uppercase; - color: lighten($color-text-primary, 10%); - letter-spacing: $tracking-wide; - font-size: 0.8em; - margin-bottom: 3px; - } - - &__reason { - font-size: 1.1em; - font-style: italic; - } - - &__appeal-history { - border-bottom: 1px solid $color-lightest; - list-style: none; - margin: 0; - padding: 0; - - a { - position: relative; - display: block; - padding-top: 3px; - padding-bottom: 3px; - padding-left: 10px; - - color: unset; - text-decoration: none; - background-color: $color-lightest-grey; - - &:hover { - background-color: darken($color-lightest-grey, 3%); - } - } - - a::after { - position: absolute; - right: 10px; - top: 25%; - font-size: 1.5rem; - font-family: "Font Awesome 6 Free"; - font-weight: 900; - content: "\f054"; - } - - } - - - &__status { - font-weight: bold; - font-size: 1.1rem; - - &--is-ban { - margin-top: 5px; - } - } - - &__actions { - padding: 7px; - - button { - margin-top: 0; - } - } - - .is-unbanned { - color: $alert-color-success; - } - - .is-pending { - color: $alert-color-info; - } - - .is-tempbanned { - color: $alert-color-warning; - } - - .is-denied { - color: $alert-color-error; - } -} - -.game-ban-column { - .game-ban { - margin-bottom: 1rem; - } -} - -.game-ban-empty { - text-align: center; - - i { - margin-bottom: 1rem; - display: block; - color: lighten($color-text-primary, 20%); - } - div { - font-weight: bold; - } -} diff --git a/resources/sass/front/molecules/_message.scss b/resources/sass/front/molecules/_message.scss deleted file mode 100644 index b586cfbc0..000000000 --- a/resources/sass/front/molecules/_message.scss +++ /dev/null @@ -1,95 +0,0 @@ -.messages { - .message { - margin-bottom: 2rem; - } -} - -.message { - display: flex; - flex-direction: row; - justify-content: flex-start; - align-items: flex-start; - - .message-avatar { - padding-top: 10px; - } - - .message-comment { - flex: 1; - } - - .message-text { - background: white; - padding: 1em; - border-radius: 5px; - position: relative; - box-shadow: inset 0 -2px 0 rgba(0, 0, 0, 0.25); - border: 1px solid #e6e6e6; - } - - .message-date { - font-size: 0.7em; - padding-top: 0.5em; - padding-left: 1rem; - color: $color-text-primary; - text-transform: uppercase; - } - - &.message--left { - .message-comment { - padding-left: 30px; - } - - .message-text::after { - content: ''; - position: absolute; - top: 15px; - left: -30px; - width: 0px; - height: 0px; - border-top: 10px solid transparent; - border-bottom: 10px solid transparent; - border-left: 10px solid transparent; - border-right: 20px solid white; - } - - &.message--distinguish { - .message-text::after { - border-right-color: lighten($color-accent, 45%); - } - } - } - - &.message--right { - .message-comment { - padding-right: 30px; - } - - .message-text::after { - content: ''; - position: absolute; - top: 15px; - right: -30px; - width: 0px; - height: 0px; - border-top: 10px solid transparent; - border-bottom: 10px solid transparent; - border-left: 20px solid white; - border-right: 10px solid transparent; - } - - &.message--distinguish { - .message-text::after { - border-left-color: lighten($color-accent, 45%); - } - } - } - - &.message--distinguish { - .message-text { - background: lighten($color-accent, 45%); - border-color: $color-accent; - box-shadow: inset 0 -2px 0 rgba($color-accent, 0.25); - } - } -} diff --git a/resources/sass/front/organisms/_page.form.scss b/resources/sass/front/organisms/_page.form.scss deleted file mode 100644 index b88cecea0..000000000 --- a/resources/sass/front/organisms/_page.form.scss +++ /dev/null @@ -1,90 +0,0 @@ -.page.form { - display: grid; - - @media screen and (min-width: $screen-l) { - grid-template-columns: 35% 2fr; - } - @media screen and (max-width: $screen-l) { - grid-template-columns: 40% 2fr; - } - @media screen and (max-width: $screen-m) { - grid-template-columns: 100%; - } - - section.overview { - background-color: #525861; - padding: 4em 3em 4em 6em; - color: #fff; - line-height: 2em; - - @media screen and (max-width: $screen-m) { - padding: 3em 2em; - } - - h1 { - font-size: 3em; - line-height: 1.1em; - margin-top: 0em; - } - - blockquote { - background-color: #626974; - border-left: 8px solid #79808A; - margin: 2em 0 0 0; - padding: 1.5em; - font-size: 0.9em; - line-height: 1.8em; - - h3 { - font-family: $font-body; - font-size: 1.5em; - margin-top: 0; - } - } - } - section.contents { - padding: 4em 6em 4em 3em; - - p, h2, label, li { - line-height: 2em; - } - - @media screen and (max-width: $screen-m) { - padding: 3em 2em; - } - - h2 { - font-size: 1.5em; - font-family: $font-body; - padding-bottom: 0.5em; - border-bottom: 1px solid #D3D3D3; - margin-top: 0em; - } - - .contents__section { - margin-bottom: 3em; - } - - ol { - padding-left: 1em; - } - - .form .form-row:first-of-type label { - margin-top: 0; - } - .form label { - color: #000; - font-weight: bold; - } - - blockquote { - border: 2px solid darken($color-lightest-grey, 20%); - padding: 1rem; - margin: 0; - border-radius: 5px; - p { - margin: 0; - } - } - } -} diff --git a/resources/views/front/layouts/root-layout.blade.php b/resources/views/front/layouts/root-layout.blade.php index 742c3c11f..d6600ea20 100644 --- a/resources/views/front/layouts/root-layout.blade.php +++ b/resources/views/front/layouts/root-layout.blade.php @@ -31,7 +31,7 @@ @yield('title', 'Project City Build') @vite([ - 'resources/sass/front/front.scss', + 'resources/sass/front.scss', 'resources/js/front/front.ts', ]) diff --git a/resources/views/front/pages/ban-appeal/_ban-history.blade.php b/resources/views/front/pages/ban-appeal/_ban-history.blade.php deleted file mode 100644 index c49d4a9a1..000000000 --- a/resources/views/front/pages/ban-appeal/_ban-history.blade.php +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - - - - - - @foreach($banHistory as $ban) - - - - - - - - @endforeach - -
StatusReasonBanned ByBanned AtExpires
{{ $ban->isActive() ? 'Active' : 'Removed' }}{{ $ban->reason ?? 'No Reason Given' }} - @if($ban->banner_player_id != null && !empty($ban->bannerPlayer->alias)) - - {{ $ban->bannerPlayer->alias }} - @else - - - @endif - - {{ $ban->created_at->format('j M Y H:i') }} - - {{ $ban->expires_at?->format('j M Y H:i') ?? 'Never' }} -
diff --git a/resources/views/front/pages/ban-appeal/_game-ban-empty.blade.php b/resources/views/front/pages/ban-appeal/_game-ban-empty.blade.php deleted file mode 100644 index 941718b4a..000000000 --- a/resources/views/front/pages/ban-appeal/_game-ban-empty.blade.php +++ /dev/null @@ -1,3 +0,0 @@ -
-
No Bans Found.
-
diff --git a/resources/views/front/pages/ban-appeal/_game-ban-listing.blade.php b/resources/views/front/pages/ban-appeal/_game-ban-listing.blade.php deleted file mode 100644 index e8cbfe0d6..000000000 --- a/resources/views/front/pages/ban-appeal/_game-ban-listing.blade.php +++ /dev/null @@ -1,65 +0,0 @@ -
-
-
- -
-
-
- {{ $ban->bannedPlayer->alias ?? 'No Alias' }} - · Banned {{ $ban->created_at }} BY - {{ $ban->bannerPlayer?->alias ?? 'No Alias' }} -
-
- "{{ $ban->reason }}" -
- @if($ban->banAppeals->isEmpty() && !$ban->isActive()) -
- Unbanned -
- @endif -
-
- @if($ban->banAppeals->isNotEmpty()) - - @endif - @if($ban->isActive() && !$ban->banAppeals()->pending()->exists()) - - @endif -
diff --git a/resources/views/front/pages/ban-appeal/_layout-form.blade.php b/resources/views/front/pages/ban-appeal/_layout-form.blade.php deleted file mode 100644 index b3206ed1e..000000000 --- a/resources/views/front/pages/ban-appeal/_layout-form.blade.php +++ /dev/null @@ -1,20 +0,0 @@ -@extends('front.templates.2-col') - -@section('title', 'Appeal Ban') -@section('heading', 'Appeal Ban') -@section('description', 'Use the below form to submit a ban appeal') - -@section('col-1') -

- If you have been wrongfully banned, please post your request, and we will investigate the matter. Alternatively, if you are simply seeking a second chance, you may plead your case for consideration. -

-

- Please fill out all fields honestly. -

-
-

WARNING

- Abuse of the ban appeal system will result in your access being revoked. -
-@endsection - - diff --git a/resources/views/front/pages/ban-appeal/_username-lookup.blade.php b/resources/views/front/pages/ban-appeal/_username-lookup.blade.php deleted file mode 100644 index dff949e0e..000000000 --- a/resources/views/front/pages/ban-appeal/_username-lookup.blade.php +++ /dev/null @@ -1,21 +0,0 @@ -
- @csrf - @include('front.components.form-error') - -
- - -
- - -
diff --git a/resources/views/front/pages/ban-appeal/create.blade.php b/resources/views/front/pages/ban-appeal/create.blade.php deleted file mode 100644 index f13ed325e..000000000 --- a/resources/views/front/pages/ban-appeal/create.blade.php +++ /dev/null @@ -1,60 +0,0 @@ -@extends('front.pages.ban-appeal._layout-form') - -@section('col-2') -
-

Appeals Process

-
    -
  1. Submit an Application using the below form
  2. -
  3. Applications are reviewed by the staff member that banned you
  4. -
  5. You may be unbanned, your ban converted to a temporary ban, or unbanned
  6. -
- - Before you appeal, please read the ban details below. Appeals which do not relate to the ban reason are - likely to be denied. -
-
-

Ban History

-

Below is a list of your current ban and any previous bans.

- @include('front.pages.ban-appeal._ban-history') -
-
-

Appeal Form

- -
- @csrf - @include('front.components.form-error') - @unless($accountVerified) -
- - -

Please check this carefully, updates to your appeal will be sent - to this address.

-
- @endunless -
- - -
- - - Submit - - -
-@endsection diff --git a/resources/views/front/pages/ban-appeal/error-no-bans.blade.php b/resources/views/front/pages/ban-appeal/error-no-bans.blade.php deleted file mode 100644 index 292e9d32f..000000000 --- a/resources/views/front/pages/ban-appeal/error-no-bans.blade.php +++ /dev/null @@ -1,10 +0,0 @@ -@extends('front.pages.ban-appeal._layout-form') - -@section('col-2') -
-
-

Account not banned

- The user {{ $player->alias }} is not currently banned. -
-
-@endsection diff --git a/resources/views/front/pages/ban-appeal/error-pending.blade.php b/resources/views/front/pages/ban-appeal/error-pending.blade.php deleted file mode 100644 index dfc1b895a..000000000 --- a/resources/views/front/pages/ban-appeal/error-pending.blade.php +++ /dev/null @@ -1,15 +0,0 @@ -@extends('front.pages.ban-appeal._layout-form') - -@section('col-2') -
-
-

Appeal Already Created

- @if($existingAppeal->is_account_verified) - You already have an appeal in progress. - @else - You already have an appeal in progress. Click the link in the appeal confirmation email to check - progress. - @endif -
-
-@endsection diff --git a/resources/views/front/pages/ban-appeal/form.blade.php b/resources/views/front/pages/ban-appeal/form.blade.php new file mode 100644 index 000000000..9fee766af --- /dev/null +++ b/resources/views/front/pages/ban-appeal/form.blade.php @@ -0,0 +1,158 @@ +@extends('front.layouts.root-layout') + +@section('title', 'Appeal Ban') +@section('heading', 'Appeal Ban') +@section('description', 'Use the below form to submit a ban appeal') + +@section('body') + + +
+
+
+
+
+

+ Submit Your Appeal +

+

+ Please fill-in all fields with appropriate detail. Appeals with false or insufficient detail will likely be denied. +

+
+
+
+
+ +
+
+ @csrf + @include('front.components.form-error') + + @isset ($ban) +

Selected Ban

+ +
+ + +
+ {{ $ban->bannedPlayer->alias }} + UUID: {{ $ban->bannedPlayer->uuid }} + {{ $ban->created_at->format('jS \of M, Y - h:i A') }} +
+
+ + + @endisset + +

Ban Details

+ +
+
+ + + @error('minecraft_uuid') + {{ $message }} + @enderror +

+ Can be looked up here +

+
+ +
+ + + @error('date_of_ban') + {{ $message }} + @enderror +

+ If unknown, a rough estimate is also acceptable +

+
+
+ + + + + @error('ban_reason') + {{ $message }} + @enderror + +

Appeal

+ + + + @error('email') + {{ $message }} + @enderror +

+ Please check this carefully - updates to your appeal will be sent to this email address. +

+ + + + + + + Submit + +
+
+@endsection diff --git a/resources/views/front/pages/ban-appeal/index.blade.php b/resources/views/front/pages/ban-appeal/index.blade.php index 777620c9d..26f8124ec 100644 --- a/resources/views/front/pages/ban-appeal/index.blade.php +++ b/resources/views/front/pages/ban-appeal/index.blade.php @@ -1,31 +1,85 @@ -@extends('front.pages.ban-appeal._layout-form') - -@section('col-2') - @auth -
-

Current Bans

-
- @each('front.pages.ban-appeal._game-ban-listing', $bans, 'ban', 'front.pages.ban-appeal._game-ban-empty') +@extends('front.layouts.root-layout') + +@section('title', 'Appeal Ban') +@section('heading', 'Appeal Ban') +@section('description', 'Use the below form to submit a ban appeal') + +@section('body') + + +
+
+ @if($errors->any()) +
+

Error

+ {{ $errors->first() }} +
+ @endif + +
+
+
+

+ Appeal a Ban +

+

+ If you have been wrongfully banned, please let us know so we can investigate the matter. + Alternatively, if you are seeking a second chance, you may plead your case for consideration. +

+
+
+
+
+ +
+
+
+ + + + +

Select from list

+ +
+ Auto-fill some of your appeal details by selecting the ban from a list. + If logged-in, you'll be shown your active bans in addition to the main list. +
+ +
+ + + Proceed + + + + +
+ +
+ or +
+ +
+ + + + +

Fill out the form

+ +
+ No login required, but all details will need to be filled-in manually. +
+ +
+ + + Proceed + + + + +
-
-
-

Look up Account

-

If the ban doesn't appear above, try searching manually. Enter your current Minecraft - username.

- - @include('front.pages.ban-appeal._username-lookup') -
- @else -
-

Sign in to Appeal

-

To appeal a ban, sign in to your PCB account. Alternatively, you may appeal as a guest.

- Sign In -
-
-

Appeal as a Guest

-

To start your appeal, enter the current username of your Minecraft account

- - @include('front.pages.ban-appeal._username-lookup') -
- @endauth + + @endsection diff --git a/resources/views/front/pages/ban-appeal/search.blade.php b/resources/views/front/pages/ban-appeal/search.blade.php new file mode 100644 index 000000000..b401d71b5 --- /dev/null +++ b/resources/views/front/pages/ban-appeal/search.blade.php @@ -0,0 +1,144 @@ +@extends('front.layouts.root-layout') + +@section('title', 'Appeal Ban') +@section('heading', 'Appeal Ban') +@section('description', 'Use the below form to submit a ban appeal') + +@section('body') + + +
+
+ @if($errors->any()) +
+

Error

+ {{ $errors->first() }} +
+ @endif + +
+
+
+ + + + + Go Back + + +

+ Select the Ban +

+

+ Find and select the ban you wish to appeal. If you have trouble locating it, you can still fill out the form manually. +

+
+
+
+
+ + @auth +
+

Your Active Bans

+ + @if ($active_bans->count() > 0) + @foreach ($active_bans as $ban) +
+ + +
+ {{ $ban->bannedPlayer->alias }} + UUID: {{ $ban->bannedPlayer->uuid }} + {{ $ban->created_at->format('jS \of M, Y - h:i A') }} +
+ +
+ + View Details + + + Select + + + + +
+
+ @endforeach + @else +
+ No active bans found for any of your linked Minecraft accounts +
+ @endif +
+ @endauth + +
+

All Bans

+ +
+ +
+ + @if ($bans->count() > 0) +
+ + + + + + + + + + + @foreach($bans as $ban) + + + + + + + @endforeach + +
Player NameReasonBan Date
+ + {{ $ban->banned_alias_at_time }} + + {{ $ban->reason ?? "-" }} + + {{ $ban->created_at->format('j M Y H:i') }} + + + View Details + + + Select + + + + +
+
+ +
+ {{ $bans->links('vendor.pagination.default') }} +
+ @else +
+ + + +

No Results

+ Please try a different search criteria +
+ @endif +
+
+@endsection diff --git a/resources/views/front/pages/ban-appeal/show.blade.php b/resources/views/front/pages/ban-appeal/show.blade.php index 16251a46f..28a94dec3 100644 --- a/resources/views/front/pages/ban-appeal/show.blade.php +++ b/resources/views/front/pages/ban-appeal/show.blade.php @@ -1,86 +1,133 @@ -@extends('front.templates.2-col') +@extends('front.layouts.root-layout') + +@php + use App\Domains\BanAppeals\Data\BanAppealStatus; +@endphp @section('title', 'Your Ban Appeal') @section('heading', 'Ban Appeal') @section('description', 'Check the status of your ban appeal') -@section('col-1') -

- View the status of your ban appeal. You will be emailed with any updates. -

-

- Please note that you cannot submit another appeal until this appeal has been resolved. -

-@endsection +@section('body') + + +
+

Your Ban Appeal

+ +
+ Viewing the status of your ban appeal. You will be emailed with any updates. +
-@section('col-2') -
- @include('front.components.form-error') - @switch($banAppeal->status) - @case(\App\Domains\BanAppeals\Data\BanAppealStatus::PENDING) -
-

Appeal Pending

- Please wait whilst your appeal is reviewed by staff. This usually happens within 48 hours, but may - take - longer in some cases. + @if ($banAppeal->status->isDecided()) + @switch($banAppeal->status) + @case(BanAppealStatus::ACCEPTED_UNBAN) +
+

Unbanned

+ Your ban appeal has been accepted.
+ Please read the below response from staff, as it may contain important information to prevent you being banned in future. +
+ @break + @case(BanAppealStatus::ACCEPTED_TEMPBAN) +
+

Ban Reduced

+ Your appeal has been considered, and your ban has been reduced to a temporary ban.
+ You will be unbanned on {{ $banAppeal->gamePlayerBan->expires_at }} +
+ @break + @case(BanAppealStatus::DENIED) +
+

Appeal Denied

+ Sorry, your appeal was denied. The response from staff is shown below.
+ Please read and consider it carefully before making another appeal. +
+ @endswitch + @else +
+
+ + + +

In Review

- @break - @case(\App\Domains\BanAppeals\Data\BanAppealStatus::ACCEPTED_UNBAN) -
-

Appeal Accepted

- Your ban appeal has been accepted.
- You must read the response from staff, as it may contain important information to prevent - you being banned in future. + Staff are currently reviewing your case.
+ This usually happens within 48 hours, but may take longer in some cases. +
+ @endif + + @if($banAppeal->status->isDecided()) +
+
+ + + +

Response

- @break - @case(\App\Domains\BanAppeals\Data\BanAppealStatus::ACCEPTED_TEMPBAN) -
-

Ban reduced

-

Your appeal has been considered, and your ban has been reduced to a temporary ban.

-

You will be unbanned on {{ $banAppeal->gamePlayerBan->expires_at }}.

+ +
+ @empty($banAppeal->decision_note) + No decision message provided. + @else + {{ $banAppeal->decision_note }} + @endif
- @break - @case(\App\Domains\BanAppeals\Data\BanAppealStatus::DENIED) -
-

Appeal Denied

- Sorry, your appeal was denied. The response from staff is shown below.
- Please read and consider this before making another appeal. +
+ {{ $banAppeal->decided_at->format('M jS, Y - h:iA') }}
- @endswitch -
-
-

Your Appeal

-
-
-
- +
+ @endif + +
+

Your Appeal

+ +
+
+ Why you should be unbanned
-
-
- {{ $banAppeal->explanation }} -
-
- You • {{ $banAppeal->created_at }} -
+ {{ $banAppeal->unban_reason }} +
+ +
+ +

Ban Details

+ +
+
+ Date of Ban
+ {{ $banAppeal->date_of_ban }}
- @if($banAppeal->status->isDecided()) -
-
-
- @empty($banAppeal->decision_note) - No decision message provided. - @else - {{ $banAppeal->decision_note }} - @endif -
-
- {{$banAppeal->deciderAccount?->username }} • {{ $banAppeal->decided_at }} -
+ +
+
+ Minecraft UUID +
+ {{ $banAppeal->minecraft_uuid }} +
+ +
+
+ Reason for Ban +
+ {{ $banAppeal->ban_reason }} +
+ + @isset ($banAppeal->gamePlayerBan) +
+
+ Selected Ban
-
- +
+ + +
+ {{ $banAppeal->gamePlayerBan->bannedPlayer->alias }} + UUID: {{ $banAppeal->gamePlayerBan->bannedPlayer->uuid }} + {{ $banAppeal->gamePlayerBan->created_at->format('jS \of M, Y - h:i A') }} +
+ + + View +
@endif diff --git a/resources/views/front/pages/banlist.blade.php b/resources/views/front/pages/banlist.blade.php deleted file mode 100644 index 76a44ddc0..000000000 --- a/resources/views/front/pages/banlist.blade.php +++ /dev/null @@ -1,84 +0,0 @@ -@extends('front.layouts.root-layout') - -@section('title', 'Player Ban List') -@section('description', 'Players listed on this page are currently banned on one or more servers on our game network') - -@section('body') - - -
-

Banned Players

-
- List of players banned from our services. -
-
- If you feel you have been unfairly or incorrectly banned, please submit an appeal. -
-
- -
-
-
- -
-
- -
- @if (count($bans) === 0) -
- - - -

No Results

- Please try a different search criteria -
- @else - - - - - - - - - - - @foreach($bans as $ban) - - - - - - - @endforeach - -
Player NameReasonBan DateAction
- - {{ $ban->bannedPlayer?->alias ?? $ban->banned_alias_at_time }} - - {{ $ban->reason ?? "-" }} - - {{ $ban->created_at->format('j M Y H:i') }} - - - View Details - - - - -
- @endif -
- - -
- {{ $bans->links('vendor.pagination.default') }} -
-
-@endsection diff --git a/resources/views/front/pages/bans/index.blade.php b/resources/views/front/pages/bans/index.blade.php new file mode 100644 index 000000000..b18c9e58b --- /dev/null +++ b/resources/views/front/pages/bans/index.blade.php @@ -0,0 +1,88 @@ +@extends('front.layouts.root-layout') + +@section('title', 'Player Ban List') +@section('description', 'Players listed on this page are currently banned on one or more servers on our game network') + +@section('body') + + +
+

Banned Players

+
+ List of players banned from our services. +
+
+ If you feel you have been unfairly or incorrectly banned, please submit an appeal. +
+
+ +
+
+
+ +
+
+ +
+ @if (count($bans) === 0) +
+ + + +

No Results

+ Please try a different search criteria +
+ @else +
+ + + + + + + + + + + @foreach($bans as $ban) + + + + + + + @endforeach + +
Player NameReasonBan Date
+ + {{ $ban->bannedPlayer?->alias ?? $ban->banned_alias_at_time }} + + {{ $ban->reason ?? "-" }} + + {{ $ban->created_at->format('j M Y H:i') }} + + + Appeal + + + View Details + + + + +
+
+ @endif +
+ +
+ {{ $bans->links('vendor.pagination.default') }} +
+
+@endsection diff --git a/resources/views/front/pages/ban.blade.php b/resources/views/front/pages/bans/show.blade.php similarity index 82% rename from resources/views/front/pages/ban.blade.php rename to resources/views/front/pages/bans/show.blade.php index 05e675f9f..61d79c782 100644 --- a/resources/views/front/pages/ban.blade.php +++ b/resources/views/front/pages/bans/show.blade.php @@ -14,7 +14,19 @@ Back to Ban List -

Ban Details

+
+

Ban Details

+ + @if ($ban->isActive()) + + Appeal This Ban + + + + + + @endif +
diff --git a/resources/views/front/pages/donate/donate.blade.php b/resources/views/front/pages/donate/donate.blade.php index 3d1884371..b564cbeb7 100644 --- a/resources/views/front/pages/donate/donate.blade.php +++ b/resources/views/front/pages/donate/donate.blade.php @@ -50,10 +50,10 @@
-

+

Donation Tiers

-

+

Choose the amount that suits you.

As a thank you for your support, you'll receive perks based on the amount you donate. @@ -70,7 +70,7 @@

$4 - + for a month

@@ -131,7 +131,7 @@ class="w-full"

$8 - + for a month

@@ -214,7 +214,7 @@ class="w-full"

$15 - + for a month

@@ -300,7 +300,7 @@ class="w-full"
-

+

FAQ

@@ -333,7 +333,7 @@ class="w-full"
-

+

Legal

diff --git a/resources/views/front/templates/2-col.blade.php b/resources/views/front/templates/2-col.blade.php deleted file mode 100644 index 19478860a..000000000 --- a/resources/views/front/templates/2-col.blade.php +++ /dev/null @@ -1,19 +0,0 @@ -@extends('front.templates.master') - -@section('body') -
-
-

@yield('heading')

- -
- @yield('col-1') -
-
- -
- @yield('col-2') -
-
- - @include('front.components.footer') -@endsection diff --git a/resources/views/front/templates/master.blade.php b/resources/views/front/templates/master.blade.php deleted file mode 100644 index 7d194b4d4..000000000 --- a/resources/views/front/templates/master.blade.php +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @yield('title', 'Project City Build') - - @vite([ - 'resources/sass/front/front.scss', - 'resources/js/front/front.ts', - ]) - - @stack('head') - - - - - -
- @yield('body') -
- -@stack('end') - - - diff --git a/routes/web.php b/routes/web.php index 60466fd0d..69fdd8b0f 100644 --- a/routes/web.php +++ b/routes/web.php @@ -22,7 +22,8 @@ use App\Http\Controllers\Front\Auth\ReauthController; use App\Http\Controllers\Front\Auth\RegisterController; use App\Http\Controllers\Front\BanAppeal\BanAppealController; -use App\Http\Controllers\Front\BanAppeal\BanLookupController; +use App\Http\Controllers\Front\BanAppeal\BanAppealFormController; +use App\Http\Controllers\Front\BanAppeal\BanAppealSearchController; use App\Http\Controllers\Front\BanlistController; use App\Http\Controllers\Front\BuilderRankApplicationController; use App\Http\Controllers\Front\ContactController; @@ -71,12 +72,22 @@ }); Route::prefix('appeal')->group(function () { - Route::get('/', [BanAppealController::class, 'index']) + Route::view('/', 'front.pages.ban-appeal.index') ->name('front.appeal'); - Route::redirect('auth', '/appeal') - ->name('front.appeal.auth') - ->middleware('auth'); + Route::get('search', [BanAppealSearchController::class, 'index']) + ->name('front.appeal.search'); + + Route::prefix('create')->group(function () { + Route::get('/', [BanAppealFormController::class, 'index']) + ->name('front.appeal.form'); + + Route::post('/', [BanAppealFormController::class, 'store']) + ->name('front.appeal.form.submit'); + + Route::get('{ban}', [BanAppealFormController::class, 'show']) + ->name('front.appeal.form.prefilled'); + }); Route::get('{banAppeal}', [BanAppealController::class, 'show']) ->name('front.appeal.show'); @@ -86,16 +97,13 @@ Route::get('/', [BanlistController::class, 'index']) ->name('front.banlist'); - Route::post('/', BanLookupController::class) - ->name('front.bans.lookup'); - Route::get('{ban}', [BanlistController::class, 'show']) ->name('front.bans.details'); - Route::get('{ban}/appeal', [BanAppealController::class, 'create']) + Route::get('{ban}/appeal', [BanAppealFormController::class, 'create']) ->name('front.appeal.create'); - Route::post('{ban}/appeal', [BanAppealController::class, 'store']) + Route::post('{ban}/appeal', [BanAppealFormController::class, 'store']) ->name('front.appeal.submit'); }); diff --git a/tests/Integration/Front/BanAppealCreateTest.php b/tests/Integration/Front/BanAppealCreateTest.php deleted file mode 100644 index 151d0dd9d..000000000 --- a/tests/Integration/Front/BanAppealCreateTest.php +++ /dev/null @@ -1,132 +0,0 @@ -for(MinecraftPlayer::factory(), 'bannedPlayer') - ->create([ - 'reason' => 'Some Ban Reason', - ]); - } - - private function createBanWithAccount($login = false) - { - $ban = $this->createBan(); - $account = Account::factory()->create(); - $ban->bannedPlayer->account()->associate($account)->save(); - - if ($login) { - $this->actingAs($account); - } - - return $ban; - } - - private function submitAppealForBan(GamePlayerBan $ban, bool $withEmail = false): TestResponse - { - $data = [ - 'explanation' => 'My Ban Appeal', - ]; - - if ($withEmail) { - $data['email'] = 'test@example.org'; - } - - return $this->post(route('front.appeal.submit', $ban), $data); - } - - public function test_create_page_not_found_for_inactive_bans() - { - $ban = GamePlayerBan::factory()->inactive()->for(MinecraftPlayer::factory(), 'bannedPlayer')->create(); - $this->get(route('front.appeal.create', $ban)) - ->assertNotFound(); - } - - public function test_create_page_shows_for_player_with_bans() - { - $this->get(route('front.appeal.create', $this->createBan())) - ->assertSee('Appeal Form'); - } - - public function test_create_page_shows_active_ban_details() - { - $this->get(route('front.appeal.create', $this->createBan())) - ->assertSee('Some Ban Reason'); - } - - public function test_create_page_shows_past_ban_details() - { - $ban = $this->createBan(); - GamePlayerBan::factory()->inactive()->for($ban->bannedPlayer, 'bannedPlayer')->create(['reason' => 'My Expired Ban']); - $this->get(route('front.appeal.create', $ban)) - ->assertSee('My Expired Ban'); - } - - public function test_pending_appeal_redirects_to_appeal_with_account() - { - $ban = $this->createBanWithAccount(); - BanAppeal::factory()->for($ban)->create(); - $this->get(route('front.appeal.create', $ban)) - ->assertSee('appeal in progress'); - } - - public function test_pending_appeal_shows_notice_for_appeal_without_account() - { - $ban = $this->createBan(); - BanAppeal::factory()->for($ban)->create(); - $this->get(route('front.appeal.create', $ban)) - ->assertSee('Click the link in the appeal confirmation email'); - } - - public function test_can_submit_appeal() - { - $ban = $this->createBanWithAccount(true); - - $this->submitAppealForBan($ban) - ->assertSessionHasNoErrors() - ->assertRedirect(); - } - - public function test_redirects_to_unsigned_url_if_account_matches_player_owner() - { - $ban = $this->createBanWithAccount(true); - $this->submitAppealForBan($ban) - ->assertSessionHasNoErrors() - ->assertRedirect(route('front.appeal.show', BanAppeal::first())); - } - - public function test_redirects_to_signed_url_if_user_not_signed_in() - { - $ban = $this->createBanWithAccount(); - $this->submitAppealForBan($ban, true) - ->assertSessionHasNoErrors() - ->assertRedirectToSignedRoute('front.appeal.show', BanAppeal::first()); - } - - public function test_redirects_to_signed_url_if_signed_in_user_different() - { - $ban = $this->createBanWithAccount(); - $this->actingAs(Account::factory()->create()); - $this->submitAppealForBan($ban, true) - ->assertSessionHasNoErrors() - ->assertRedirectToSignedRoute('front.appeal.show', BanAppeal::first()); - } -} diff --git a/tests/Integration/Front/BanAppealListTest.php b/tests/Integration/Front/BanAppealListTest.php deleted file mode 100644 index 6f9adaafe..000000000 --- a/tests/Integration/Front/BanAppealListTest.php +++ /dev/null @@ -1,74 +0,0 @@ -get(route('front.appeal')) - ->assertOk() - ->assertSeeText('Sign in to Appeal') - ->assertSeeText('Appeal as a Guest'); - } - - private function createPlayerWithAccountAndLogin() - { - $account = Account::factory()->create(); - $player = MinecraftPlayer::factory()->for($account)->create(); - $this->actingAs($account); - - return $player; - } - - public function test_shows_ban() - { - $player = $this->createPlayerWithAccountAndLogin(); - - $ban = GamePlayerBan::factory() - ->for($player, 'bannedPlayer') - ->create(); - - $this->get(route('front.appeal')) - ->assertSee($ban->reason); - } - - public function test_shows_appeal() - { - $player = $this->createPlayerWithAccountAndLogin(); - - GamePlayerBan::factory() - ->for($player, 'bannedPlayer') - ->hasBanAppeals(1) - ->create(); - - $this->get(route('front.appeal')) - ->assertSee('Appeal #1'); - } - - public function test_shows_appeal_again() - { - $player = $this->createPlayerWithAccountAndLogin(); - - GamePlayerBan::factory() - ->for($player, 'bannedPlayer') - ->hasBanAppeals(1, ['status' => BanAppealStatus::DENIED]) - ->create(); - - $this->get(route('front.appeal')) - ->assertSeeIgnoringWhitespace('Appeal Again'); - } - - public function test_shows_no_bans_message() - { - $this->createPlayerWithAccountAndLogin(); - $this->get(route('front.appeal')) - ->assertSee('No Bans Found'); - } -} diff --git a/tests/Integration/Front/BanAppealViewTest.php b/tests/Integration/Front/BanAppealViewTest.php deleted file mode 100644 index 4a224551a..000000000 --- a/tests/Integration/Front/BanAppealViewTest.php +++ /dev/null @@ -1,53 +0,0 @@ -banAppeal = BanAppeal::factory() - ->for(GamePlayerBan::factory()->for(MinecraftPlayer::factory(), 'bannedPlayer')) - ->create(); - } - - public function test_can_view_ban_appeal_signed() - { - $signedUrl = URL::signedRoute('front.appeal.show', ['banAppeal' => $this->banAppeal]); - $this->get($signedUrl) - ->assertOk(); - } - - public function test_cant_view_ban_appeal_with_wrong_signature() - { - $this->get(route('front.appeal.show', ['banAppeal' => $this->banAppeal, 'signature' => 'foo'])) - ->assertForbidden(); - } - - public function test_can_view_if_player_owner_and_unsigned() - { - $account = Account::factory()->create(); - $this->banAppeal->gamePlayerBan->bannedPlayer->account()->associate($account)->save(); - $this->actingAs($account) - ->get(route('front.appeal.show', $this->banAppeal)) - ->assertOk(); - } - - public function test_cant_view_if_not_player_owner_and_unsigned() - { - $this->banAppeal->gamePlayerBan->bannedPlayer->account()->associate(Account::factory()->create())->save(); - $this->actingAs(Account::factory()->create()) - ->get(route('front.appeal.show', $this->banAppeal)) - ->assertForbidden(); - } -} diff --git a/tests/Integration/Front/BanLookupTest.php b/tests/Integration/Front/BanLookupTest.php deleted file mode 100644 index da9ab3ec1..000000000 --- a/tests/Integration/Front/BanLookupTest.php +++ /dev/null @@ -1,98 +0,0 @@ -mock(LookupPlayerBan::class, function (MockInterface $mock) use ($username, $ban) { - $mock->shouldReceive('execute') - ->with($username) - ->andReturn($ban); - }); - } - - private function mockUseCaseToThrow(string $exception) - { - $this->mock(LookupPlayerBan::class, function (MockInterface $mock) use ($exception) { - $mock->shouldReceive('execute') - ->andThrow($exception); - }); - } - - public function test_can_submit_lookup_as_guest() - { - $mcPlayer = MinecraftPlayer::factory()->create(); - $ban = GamePlayerBan::factory()->for($mcPlayer, 'bannedPlayer')->create(); - - $this->mockUseCaseToReturnBan('Herobrine', $ban); - - $this->post(route('front.bans.lookup'), ['username' => 'Herobrine']) - ->assertSessionHasNoErrors() - ->assertRedirect(route('front.appeal.create', $ban)); - } - - public function test_can_submit_lookup_as_user() - { - $this->actingAs(Account::factory()->create()); - $mcPlayer = MinecraftPlayer::factory()->create(); - $ban = GamePlayerBan::factory()->for($mcPlayer, 'bannedPlayer')->create(); - - $this->mockUseCaseToReturnBan('Herobrine', $ban); - - $this->post(route('front.bans.lookup'), ['username' => 'Herobrine']) - ->assertSessionHasNoErrors() - ->assertRedirect(route('front.appeal.create', $ban)); - } - - public function test_errors_if_throws_rate_limit() - { - $this->mockUseCaseToThrow(TooManyRequestsException::class); - $this->post(route('front.bans.lookup'), ['username' => 'Herobrine']) - ->assertSessionHasErrors(); - } - - public function test_errors_if_no_active_bans() - { - $mcPlayer = MinecraftPlayer::factory()->create(); - GamePlayerBan::factory()->inactive()->for($mcPlayer, 'bannedPlayer')->create(); - $this->mockUseCaseToReturnBan('Herobrine', null); - $this->post(route('front.bans.lookup'), ['username' => 'Herobrine']) - ->assertSessionHasErrors(); - } - - public function test_errors_if_no_bans() - { - MinecraftPlayer::factory()->create(); - $this->mockUseCaseToReturnBan('Herobrine', null); - $this->post(route('front.bans.lookup'), ['username' => 'Herobrine']) - ->assertSessionHasErrors(); - } - - public function test_errors_if_not_valid_username() - { - MinecraftPlayer::factory()->create(); - $this->mockUseCaseToReturnBan('Herobrine', null); - $this->post(route('front.bans.lookup'), ['username' => 'Herobrine']) - ->assertSessionHasErrors(); - } - - public function test_errors_if_player_not_known() - { - $this->mockUseCaseToReturnBan('Herobrine', null); - $this->post(route('front.bans.lookup'), ['username' => 'Herobrine']) - ->assertSessionHasErrors(); - } -} diff --git a/tests/TestCase.php b/tests/TestCase.php index f42f27f1e..e24326c3f 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -2,15 +2,12 @@ namespace Tests; -use App\Core\Domains\Mojang\Api\MojangPlayerApi; use App\Http\Middleware\MfaAuthenticated; use App\Models\Account; use App\Models\Group; use App\Models\ServerToken; -use Illuminate\Foundation\Testing\Concerns\MakesHttpRequests; use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Foundation\Testing\TestCase as BaseTestCase; -use Illuminate\Support\Carbon; use Illuminate\Support\Facades\Http; use Illuminate\Support\Facades\Session; use Tests\Support\TemporaryConfig; @@ -29,9 +26,6 @@ protected function setUp(): void $this->registerTestResponseMacros(); - // Mock this class everywhere to prevent it making real requests - $this->mock(MojangPlayerApi::class); - // Throw an exception if a HTTP response hasn't been mocked Http::preventStrayRequests(); } diff --git a/vite.config.mjs b/vite.config.mjs index 76b3e13f5..1f9d4979b 100644 --- a/vite.config.mjs +++ b/vite.config.mjs @@ -6,7 +6,7 @@ export default defineConfig({ plugins: [ laravel({ input: [ - 'resources/sass/front/front.scss', + 'resources/sass/front.scss', 'resources/js/front/front.ts', 'resources/js/manage/manage.ts', 'resources/sass/manage.scss',