From 3ae0bfd310349a59b0003ac68892ab9fcf6f230e Mon Sep 17 00:00:00 2001 From: Andy Saw <7236312+andyksaw@users.noreply.github.com> Date: Sat, 11 Jan 2025 12:16:13 +0000 Subject: [PATCH] feat: create reviews panel (#854) --- app/AppServiceProvider.php | 8 + .../{Entities => Data}/BanAppealStatus.php | 2 +- .../Exceptions/NoPlayerForActionException.php | 2 +- .../BanAppeals/UseCases/CreateBanAppeal.php | 2 +- .../BanAppeals/UseCases/UpdateBanAppeal.php | 4 +- .../Data/ApplicationStatus.php | 4 +- .../UseCases/ApproveBuildRankApplication.php | 23 +- .../UseCases/CreateBuildRankApplication.php | 4 +- .../UseCases/DenyBuildRankApplication.php | 3 + .../Components/ManageSideBarComponent.php | 25 -- app/Domains/Manage/ManageServiceProvider.php | 26 -- app/Domains/Manage/RendersManageApp.php | 17 + .../UseCases/UpdateSeenMinecraftPlayer.php | 5 +- app/Domains/Review/RendersReviewApp.php | 17 + .../BuilderRankApplicationController.php | 44 +-- .../Accounts/AccountBadgeController.php | 6 +- .../Manage/Accounts/AccountController.php | 13 +- .../Accounts/AccountGroupController.php | 6 +- .../Accounts/AccountPlayerController.php | 7 +- .../Manage/Badges/BadgeController.php | 10 +- .../Manage/Bans/GameIPBanController.php | 10 +- .../Manage/Bans/GamePlayerBanController.php | 9 +- .../Manage/Donations/DonationController.php | 11 +- .../Manage/Groups/GroupAccountController.php | 6 +- .../Manage/Groups/GroupController.php | 9 +- .../Controllers/Manage/HomeController.php | 6 +- .../Minecraft/MinecraftConfigController.php | 7 +- .../Minecraft/MinecraftWarpController.php | 9 +- .../Players/MinecraftPlayerController.php | 11 +- .../Manage/Servers/ServerController.php | 10 +- .../Manage/Servers/ServerTokenController.php | 10 +- .../Warnings/PlayerWarningController.php | 9 +- .../Review/BanAppeals/BanAppealController.php | 38 ++- .../BuilderRanks/BuilderRanksController.php | 35 +- .../Controllers/Review/HomeController.php | 17 + app/Http/Middleware/HandleInertiaRequests.php | 7 +- app/Http/Requests/BanAppealUpdateRequest.php | 4 +- .../BuilderRankApplicationRequest.php | 1 + app/Models/BanAppeal.php | 13 +- app/Models/MinecraftPlayer.php | 11 - bootstrap/providers.php | 1 - database/factories/BanAppealFactory.php | 4 +- .../BuilderRankApplicationFactory.php | 21 ++ database/seeders/AccountSeeder.php | 1 - database/seeders/BanAppealSeeder.php | 46 +++ .../seeders/BuilderRankApplicationSeeder.php | 46 +++ database/seeders/DatabaseSeeder.php | 33 +- resources/js/manage/Components/Dialog.vue | 43 +++ .../manage/Components/InfinitePagination.vue | 2 +- resources/js/manage/Components/Pill.vue | 4 +- resources/js/manage/Components/SvgIcon.vue | 9 + resources/js/manage/Data/BanAppeal.ts | 17 + resources/js/manage/Data/BanAppealStatus.ts | 6 + .../js/manage/Data/BuilderRankApplication.ts | 23 ++ .../js/manage/Layouts/Root/ManageLayout.vue | 16 + .../manage/Layouts/Root/Partials/NavBar.vue | 24 ++ .../js/manage/Layouts/Root/RootLayout.vue | 3 +- resources/js/manage/Pages/Home.vue | 2 - .../js/manage/Utilities/DateFormatter.ts | 20 +- resources/js/manage/manage.ts | 4 +- .../review/Layouts/Root/Partials/NavBar.vue | 64 ---- .../review/Layouts/Root/Partials/SideBar.vue | 121 ++----- .../Layouts/Root/Partials/SideBarMenuItem.vue | 83 ----- .../js/review/Layouts/Root/ReviewLayout.vue | 16 + .../js/review/Layouts/Root/RootLayout.vue | 16 - .../review/Pages/BanAppeals/BanAppealList.vue | 35 ++ .../review/Pages/BanAppeals/BanAppealShow.vue | 299 ++++++++++++++++++ .../Partials/BanAppealListTable.vue | 67 ++++ .../BuilderRankApplicationList.vue | 35 ++ .../BuilderRankApplicationShow.vue | 201 ++++++++++++ .../Partials/AwaitingDecisionAlert.vue | 19 ++ .../BuilderRankApplicationListTable.vue | 72 +++++ .../Partials/BuilderRankDecision.vue | 54 ++++ .../Partials/BuilderRankDecisionForm.vue | 131 ++++++++ resources/js/review/Pages/Home.vue | 8 + resources/js/review/review.ts | 4 +- resources/sass/front/front.scss | 2 + resources/sass/{manage => }/manage.scss | 0 resources/sass/{review => }/review.scss | 0 .../ban-appeal/_game-ban-listing.blade.php | 8 +- .../front/pages/ban-appeal/show.blade.php | 8 +- resources/views/manage/app.blade.php | 2 +- resources/views/review/app.blade.php | 2 +- routes/web.php | 2 +- routes/web_review.php | 24 +- tests/Integration/Front/BanAppealListTest.php | 2 +- 86 files changed, 1535 insertions(+), 526 deletions(-) rename app/Domains/BanAppeals/{Entities => Data}/BanAppealStatus.php (96%) rename app/Domains/{Manage => BanAppeals}/Exceptions/NoPlayerForActionException.php (63%) delete mode 100644 app/Domains/Manage/Components/ManageSideBarComponent.php delete mode 100644 app/Domains/Manage/ManageServiceProvider.php create mode 100644 app/Domains/Manage/RendersManageApp.php create mode 100644 app/Domains/Review/RendersReviewApp.php create mode 100644 app/Http/Controllers/Review/HomeController.php create mode 100644 database/seeders/BanAppealSeeder.php create mode 100644 database/seeders/BuilderRankApplicationSeeder.php create mode 100644 resources/js/manage/Components/Dialog.vue create mode 100644 resources/js/manage/Data/BanAppeal.ts create mode 100644 resources/js/manage/Data/BanAppealStatus.ts create mode 100644 resources/js/manage/Data/BuilderRankApplication.ts create mode 100644 resources/js/manage/Layouts/Root/ManageLayout.vue delete mode 100644 resources/js/review/Layouts/Root/Partials/NavBar.vue delete mode 100644 resources/js/review/Layouts/Root/Partials/SideBarMenuItem.vue create mode 100644 resources/js/review/Layouts/Root/ReviewLayout.vue delete mode 100644 resources/js/review/Layouts/Root/RootLayout.vue create mode 100644 resources/js/review/Pages/BanAppeals/BanAppealList.vue create mode 100644 resources/js/review/Pages/BanAppeals/BanAppealShow.vue create mode 100644 resources/js/review/Pages/BanAppeals/Partials/BanAppealListTable.vue create mode 100644 resources/js/review/Pages/BuilderRankApplications/BuilderRankApplicationList.vue create mode 100644 resources/js/review/Pages/BuilderRankApplications/BuilderRankApplicationShow.vue create mode 100644 resources/js/review/Pages/BuilderRankApplications/Partials/AwaitingDecisionAlert.vue create mode 100644 resources/js/review/Pages/BuilderRankApplications/Partials/BuilderRankApplicationListTable.vue create mode 100644 resources/js/review/Pages/BuilderRankApplications/Partials/BuilderRankDecision.vue create mode 100644 resources/js/review/Pages/BuilderRankApplications/Partials/BuilderRankDecisionForm.vue create mode 100644 resources/js/review/Pages/Home.vue rename resources/sass/{manage => }/manage.scss (100%) rename resources/sass/{review => }/review.scss (100%) diff --git a/app/AppServiceProvider.php b/app/AppServiceProvider.php index fa1b33b33..c19712fea 100644 --- a/app/AppServiceProvider.php +++ b/app/AppServiceProvider.php @@ -21,6 +21,7 @@ use Illuminate\Http\Request; use Illuminate\Support\Carbon; use Illuminate\Support\Facades\Blade; +use Illuminate\Support\Facades\Gate; use Illuminate\Support\Facades\RateLimiter; use Illuminate\Support\ServiceProvider; use Illuminate\Validation\Rules\Password; @@ -65,6 +66,13 @@ public function boot() ? Password::min(12)->letters()->numbers() : Password::min(8); }); + + Gate::define('access-manage', function (Account $account) { + return $account->isAdmin() || $account->isStaff(); + }); + Gate::define('access-review', function (Account $account) { + return $account->isAdmin() || $account->isStaff() || $account->isArchitect(); + }); } private function enforceMorphMap(): void diff --git a/app/Domains/BanAppeals/Entities/BanAppealStatus.php b/app/Domains/BanAppeals/Data/BanAppealStatus.php similarity index 96% rename from app/Domains/BanAppeals/Entities/BanAppealStatus.php rename to app/Domains/BanAppeals/Data/BanAppealStatus.php index 2592edb4d..641094628 100644 --- a/app/Domains/BanAppeals/Entities/BanAppealStatus.php +++ b/app/Domains/BanAppeals/Data/BanAppealStatus.php @@ -1,6 +1,6 @@ 'In progress', + self::PENDING => 'Pending', self::APPROVED => 'Approved', self::DENIED => 'Denied', }; diff --git a/app/Domains/BuilderRankApplications/UseCases/ApproveBuildRankApplication.php b/app/Domains/BuilderRankApplications/UseCases/ApproveBuildRankApplication.php index 6891c086d..e2ce23757 100644 --- a/app/Domains/BuilderRankApplications/UseCases/ApproveBuildRankApplication.php +++ b/app/Domains/BuilderRankApplications/UseCases/ApproveBuildRankApplication.php @@ -6,6 +6,7 @@ use App\Domains\BuilderRankApplications\Notifications\BuilderRankAppApprovedNotification; use App\Models\BuilderRankApplication; use App\Models\Group; +use Illuminate\Support\Facades\DB; class ApproveBuildRankApplication { @@ -13,14 +14,26 @@ public function execute( int $applicationId, int $promoteGroupId, ): BuilderRankApplication { + $application = BuilderRankApplication::find($applicationId); $promoteGroup = Group::find($promoteGroupId); - $application = BuilderRankApplication::find($applicationId); - $application->status = ApplicationStatus::APPROVED->value; - $application->closed_at = now(); - $application->save(); + abort_if($application->isReviewed(), 409); + + DB::transaction(function () use ($application, $promoteGroup) { + $application->status = ApplicationStatus::APPROVED->value; + $application->closed_at = now(); + $application->save(); + + $updatedGroupIds = $application + ->account + ->groups() + ->where('group_type', '!=', 'build') + ->get() + ->map(fn ($it) => $it->getKey()) + ->push($promoteGroup->getKey()); - $application->account->groups()->attach($promoteGroup->getKey()); + $application->account->groups()->sync($updatedGroupIds); + }); $application->account->notify( new BuilderRankAppApprovedNotification( diff --git a/app/Domains/BuilderRankApplications/UseCases/CreateBuildRankApplication.php b/app/Domains/BuilderRankApplications/UseCases/CreateBuildRankApplication.php index daf1ebb3a..ecfa2d14a 100644 --- a/app/Domains/BuilderRankApplications/UseCases/CreateBuildRankApplication.php +++ b/app/Domains/BuilderRankApplications/UseCases/CreateBuildRankApplication.php @@ -22,7 +22,7 @@ public function execute( string $buildDescription, ?string $additionalNotes, ): BuilderRankApplication { - $existingApplication = BuilderRankApplication::where('status', ApplicationStatus::IN_PROGRESS->value) + $existingApplication = BuilderRankApplication::where('status', ApplicationStatus::PENDING->value) ->where('account_id', $account->getKey()) ->count(); @@ -37,7 +37,7 @@ public function execute( 'build_location' => $buildLocation, 'build_description' => $buildDescription, 'additional_notes' => $additionalNotes, - 'status' => ApplicationStatus::IN_PROGRESS->value, + 'status' => ApplicationStatus::PENDING->value, 'closed_at' => null, ]); diff --git a/app/Domains/BuilderRankApplications/UseCases/DenyBuildRankApplication.php b/app/Domains/BuilderRankApplications/UseCases/DenyBuildRankApplication.php index 0fa6b9181..413f9d74e 100644 --- a/app/Domains/BuilderRankApplications/UseCases/DenyBuildRankApplication.php +++ b/app/Domains/BuilderRankApplications/UseCases/DenyBuildRankApplication.php @@ -13,6 +13,9 @@ public function execute( string $denyReason, ): BuilderRankApplication { $application = BuilderRankApplication::find($applicationId); + + abort_if($application->isReviewed(), 409); + $application->status = ApplicationStatus::DENIED->value; $application->denied_reason = $denyReason; $application->closed_at = now(); diff --git a/app/Domains/Manage/Components/ManageSideBarComponent.php b/app/Domains/Manage/Components/ManageSideBarComponent.php deleted file mode 100644 index dbed2bf7b..000000000 --- a/app/Domains/Manage/Components/ManageSideBarComponent.php +++ /dev/null @@ -1,25 +0,0 @@ -value)->count(); - $outstandingBanAppeals = BanAppeal::pending()->count(); - - return view('manage.layouts._sidebar', [ - 'outgoing_rank_apps' => $outgoingRankApplications, - 'outstanding_ban_appeals' => $outstandingBanAppeals, - ]); - } -} diff --git a/app/Domains/Manage/ManageServiceProvider.php b/app/Domains/Manage/ManageServiceProvider.php deleted file mode 100644 index a082e8c49..000000000 --- a/app/Domains/Manage/ManageServiceProvider.php +++ /dev/null @@ -1,26 +0,0 @@ -isAdmin() || $account->isStaff() || $account->isArchitect(); - }); - - Blade::component('panel-side-bar', ManageSideBarComponent::class); - } -} diff --git a/app/Domains/Manage/RendersManageApp.php b/app/Domains/Manage/RendersManageApp.php new file mode 100644 index 000000000..284e6127a --- /dev/null +++ b/app/Domains/Manage/RendersManageApp.php @@ -0,0 +1,17 @@ +getRawModel(); - $minecraftPlayer->last_seen_at = now(); - $minecraftPlayer->save(); + $player->last_seen_at = now(); + $player->save(); } } diff --git a/app/Domains/Review/RendersReviewApp.php b/app/Domains/Review/RendersReviewApp.php new file mode 100644 index 000000000..454fa6baf --- /dev/null +++ b/app/Domains/Review/RendersReviewApp.php @@ -0,0 +1,17 @@ +with(compact('application')); + } + + public function create( Request $request, ) { + Gate::authorize('create', BuilderRankApplication::class); + $minecraftUsername = $request->user() ?->minecraftAccount ?->first() ?->alias; - $applicationInProgress = BuilderRankApplication::where('status', ApplicationStatus::IN_PROGRESS->value) + $applicationInProgress = BuilderRankApplication::where('status', ApplicationStatus::PENDING->value) ->where('account_id', $request->user()->getKey()) ->orderBy('created_at', 'DESC') ->first(); if ($applicationInProgress !== null) { - return redirect() - ->route('front.rank-up.status', $applicationInProgress->getKey()); + return to_route('front.rank-up.status', $applicationInProgress->getKey()); } return view('front.pages.builder-rank.builder-rank-form') ->with(compact('minecraftUsername')); } - public function show( - Request $request, - BuilderRankApplication $application, - ) { - Gate::authorize('view', $application); - - return view('front.pages.builder-rank.builder-rank-status') - ->with(compact('application')); - } - public function store( BuilderRankApplicationRequest $request, CreateBuildRankApplication $createBuildRankApplication, ) { Gate::authorize('create', BuilderRankApplication::class); - $input = $request->validated(); + $validated = $request->validated(); $account = $request->user(); try { $application = $createBuildRankApplication->execute( account: $account, - minecraftAlias: $input['minecraft_username'], - currentBuilderRank: BuilderRank::from($input['current_builder_rank']), - buildLocation: $input['build_location'], - buildDescription: $input['build_description'], - additionalNotes: $request->get('additional_notes'), + minecraftAlias: $validated['minecraft_username'], + currentBuilderRank: BuilderRank::from($validated['current_builder_rank']), + buildLocation: $validated['build_location'], + buildDescription: $validated['build_description'], + additionalNotes: $validated['additional_notes'], ); - return redirect() - ->route('front.rank-up.status', $application->getKey()); + return to_route('front.rank-up.status', $application->getKey()); } catch (ApplicationAlreadyInProgressException) { return redirect() diff --git a/app/Http/Controllers/Manage/Accounts/AccountBadgeController.php b/app/Http/Controllers/Manage/Accounts/AccountBadgeController.php index 5df4f1c81..99fb16c1e 100644 --- a/app/Http/Controllers/Manage/Accounts/AccountBadgeController.php +++ b/app/Http/Controllers/Manage/Accounts/AccountBadgeController.php @@ -2,15 +2,17 @@ namespace App\Http\Controllers\Manage\Accounts; +use App\Domains\Manage\RendersManageApp; use App\Domains\MinecraftEventBus\Events\MinecraftPlayerUpdated; use App\Models\Account; use App\Models\Badge; use Illuminate\Http\Request; use Illuminate\Support\Facades\Gate; -use Inertia\Inertia; class AccountBadgeController { + use RendersManageApp; + public function index(Request $request, Account $account) { Gate::authorize('viewAny', Account::class); @@ -18,7 +20,7 @@ public function index(Request $request, Account $account) $badges = Badge::get(); $accountBadgeIds = $account->badges->pluck(Badge::primaryKey()); - return Inertia::render('Accounts/AccountBadgeSelect', [ + return $this->inertiaRender('Accounts/AccountBadgeSelect', [ 'badges' => $badges, 'account_badge_ids' => $accountBadgeIds ?? [], 'account_id' => $account->getKey(), diff --git a/app/Http/Controllers/Manage/Accounts/AccountController.php b/app/Http/Controllers/Manage/Accounts/AccountController.php index 48d1a3ae3..a745ec999 100644 --- a/app/Http/Controllers/Manage/Accounts/AccountController.php +++ b/app/Http/Controllers/Manage/Accounts/AccountController.php @@ -3,7 +3,7 @@ namespace App\Http\Controllers\Manage\Accounts; use App\Core\Rules\DiscourseUsernameRule; -use App\Domains\Registration\Events\AccountCreated; +use App\Domains\Manage\RendersManageApp; use App\Domains\Registration\UseCases\CreateUnactivatedAccount; use App\Http\Controllers\WebController; use App\Http\Filters\EqualFilter; @@ -15,10 +15,11 @@ use Illuminate\Support\Facades\Pipeline; use Illuminate\Validation\Rule; use Illuminate\Validation\Rules\Password; -use Inertia\Inertia; class AccountController extends WebController { + use RendersManageApp; + public function index(Request $request) { Gate::authorize('viewAny', Account::class); @@ -38,7 +39,7 @@ public function index(Request $request) if ($request->wantsJson()) { return $accounts; } - return Inertia::render('Accounts/AccountList', compact('accounts')); + return $this->inertiaRender('Accounts/AccountList', compact('accounts')); } public function show(Account $account) @@ -54,14 +55,14 @@ public function show(Account $account) 'donations', ]); - return Inertia::render('Accounts/AccountShow', compact('account')); + return $this->inertiaRender('Accounts/AccountShow', compact('account')); } public function create() { Gate::authorize('create', Account::class); - return Inertia::render('Accounts/AccountCreate'); + return $this->inertiaRender('Accounts/AccountCreate'); } public function store(Request $request, CreateUnactivatedAccount $createUnactivatedAccount) @@ -97,7 +98,7 @@ public function edit(Account $account) { Gate::authorize('update', $account); - return Inertia::render('Accounts/AccountEdit', compact('account')); + return $this->inertiaRender('Accounts/AccountEdit', compact('account')); } public function update(Request $request, Account $account) diff --git a/app/Http/Controllers/Manage/Accounts/AccountGroupController.php b/app/Http/Controllers/Manage/Accounts/AccountGroupController.php index 2d8eb6f81..7cd528346 100644 --- a/app/Http/Controllers/Manage/Accounts/AccountGroupController.php +++ b/app/Http/Controllers/Manage/Accounts/AccountGroupController.php @@ -2,15 +2,17 @@ namespace App\Http\Controllers\Manage\Accounts; +use App\Domains\Manage\RendersManageApp; use App\Http\Controllers\WebController; use App\Models\Account; use App\Models\Group; use Illuminate\Http\Request; use Illuminate\Support\Facades\Gate; -use Inertia\Inertia; class AccountGroupController extends WebController { + use RendersManageApp; + public function index(Request $request, Account $account) { Gate::authorize('viewAny', Account::class); @@ -18,7 +20,7 @@ public function index(Request $request, Account $account) $groups = Group::where('is_default', false)->get(); $accountGroupIds = $account->groups->pluck(Group::primaryKey()); - return Inertia::render('Accounts/AccountGroupSelect', [ + return $this->inertiaRender('Accounts/AccountGroupSelect', [ 'groups' => $groups, 'account_group_ids' => $accountGroupIds ?? [], 'account_id' => $account->getKey(), diff --git a/app/Http/Controllers/Manage/Accounts/AccountPlayerController.php b/app/Http/Controllers/Manage/Accounts/AccountPlayerController.php index 261d3e113..65ddb72c8 100644 --- a/app/Http/Controllers/Manage/Accounts/AccountPlayerController.php +++ b/app/Http/Controllers/Manage/Accounts/AccountPlayerController.php @@ -4,21 +4,22 @@ use App\Core\Domains\MinecraftUUID\Data\MinecraftUUID; use App\Core\Domains\MinecraftUUID\Rules\MinecraftUUIDRule; +use App\Domains\Manage\RendersManageApp; use App\Http\Controllers\WebController; use App\Models\Account; -use App\Models\Group; use App\Models\MinecraftPlayer; use Illuminate\Http\Request; use Illuminate\Support\Facades\Gate; -use Inertia\Inertia; class AccountPlayerController extends WebController { + use RendersManageApp; + public function create(Request $request, Account $account) { Gate::authorize('update', $account); - return Inertia::render('Accounts/AccountPlayerSelect', [ + return $this->inertiaRender('Accounts/AccountPlayerSelect', [ 'account_id' => $account->getKey(), ]); } diff --git a/app/Http/Controllers/Manage/Badges/BadgeController.php b/app/Http/Controllers/Manage/Badges/BadgeController.php index 947dc75d7..3cec9a4f7 100644 --- a/app/Http/Controllers/Manage/Badges/BadgeController.php +++ b/app/Http/Controllers/Manage/Badges/BadgeController.php @@ -2,14 +2,16 @@ namespace App\Http\Controllers\Manage\Badges; +use App\Domains\Manage\RendersManageApp; use App\Http\Controllers\WebController; use App\Models\Badge; use Illuminate\Http\Request; use Illuminate\Support\Facades\Gate; -use Inertia\Inertia; class BadgeController extends WebController { + use RendersManageApp; + public function index(Request $request) { Gate::authorize('viewAny', Badge::class); @@ -20,14 +22,14 @@ public function index(Request $request) if ($request->wantsJson()) { return $badges; } - return Inertia::render('Badges/BadgeList', compact('badges')); + return $this->inertiaRender('Badges/BadgeList', compact('badges')); } public function create(Request $request) { Gate::authorize('create', Badge::class); - return Inertia::render('Badges/BadgeCreate'); + return $this->inertiaRender('Badges/BadgeCreate'); } public function store(Request $request) @@ -57,7 +59,7 @@ public function edit(Badge $badge) { Gate::authorize('update', $badge); - return Inertia::render('Badges/BadgeEdit', compact('badge')); + return $this->inertiaRender('Badges/BadgeEdit', compact('badge')); } public function update(Request $request, Badge $badge) diff --git a/app/Http/Controllers/Manage/Bans/GameIPBanController.php b/app/Http/Controllers/Manage/Bans/GameIPBanController.php index d336e783c..ea76f1e4b 100644 --- a/app/Http/Controllers/Manage/Bans/GameIPBanController.php +++ b/app/Http/Controllers/Manage/Bans/GameIPBanController.php @@ -4,16 +4,18 @@ 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\WebController; use App\Models\GameIPBan; use App\Models\MinecraftPlayer; use Illuminate\Http\Request; use Illuminate\Support\Facades\Gate; -use Inertia\Inertia; class GameIPBanController extends WebController { + use RendersManageApp; + public function index(Request $request) { Gate::authorize('viewAny', GameIPBan::class); @@ -25,14 +27,14 @@ public function index(Request $request) if (request()->wantsJson()) { return $bans; } - return Inertia::render('IPBans/IPBanList', compact('bans')); + return $this->inertiaRender('IPBans/IPBanList', compact('bans')); } public function create(Request $request) { Gate::authorize('create', GameIPBan::class); - return Inertia::render('IPBans/IPBanCreate'); + return $this->inertiaRender('IPBans/IPBanCreate'); } public function store(Request $request) @@ -65,7 +67,7 @@ public function edit(GameIPBan $ipBan) $ipBan->load('bannerPlayer'); - return Inertia::render('IPBans/IPBanEdit', [ + return $this->inertiaRender('IPBans/IPBanEdit', [ 'ban' => $ipBan, ]); } diff --git a/app/Http/Controllers/Manage/Bans/GamePlayerBanController.php b/app/Http/Controllers/Manage/Bans/GamePlayerBanController.php index eafc10ec7..b5ad95a5e 100644 --- a/app/Http/Controllers/Manage/Bans/GamePlayerBanController.php +++ b/app/Http/Controllers/Manage/Bans/GamePlayerBanController.php @@ -5,6 +5,7 @@ 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\WebController; use App\Models\GamePlayerBan; @@ -16,6 +17,8 @@ class GamePlayerBanController extends WebController { + use RendersManageApp; + public function index(Request $request) { Gate::authorize('viewAny', GamePlayerBan::class); @@ -27,7 +30,7 @@ public function index(Request $request) if (request()->wantsJson()) { return $bans; } - return Inertia::render('PlayerBans/PlayerBanList', compact('bans')); + return $this->inertiaRender('PlayerBans/PlayerBanList', compact('bans')); } public function create(Request $request) @@ -37,7 +40,7 @@ public function create(Request $request) $account = $request->user(); $account->load('minecraftAccount'); - return Inertia::render('PlayerBans/PlayerBanCreate', [ + return $this->inertiaRender('PlayerBans/PlayerBanCreate', [ 'account' => $account, ]); } @@ -84,7 +87,7 @@ public function edit(GamePlayerBan $playerBan) $playerBan->load('bannedPlayer', 'bannerPlayer', 'unbannerPlayer'); - return Inertia::render('PlayerBans/PlayerBanEdit', [ + return $this->inertiaRender('PlayerBans/PlayerBanEdit', [ 'ban' => $playerBan, ]); } diff --git a/app/Http/Controllers/Manage/Donations/DonationController.php b/app/Http/Controllers/Manage/Donations/DonationController.php index e9dd2e9a9..03f4e79b0 100644 --- a/app/Http/Controllers/Manage/Donations/DonationController.php +++ b/app/Http/Controllers/Manage/Donations/DonationController.php @@ -2,6 +2,7 @@ namespace App\Http\Controllers\Manage\Donations; +use App\Domains\Manage\RendersManageApp; use App\Http\Controllers\WebController; use App\Models\Donation; use Illuminate\Http\Request; @@ -10,6 +11,8 @@ class DonationController extends WebController { + use RendersManageApp; + public function index(Request $request) { Gate::authorize('viewAny', Donation::class); @@ -21,7 +24,7 @@ public function index(Request $request) if (request()->wantsJson()) { return $donations; } - return Inertia::render( + return $this->inertiaRender( 'Donations/DonationList', compact('donations'), ); @@ -33,7 +36,7 @@ public function show(Donation $donation) $donation->load('perks', 'perks.account'); - return Inertia::render( + return $this->inertiaRender( 'Donations/DonationShow', compact('donation'), ); @@ -43,7 +46,7 @@ public function create(Request $request) { Gate::authorize('create', Donation::class); - return Inertia::render('Donations/DonationCreate'); + return $this->inertiaRender('Donations/DonationCreate'); } public function store(Request $request) @@ -66,7 +69,7 @@ public function edit(Donation $donation) { Gate::authorize('update', $donation); - return Inertia::render( + return $this->inertiaRender( 'Donations/DonationEdit', compact('donation'), ); diff --git a/app/Http/Controllers/Manage/Groups/GroupAccountController.php b/app/Http/Controllers/Manage/Groups/GroupAccountController.php index 50a85bc16..527157f9f 100644 --- a/app/Http/Controllers/Manage/Groups/GroupAccountController.php +++ b/app/Http/Controllers/Manage/Groups/GroupAccountController.php @@ -2,15 +2,17 @@ namespace App\Http\Controllers\Manage\Groups; +use App\Domains\Manage\RendersManageApp; use App\Http\Controllers\WebController; use App\Models\Account; use App\Models\Group; use Illuminate\Http\Request; use Illuminate\Support\Facades\Gate; -use Inertia\Inertia; class GroupAccountController extends WebController { + use RendersManageApp; + public function index(Request $request, Group $group) { Gate::authorize('view', $group); @@ -26,7 +28,7 @@ public function index(Request $request, Group $group) if ($request->wantsJson()) { return $accounts; } - return Inertia::render( + return $this->inertiaRender( 'Groups/GroupAccountList', compact('accounts', 'group'), ); diff --git a/app/Http/Controllers/Manage/Groups/GroupController.php b/app/Http/Controllers/Manage/Groups/GroupController.php index ccc8a5900..f70990620 100644 --- a/app/Http/Controllers/Manage/Groups/GroupController.php +++ b/app/Http/Controllers/Manage/Groups/GroupController.php @@ -2,6 +2,7 @@ namespace App\Http\Controllers\Manage\Groups; +use App\Domains\Manage\RendersManageApp; use App\Http\Controllers\WebController; use App\Models\Account; use App\Models\Group; @@ -13,6 +14,8 @@ class GroupController extends WebController { + use RendersManageApp; + public function index() { Gate::authorize('viewAny', Group::class); @@ -27,14 +30,14 @@ public function index() ->where('is_default', true) ->map(fn ($group) => $group->accounts_count = Account::doesntHave('groups')->count()); - return Inertia::render('Groups/GroupList', compact('groups')); + return $this->inertiaRender('Groups/GroupList', compact('groups')); } public function create(Request $request) { Gate::authorize('create', Group::class); - return Inertia::render('Groups/GroupCreate'); + return $this->inertiaRender('Groups/GroupCreate'); } public function store(Request $request): RedirectResponse @@ -61,7 +64,7 @@ public function edit(Group $group) { Gate::authorize('update', $group); - return Inertia::render('Groups/GroupEdit', compact('group')); + return $this->inertiaRender('Groups/GroupEdit', compact('group')); } public function update(Request $request, Group $group): RedirectResponse diff --git a/app/Http/Controllers/Manage/HomeController.php b/app/Http/Controllers/Manage/HomeController.php index 68c770a05..eeca9f9a7 100644 --- a/app/Http/Controllers/Manage/HomeController.php +++ b/app/Http/Controllers/Manage/HomeController.php @@ -2,14 +2,16 @@ namespace App\Http\Controllers\Manage; +use App\Domains\Manage\RendersManageApp; use App\Http\Controllers\WebController; use Illuminate\Http\Request; -use Inertia\Inertia; class HomeController extends WebController { + use RendersManageApp; + public function __invoke(Request $request) { - return Inertia::render('Home'); + return $this->inertiaRender('Home'); } } diff --git a/app/Http/Controllers/Manage/Minecraft/MinecraftConfigController.php b/app/Http/Controllers/Manage/Minecraft/MinecraftConfigController.php index 909e6ade6..b65886943 100644 --- a/app/Http/Controllers/Manage/Minecraft/MinecraftConfigController.php +++ b/app/Http/Controllers/Manage/Minecraft/MinecraftConfigController.php @@ -2,23 +2,24 @@ namespace App\Http\Controllers\Manage\Minecraft; +use App\Domains\Manage\RendersManageApp; use App\Domains\MinecraftEventBus\Events\MinecraftConfigUpdated; use App\Http\Controllers\WebController; use App\Models\MinecraftConfig; -use App\Models\MinecraftPlayer; use Illuminate\Http\Request; use Illuminate\Support\Facades\Gate; -use Inertia\Inertia; class MinecraftConfigController extends WebController { + use RendersManageApp; + public function create() { Gate::authorize('create', MinecraftConfig::class); $config = MinecraftConfig::byLatest()->first(); - return Inertia::render('MinecraftConfig/MinecraftConfig',[ + return $this->inertiaRender('MinecraftConfig/MinecraftConfig',[ 'config' => $config, ]); } diff --git a/app/Http/Controllers/Manage/Minecraft/MinecraftWarpController.php b/app/Http/Controllers/Manage/Minecraft/MinecraftWarpController.php index 099878f6d..7ecd567eb 100644 --- a/app/Http/Controllers/Manage/Minecraft/MinecraftWarpController.php +++ b/app/Http/Controllers/Manage/Minecraft/MinecraftWarpController.php @@ -3,16 +3,17 @@ namespace App\Http\Controllers\Manage\Minecraft; use App\Core\Domains\MinecraftCoordinate\ValidatesCoordinates; +use App\Domains\Manage\RendersManageApp; use App\Http\Controllers\WebController; use App\Models\MinecraftWarp; use Illuminate\Http\RedirectResponse; use Illuminate\Http\Request; use Illuminate\Support\Facades\Gate; use Illuminate\Validation\Rule; -use Inertia\Inertia; class MinecraftWarpController extends WebController { + use RendersManageApp; use ValidatesCoordinates; public function index(Request $request) @@ -25,14 +26,14 @@ public function index(Request $request) if (request()->wantsJson()) { return $warps; } - return Inertia::render('Warps/WarpList', compact('warps')); + return $this->inertiaRender('Warps/WarpList', compact('warps')); } public function create(Request $request) { Gate::authorize('create', MinecraftWarp::class); - return Inertia::render('Warps/WarpCreate'); + return $this->inertiaRender('Warps/WarpCreate'); } public function store(Request $request): RedirectResponse @@ -54,7 +55,7 @@ public function edit(MinecraftWarp $warp) { Gate::authorize('update', $warp); - return Inertia::render('Warps/WarpEdit', compact('warp')); + return $this->inertiaRender('Warps/WarpEdit', compact('warp')); } public function update(Request $request, MinecraftWarp $warp) diff --git a/app/Http/Controllers/Manage/Players/MinecraftPlayerController.php b/app/Http/Controllers/Manage/Players/MinecraftPlayerController.php index e7cfa64e2..0d0e6210f 100644 --- a/app/Http/Controllers/Manage/Players/MinecraftPlayerController.php +++ b/app/Http/Controllers/Manage/Players/MinecraftPlayerController.php @@ -6,6 +6,7 @@ use App\Core\Domains\MinecraftUUID\Rules\MinecraftUUIDRule; use App\Core\Domains\MinecraftUUID\UseCases\LookupMinecraftUUID; use App\Core\Domains\Mojang\Api\MojangPlayerApi; +use App\Domains\Manage\RendersManageApp; use App\Http\Controllers\WebController; use App\Models\MinecraftPlayer; use Illuminate\Http\Request; @@ -17,6 +18,8 @@ class MinecraftPlayerController extends WebController { + use RendersManageApp; + public function index() { Gate::authorize('viewAny', MinecraftPlayer::class); @@ -28,7 +31,7 @@ public function index() if (request()->wantsJson()) { return $minecraftPlayers; } - return Inertia::render('Players/PlayerList', [ + return $this->inertiaRender('Players/PlayerList', [ 'players' => $minecraftPlayers, ]); } @@ -39,14 +42,14 @@ public function show(MinecraftPlayer $player) $player->load(['account']); - return Inertia::render('Players/PlayerShow', compact('player')); + return $this->inertiaRender('Players/PlayerShow', compact('player')); } public function create() { Gate::authorize('create', MinecraftPlayer::class); - return Inertia::render('Players/PlayerCreate'); + return $this->inertiaRender('Players/PlayerCreate'); } public function store(Request $request, LookupMinecraftUUID $lookupMinecraftUUID) @@ -91,7 +94,7 @@ public function edit(MinecraftPlayer $player) { Gate::authorize('update', $player); - return Inertia::render('Players/PlayerEdit', compact('player')); + return $this->inertiaRender('Players/PlayerEdit', compact('player')); } public function update(Request $request, MinecraftPlayer $player) diff --git a/app/Http/Controllers/Manage/Servers/ServerController.php b/app/Http/Controllers/Manage/Servers/ServerController.php index 6614bec78..8a75e727b 100644 --- a/app/Http/Controllers/Manage/Servers/ServerController.php +++ b/app/Http/Controllers/Manage/Servers/ServerController.php @@ -2,29 +2,31 @@ namespace App\Http\Controllers\Manage\Servers; +use App\Domains\Manage\RendersManageApp; use App\Http\Controllers\WebController; use App\Models\Server; use Illuminate\Http\RedirectResponse; use Illuminate\Http\Request; use Illuminate\Support\Facades\Gate; -use Inertia\Inertia; class ServerController extends WebController { + use RendersManageApp; + public function index(Request $request) { Gate::authorize('viewAny', Server::class); $servers = Server::orderBy('created_at', 'desc')->get(); - return Inertia::render('Servers/ServerList', compact('servers')); + return $this->inertiaRender('Servers/ServerList', compact('servers')); } public function create(Request $request) { Gate::authorize('create', Server::class); - return Inertia::render('Servers/ServerCreate'); + return $this->inertiaRender('Servers/ServerCreate'); } public function store(Request $request): RedirectResponse @@ -48,7 +50,7 @@ public function edit(Server $server) { Gate::authorize('update', $server); - return Inertia::render('Servers/ServerEdit', compact('server')); + return $this->inertiaRender('Servers/ServerEdit', compact('server')); } public function update(Request $request, Server $server) diff --git a/app/Http/Controllers/Manage/Servers/ServerTokenController.php b/app/Http/Controllers/Manage/Servers/ServerTokenController.php index bd42c6806..1a15a9430 100644 --- a/app/Http/Controllers/Manage/Servers/ServerTokenController.php +++ b/app/Http/Controllers/Manage/Servers/ServerTokenController.php @@ -2,29 +2,31 @@ namespace App\Http\Controllers\Manage\Servers; +use App\Domains\Manage\RendersManageApp; use App\Http\Controllers\WebController; use App\Models\Server; use App\Models\ServerToken; use Illuminate\Http\Request; use Illuminate\Support\Facades\Gate; -use Inertia\Inertia; class ServerTokenController extends WebController { + use RendersManageApp; + public function index(Request $request) { Gate::authorize('viewAny', ServerToken::class); $tokens = ServerToken::orderBy('created_at', 'desc')->get(); - return Inertia::render('ServerTokens/ServerTokensList', compact('tokens')); + return $this->inertiaRender('ServerTokens/ServerTokensList', compact('tokens')); } public function create(Request $request) { Gate::authorize('create', ServerToken::class); - return Inertia::render('ServerTokens/ServerTokenCreate'); + return $this->inertiaRender('ServerTokens/ServerTokenCreate'); } public function store(Request $request) @@ -50,7 +52,7 @@ public function edit(ServerToken $serverToken) { Gate::authorize('update', ServerToken::class); - return Inertia::render('ServerTokens/ServerTokenEdit', [ + return $this->inertiaRender('ServerTokens/ServerTokenEdit', [ 'token' => $serverToken, ]); } diff --git a/app/Http/Controllers/Manage/Warnings/PlayerWarningController.php b/app/Http/Controllers/Manage/Warnings/PlayerWarningController.php index 14d2d9c5f..3b7f8fc61 100644 --- a/app/Http/Controllers/Manage/Warnings/PlayerWarningController.php +++ b/app/Http/Controllers/Manage/Warnings/PlayerWarningController.php @@ -4,6 +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\WebController; use App\Models\MinecraftPlayer; use App\Models\PlayerWarning; @@ -13,6 +14,8 @@ class PlayerWarningController extends WebController { + use RendersManageApp; + public function index(Request $request) { Gate::authorize('viewAny', PlayerWarning::class); @@ -24,14 +27,14 @@ public function index(Request $request) if (request()->wantsJson()) { return $warnings; } - return Inertia::render('Warnings/WarningList', compact('warnings')); + return $this->inertiaRender('Warnings/WarningList', compact('warnings')); } public function create(Request $request) { Gate::authorize('create', PlayerWarning::class); - return Inertia::render('Warnings/WarningCreate'); + return $this->inertiaRender('Warnings/WarningCreate'); } public function store(Request $request) @@ -74,7 +77,7 @@ public function edit(PlayerWarning $warning) $warning->load('warnedPlayer', 'warnerPlayer'); - return INertia::render('Warnings/WarningEdit', compact('warning')); + return $this->inertiaRender('Warnings/WarningEdit', compact('warning')); } public function update(Request $request, PlayerWarning $warning) diff --git a/app/Http/Controllers/Review/BanAppeals/BanAppealController.php b/app/Http/Controllers/Review/BanAppeals/BanAppealController.php index 012d3a5cc..0ca3b771b 100644 --- a/app/Http/Controllers/Review/BanAppeals/BanAppealController.php +++ b/app/Http/Controllers/Review/BanAppeals/BanAppealController.php @@ -3,19 +3,23 @@ namespace App\Http\Controllers\Review\BanAppeals; use App\Core\Data\Exceptions\NotImplementedException; -use App\Domains\BanAppeals\Entities\BanAppealStatus; +use App\Domains\BanAppeals\Data\BanAppealStatus; use App\Domains\BanAppeals\Exceptions\AppealAlreadyDecidedException; +use App\Domains\BanAppeals\Exceptions\NoPlayerForActionException; use App\Domains\BanAppeals\Notifications\BanAppealUpdatedNotification; use App\Domains\BanAppeals\UseCases\UpdateBanAppeal; use App\Domains\Bans\Exceptions\NotBannedException; -use App\Domains\Manage\Exceptions\NoPlayerForActionException; +use App\Domains\Review\RendersReviewApp; use App\Http\Requests\BanAppealUpdateRequest; use App\Models\BanAppeal; use Illuminate\Support\Facades\Gate; use Illuminate\Validation\ValidationException; +use Inertia\Inertia; class BanAppealController { + use RendersReviewApp; + public function index() { Gate::authorize('viewAny', BanAppeal::class); @@ -23,21 +27,30 @@ public function index() // Get ban appeals paginated in the order: // Pending appeal (newest first), then all other appeals (newest first) $banAppeals = BanAppeal::orderByRaw('FIELD(status, '.BanAppealStatus::PENDING->value.') DESC') + ->with('gamePlayerBan.bannedPlayer') ->orderBy('created_at', 'desc') - ->paginate(50); + ->cursorPaginate(50); - return view('manage.pages.ban-appeal.index')->with([ - 'banAppeals' => $banAppeals, - ]); + return $this->inertiaRender( + 'BanAppeals/BanAppealList', + compact('banAppeals'), + ); } public function show(BanAppeal $banAppeal) { Gate::authorize('view', $banAppeal); - return view('manage.pages.ban-appeal.show')->with([ - 'banAppeal' => $banAppeal, + $banAppeal->load([ + 'gamePlayerBan.bannerPlayer', + 'gamePlayerBan.bannedPlayer', + 'deciderPlayer', ]); + + return $this->inertiaRender( + 'BanAppeals/BanAppealShow', + compact('banAppeal'), + ); } public function update( @@ -47,12 +60,14 @@ public function update( ) { Gate::authorize('update', $banAppeal); + $validated = $request->validated(); + try { $useCase->execute( banAppeal: $banAppeal, decidingAccount: $request->user(), - decisionNote: $request->get('decision_note'), - status: BanAppealStatus::from($request->get('status')) + decisionNote: $validated['decision_note'], + status: BanAppealStatus::from($validated['status']), ); } catch (NotImplementedException $e) { throw ValidationException::withMessages([ @@ -74,6 +89,7 @@ public function update( $banAppeal->notify(new BanAppealUpdatedNotification($banAppeal->showLink())); - return redirect()->route('manage.ban-appeals.show', $banAppeal); + return to_route('review.ban-appeals.show', $banAppeal) + ->with(['success' => 'Ban appeal updated and closed']); } } diff --git a/app/Http/Controllers/Review/BuilderRanks/BuilderRanksController.php b/app/Http/Controllers/Review/BuilderRanks/BuilderRanksController.php index 8e4cb22a0..ce18fb097 100644 --- a/app/Http/Controllers/Review/BuilderRanks/BuilderRanksController.php +++ b/app/Http/Controllers/Review/BuilderRanks/BuilderRanksController.php @@ -5,35 +5,48 @@ 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\WebController; use App\Models\BuilderRankApplication; use App\Models\Group; use Illuminate\Http\Request; use Illuminate\Support\Facades\Gate; use Illuminate\Validation\Rule; +use Inertia\Inertia; class BuilderRanksController extends WebController { + use RendersReviewApp; + public function index(Request $request) { Gate::authorize('viewAny', BuilderRankApplication::class); - $applications = BuilderRankApplication::orderbyRaw('FIELD(status, '.ApplicationStatus::IN_PROGRESS->value.') DESC') + $applications = BuilderRankApplication::orderbyRaw('FIELD(status, '.ApplicationStatus::PENDING->value.') DESC') + ->with('account.minecraftAccount') ->orderBy('created_at', 'desc') ->paginate(100); - return view('manage.pages.builder-rank.index') - ->with(compact('applications')); + return $this->inertiaRender('BuilderRankApplications/BuilderRankApplicationList', + compact('applications'), + ); } public function show(Request $request, BuilderRankApplication $application) { Gate::authorize('view', $application); + $application->load( + 'account.minecraftAccount', + 'account.groups', + ); + $buildGroups = Group::whereBuildType()->get(); - return view('manage.pages.builder-rank.show') - ->with(compact('application', 'buildGroups')); + return $this->inertiaRender( + 'BuilderRankApplications/BuilderRankApplicationShow', + compact('application', 'buildGroups'), + ); } public function approve( @@ -56,10 +69,8 @@ public function approve( promoteGroupId: $validated['promote_group'], ); - return redirect()->action( - action: [BuilderRanksController::class, 'show'], - parameters: $application->getKey(), - ); + return to_route('review.builder-ranks.show', $application) + ->with(['success' => 'Application approved and closed']); } public function deny( @@ -78,9 +89,7 @@ public function deny( denyReason: $validated['deny_reason'], ); - return redirect()->action( - action: [BuilderRanksController::class, 'show'], - parameters: $application->getKey(), - ); + return to_route('review.builder-ranks.show', $application) + ->with(['success' => 'Application denied and closed']); } } diff --git a/app/Http/Controllers/Review/HomeController.php b/app/Http/Controllers/Review/HomeController.php new file mode 100644 index 000000000..0341bff8f --- /dev/null +++ b/app/Http/Controllers/Review/HomeController.php @@ -0,0 +1,17 @@ +inertiaRender('Home'); + } +} diff --git a/app/Http/Middleware/HandleInertiaRequests.php b/app/Http/Middleware/HandleInertiaRequests.php index 3260463f5..c8b5fc7d3 100644 --- a/app/Http/Middleware/HandleInertiaRequests.php +++ b/app/Http/Middleware/HandleInertiaRequests.php @@ -14,7 +14,12 @@ class HandleInertiaRequests extends Middleware * * @var string */ - protected $rootView = 'manage.app'; + public function rootView(Request $request) + { + // We define this inside Controllers instead due to supporting + // multiple Inertia apps + return parent::rootView($request); + } /** * Determines the current asset version. diff --git a/app/Http/Requests/BanAppealUpdateRequest.php b/app/Http/Requests/BanAppealUpdateRequest.php index 2d1cf22dc..0beec248e 100644 --- a/app/Http/Requests/BanAppealUpdateRequest.php +++ b/app/Http/Requests/BanAppealUpdateRequest.php @@ -2,7 +2,7 @@ namespace App\Http\Requests; -use App\Domains\BanAppeals\Entities\BanAppealStatus; +use App\Domains\BanAppeals\Data\BanAppealStatus; use Illuminate\Foundation\Http\FormRequest; use Illuminate\Support\Collection; use Illuminate\Validation\Rule; @@ -35,7 +35,7 @@ public function withValidator(Validator $validator): void if (! $this->user()->minecraftAccount()->exists()) { $validator->errors()->add( 'error', - 'Can\'t perform ban actions with no minecraft accounts linked.' + 'You must have a linked Minecraft account.' ); } }); diff --git a/app/Http/Requests/BuilderRankApplicationRequest.php b/app/Http/Requests/BuilderRankApplicationRequest.php index 2405facce..7460172b8 100644 --- a/app/Http/Requests/BuilderRankApplicationRequest.php +++ b/app/Http/Requests/BuilderRankApplicationRequest.php @@ -22,6 +22,7 @@ public function rules(): array 'current_builder_rank' => ['required', Rule::in($ranks)], 'build_location' => 'required', 'build_description' => 'required', + 'additional_notes' => 'nullable', ]; } diff --git a/app/Models/BanAppeal.php b/app/Models/BanAppeal.php index ce613116c..ca44b00cc 100644 --- a/app/Models/BanAppeal.php +++ b/app/Models/BanAppeal.php @@ -4,7 +4,7 @@ use App\Core\Domains\Auditing\Contracts\LinkableAuditModel; use App\Core\Utilities\Traits\HasStaticTable; -use App\Domains\BanAppeals\Entities\BanAppealStatus; +use App\Domains\BanAppeals\Data\BanAppealStatus; use Carbon\CarbonInterface; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Builder; @@ -60,11 +60,6 @@ public function scopeResolved(Builder $query): Builder return $query->whereNot('status', BanAppealStatus::PENDING); } - public function isPending() - { - return $this->status == BanAppealStatus::PENDING; - } - public function routeNotificationForMail($notification) { return $this->gamePlayerBan->bannedPlayer->account?->email ?? $this->email; @@ -75,12 +70,6 @@ public function routeNotificationForDiscord(): string return config('discord.webhook_ban_appeal_channel'); } - public function getBannedPlayerName() - { - return $this->gamePlayerBan->bannedPlayer->alias ?? - $this->gamePlayerBan->banned_alias_at_time; - } - public function showLink(): string { return $this->is_account_verified ? diff --git a/app/Models/MinecraftPlayer.php b/app/Models/MinecraftPlayer.php index 716b42116..e8233c9f2 100644 --- a/app/Models/MinecraftPlayer.php +++ b/app/Models/MinecraftPlayer.php @@ -102,17 +102,6 @@ public function scopeWhereUuid(Builder $query, MinecraftUUID $uuid) $query->where('uuid', $uuid->trimmed()); } - /** ************************************************ - * - * GamePlayable - * - ***************************************************/ - /** @deprecated */ - public function getRawModel(): static - { - return $this; - } - public function auditAttributeConfig(): AuditAttributes { return AuditAttributes::build() diff --git a/bootstrap/providers.php b/bootstrap/providers.php index 26c23eab7..06be165db 100644 --- a/bootstrap/providers.php +++ b/bootstrap/providers.php @@ -14,7 +14,6 @@ \App\Domains\Activation\ActivationServiceProvider::class, \App\Domains\Captcha\CaptchaServiceProvider::class, \App\Domains\Donations\DonationServiceProvider::class, - \App\Domains\Manage\ManageServiceProvider::class, \App\Domains\Mfa\MfaServiceProvider::class, \App\Domains\MinecraftEventBus\MinecraftEventBusServiceProvider::class, ]; diff --git a/database/factories/BanAppealFactory.php b/database/factories/BanAppealFactory.php index 32b06a199..1b3a43e4d 100644 --- a/database/factories/BanAppealFactory.php +++ b/database/factories/BanAppealFactory.php @@ -2,7 +2,7 @@ namespace Database\Factories; -use App\Domains\BanAppeals\Entities\BanAppealStatus; +use App\Domains\BanAppeals\Data\BanAppealStatus; use App\Models\BanAppeal; use App\Models\MinecraftPlayer; @@ -38,7 +38,7 @@ public function withResponse(): Factory return $this->state(function (array $attributes) { return [ 'decision_note' => $this->faker->paragraph, - 'decided_at' => now(), + 'decided_at' => now()->addDays(rand(0, 30)), 'decider_player_minecraft_id' => MinecraftPlayer::factory(), ]; }); diff --git a/database/factories/BuilderRankApplicationFactory.php b/database/factories/BuilderRankApplicationFactory.php index bc856f075..1bb8eb1e3 100644 --- a/database/factories/BuilderRankApplicationFactory.php +++ b/database/factories/BuilderRankApplicationFactory.php @@ -39,4 +39,25 @@ public function status(ApplicationStatus $status) ]; }); } + + public function approved() + { + return $this->state(function (array $attributes) { + return [ + 'status' => ApplicationStatus::APPROVED, + 'closed_at' => now()->addDays(rand(0, 30)), + ]; + }); + } + + public function denied() + { + return $this->state(function (array $attributes) { + return [ + 'status' => ApplicationStatus::DENIED, + 'denied_reason' => $this->faker->paragraph, + 'closed_at' => now()->addDays(rand(0, 30)), + ]; + }); + } } diff --git a/database/seeders/AccountSeeder.php b/database/seeders/AccountSeeder.php index ab7ec2eaf..8d6827b0a 100644 --- a/database/seeders/AccountSeeder.php +++ b/database/seeders/AccountSeeder.php @@ -83,7 +83,6 @@ private function createUnactivatedAccount() AccountActivation::factory()->create([ 'account_id' => $account->getKey(), - 'activated' => false, 'token' => $this->tokenGenerator->make(), 'expires_at' => now()->addYear(), ]); diff --git a/database/seeders/BanAppealSeeder.php b/database/seeders/BanAppealSeeder.php new file mode 100644 index 000000000..7e320e86a --- /dev/null +++ b/database/seeders/BanAppealSeeder.php @@ -0,0 +1,46 @@ +createPending(15); + $this->createUnbanned(20); + $this->createDenied(20); + } + + private function createPending(int $count) + { + for ($i = 0; $i < $count; $i++) { + BanAppeal::factory() + ->for(GamePlayerBan::inRandomOrder()->first()) + ->create(); + } + } + + private function createUnbanned(int $count) + { + for ($i = 0; $i < $count; $i++) { + BanAppeal::factory() + ->for(GamePlayerBan::inRandomOrder()->first()) + ->unbanned() + ->create(); + } + } + + private function createDenied(int $count) + { + for ($i = 0; $i < $count; $i++) { + BanAppeal::factory() + ->for(GamePlayerBan::inRandomOrder()->first()) + ->denied() + ->create(); + } + } +} diff --git a/database/seeders/BuilderRankApplicationSeeder.php b/database/seeders/BuilderRankApplicationSeeder.php new file mode 100644 index 000000000..a8a81f72e --- /dev/null +++ b/database/seeders/BuilderRankApplicationSeeder.php @@ -0,0 +1,46 @@ +createPending(15); + $this->createApproved(5); + $this->createDenied(20); + } + + private function createPending(int $count) + { + for ($i = 0; $i < $count; $i++) { + BuilderRankApplication::factory() + ->for(Account::inRandomOrder()->first()) + ->create(); + } + } + + private function createApproved(int $count) + { + for ($i = 0; $i < $count; $i++) { + BuilderRankApplication::factory() + ->for(Account::inRandomOrder()->first()) + ->approved() + ->create(); + } + } + + private function createDenied(int $count) + { + for ($i = 0; $i < $count; $i++) { + BuilderRankApplication::factory() + ->for(Account::inRandomOrder()->first()) + ->denied() + ->create(); + } + } +} diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index 4f5e6d689..82e145602 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -2,9 +2,6 @@ namespace Database\Seeders; -use App\Domains\BuilderRankApplications\Data\ApplicationStatus; -use App\Models\Account; -use App\Models\BuilderRankApplication; use App\Models\MinecraftBuild; use App\Models\MinecraftConfig; use App\Models\MinecraftPlayer; @@ -25,6 +22,12 @@ public function run() 'web_port' => '8080', ]); + ServerToken::create([ + 'token' => 'pcbridge_local', + 'server_id' => Server::first()->getKey(), + 'description' => 'For test use', + ]); + $this->call(GroupSeeder::class); $this->call(AccountSeeder::class); $this->call(MinecraftPlayerSeeder::class); @@ -32,12 +35,8 @@ public function run() $this->call(PlayerWarningSeeder::class); $this->call(DonationSeeder::class); $this->call(BadgeSeeder::class); - - ServerToken::create([ - 'token' => 'pcbridge_local', - 'server_id' => Server::first()->getKey(), - 'description' => 'For test use', - ]); + $this->call(BanAppealSeeder::class); + $this->call(BuilderRankApplicationSeeder::class); MinecraftConfig::factory() ->create(); @@ -51,21 +50,5 @@ public function run() MinecraftBuild::factory() ->create(['player_id' => $players->random()]); } - - for ($i = 0; $i < 5; $i++) { - BuilderRankApplication::factory() - ->for(Account::inRandomOrder()->first()) - ->create(); - } - - BuilderRankApplication::factory() - ->for(Account::inRandomOrder()->first()) - ->status(ApplicationStatus::APPROVED) - ->create(); - - BuilderRankApplication::factory() - ->for(Account::inRandomOrder()->first()) - ->status(ApplicationStatus::DENIED) - ->create(); } } diff --git a/resources/js/manage/Components/Dialog.vue b/resources/js/manage/Components/Dialog.vue new file mode 100644 index 000000000..172c87e86 --- /dev/null +++ b/resources/js/manage/Components/Dialog.vue @@ -0,0 +1,43 @@ + + + diff --git a/resources/js/manage/Components/InfinitePagination.vue b/resources/js/manage/Components/InfinitePagination.vue index d8e8b60d0..f0efc8ea8 100644 --- a/resources/js/manage/Components/InfinitePagination.vue +++ b/resources/js/manage/Components/InfinitePagination.vue @@ -62,7 +62,7 @@ const load = async () => { if (cursor == null) { stop() } - return response.data.data + return response.data?.data ?? [] } finally { loading.value = false } diff --git a/resources/js/manage/Components/Pill.vue b/resources/js/manage/Components/Pill.vue index 3688c1135..6c7e17b40 100644 --- a/resources/js/manage/Components/Pill.vue +++ b/resources/js/manage/Components/Pill.vue @@ -25,7 +25,7 @@ const style = computed(() => { diff --git a/resources/js/manage/Components/SvgIcon.vue b/resources/js/manage/Components/SvgIcon.vue index 56e3e57f0..e43f3733a 100644 --- a/resources/js/manage/Components/SvgIcon.vue +++ b/resources/js/manage/Components/SvgIcon.vue @@ -16,6 +16,9 @@ type Icon = 'plus' | 'check-shield' | 'check' | 'arrow-left' + | 'alert' + | 'clock' + | 'eye' interface Props { @@ -56,6 +59,12 @@ const path = computed(() => { return 'm4.5 12.75 6 6 9-13.5' case 'arrow-left': return 'M6.75 15.75 3 12m0 0 3.75-3.75M3 12h18' + case 'alert': + return 'M12 9v3.75m9-.75a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9 3.75h.008v.008H12v-.008Z' + case 'clock': + return 'M12 6v6h4.5m4.5 0a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z' + case 'eye': + return 'M1.323 11.447C2.811 6.976 7.028 3.75 12.001 3.75c4.97 0 9.185 3.223 10.675 7.69.12.362.12.752 0 1.113-1.487 4.471-5.705 7.697-10.677 7.697-4.97 0-9.186-3.223-10.675-7.69a1.762 1.762 0 0 1 0-1.113ZM17.25 12a5.25 5.25 0 1 1-10.5 0 5.25 5.25 0 0 1 10.5 0Z' } }) diff --git a/resources/js/manage/Data/BanAppeal.ts b/resources/js/manage/Data/BanAppeal.ts new file mode 100644 index 000000000..ea18075d6 --- /dev/null +++ b/resources/js/manage/Data/BanAppeal.ts @@ -0,0 +1,17 @@ +import { BanAppealStatus } from './BanAppealStatus' +import { Player } from './Player' +import { PlayerBan } from './PlayerBan' + +export interface BanAppeal { + id: number, + explanation: string, + email: string, + status: BanAppealStatus, + is_account_verified: boolean, + game_player_ban: PlayerBan, + created_at: string, + updated_at: string, + decided_at?: string, + decider_player?: Player, + decision_note?: string, +} diff --git a/resources/js/manage/Data/BanAppealStatus.ts b/resources/js/manage/Data/BanAppealStatus.ts new file mode 100644 index 000000000..b64ea74d1 --- /dev/null +++ b/resources/js/manage/Data/BanAppealStatus.ts @@ -0,0 +1,6 @@ +export enum BanAppealStatus { + pending = 0, + unbanned, + tempBanned, + denied, +} diff --git a/resources/js/manage/Data/BuilderRankApplication.ts b/resources/js/manage/Data/BuilderRankApplication.ts new file mode 100644 index 000000000..dcca18bcc --- /dev/null +++ b/resources/js/manage/Data/BuilderRankApplication.ts @@ -0,0 +1,23 @@ +import { Account } from './Account' + +export interface BuilderRankApplication { + id: number, + account_id: number, + account?: Account, + minecraft_alias: string, + current_builder_rank: string, + build_location: string, + build_description: string, + additional_notes?: string, + status: BuilderRankApplicationStatus, + denied_reason?: string, + closed_at?: string, + created_at: string, + updated_at: string, +} + +export enum BuilderRankApplicationStatus { + pending = 1, + approved, + denied, +} diff --git a/resources/js/manage/Layouts/Root/ManageLayout.vue b/resources/js/manage/Layouts/Root/ManageLayout.vue new file mode 100644 index 000000000..0e3349bb7 --- /dev/null +++ b/resources/js/manage/Layouts/Root/ManageLayout.vue @@ -0,0 +1,16 @@ + + + diff --git a/resources/js/manage/Layouts/Root/Partials/NavBar.vue b/resources/js/manage/Layouts/Root/Partials/NavBar.vue index 2f725f462..7f8c49601 100644 --- a/resources/js/manage/Layouts/Root/Partials/NavBar.vue +++ b/resources/js/manage/Layouts/Root/Partials/NavBar.vue @@ -1,7 +1,26 @@