From 35b5f39843d1f89eee5e11de410f0ecfd6bd55ba Mon Sep 17 00:00:00 2001 From: Dolo Date: Mon, 13 Apr 2026 14:01:19 +0200 Subject: [PATCH] Neuaufbau des Repositories --- app/Http/Controllers/Admin/UserController.php | 80 ++++++++++++ app/Providers/AppServiceProvider.php | 6 + database/seeders/AdminUserSeeder.php | 33 +++++ database/seeders/DatabaseSeeder.php | 4 + make_admin.php | 14 ++ resources/js/components/AppHeader.vue | 5 +- resources/js/components/AppSidebar.vue | 5 +- .../js/components/TwoFactorRecoveryCodes.vue | 3 +- resources/js/layouts/AdminLayout.vue | 7 +- resources/js/pages/Admin/Users/Create.vue | 116 +++++++++++++++++ resources/js/pages/Admin/Users/Edit.vue | 123 ++++++++++++++++++ resources/js/pages/Admin/Users/Index.vue | 103 +++++++++++++++ resources/js/pages/settings/Appearance.vue | 3 +- routes/web.php | 5 + 14 files changed, 494 insertions(+), 13 deletions(-) create mode 100644 app/Http/Controllers/Admin/UserController.php create mode 100644 database/seeders/AdminUserSeeder.php create mode 100644 make_admin.php create mode 100644 resources/js/pages/Admin/Users/Create.vue create mode 100644 resources/js/pages/Admin/Users/Edit.vue create mode 100644 resources/js/pages/Admin/Users/Index.vue diff --git a/app/Http/Controllers/Admin/UserController.php b/app/Http/Controllers/Admin/UserController.php new file mode 100644 index 0000000..783ab68 --- /dev/null +++ b/app/Http/Controllers/Admin/UserController.php @@ -0,0 +1,80 @@ + User::all(), + ]); + } + + public function create() + { + return Inertia::render('Admin/Users/Create'); + } + + public function store(Request $request) + { + $request->validate([ + 'name' => 'required|string|max:255', + 'email' => 'required|string|email|max:255|unique:users', + 'password' => 'required|string|min:8|confirmed', + 'role' => ['required', Rule::in(['user', 'mod', 'admin'])], + ]); + + User::create([ + 'name' => $request->name, + 'email' => $request->email, + 'password' => Hash::make($request->password), + 'role' => $request->role, + ]); + + return redirect('/admin/users'); + } + + public function edit(User $user) + { + return Inertia::render('Admin/Users/Edit', [ + 'user' => $user, + ]); + } + + public function update(Request $request, User $user) + { + $request->validate([ + 'name' => 'required|string|max:255', + 'email' => ['required', 'string', 'email', 'max:255', Rule::unique('users')->ignore($user->id)], + 'password' => 'nullable|string|min:8|confirmed', + 'role' => ['required', Rule::in(['user', 'mod', 'admin'])], + ]); + + $user->name = $request->name; + $user->email = $request->email; + $user->role = $request->role; + + if ($request->filled('password')) { + $user->password = Hash::make($request->password); + } + + $user->save(); + + return redirect('/admin/users'); + } + + public function destroy(User $user) + { + $user->delete(); + + return redirect('/admin/users'); + } +} diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 4f74b10..4ef0f26 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -32,6 +32,12 @@ class AppServiceProvider extends ServiceProvider // You should restrict this later! return true; }); + + Gate::define('manage-users', function (User $user) { + // Temporarily allowing all authenticated users while testing. + // You should restrict this later by returning $user->isAdmin(); + return true; + }); } /** diff --git a/database/seeders/AdminUserSeeder.php b/database/seeders/AdminUserSeeder.php new file mode 100644 index 0000000..e6bb82f --- /dev/null +++ b/database/seeders/AdminUserSeeder.php @@ -0,0 +1,33 @@ + 'admin@bratanbonus.test'], + [ + 'name' => 'Admin Bratan', + 'password' => Hash::make('password'), + 'role' => 'admin', + ] + ); + + $this->command->info('Admin User created successfully!'); + $this->command->info('--------------------------------'); + $this->command->info('Email: ' . $user->email); + $this->command->info('Password: password'); + $this->command->info('Role: ' . $user->role); + $this->command->info('--------------------------------'); + } +} diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index d01a0ef..18297de 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -19,5 +19,9 @@ class DatabaseSeeder extends Seeder 'name' => 'Test User', 'email' => 'test@example.com', ]); + + $this->call([ + AdminUserSeeder::class, + ]); } } diff --git a/make_admin.php b/make_admin.php new file mode 100644 index 0000000..3a27f6c --- /dev/null +++ b/make_admin.php @@ -0,0 +1,14 @@ +make(Illuminate\Contracts\Console\Kernel::class); +$kernel->bootstrap(); + +$user = \App\Models\User::first(); +if ($user) { + $user->role = 'admin'; + $user->save(); + echo "User {$user->email} is now an admin!\n"; +} else { + echo "No user found.\n"; +} diff --git a/resources/js/components/AppHeader.vue b/resources/js/components/AppHeader.vue index f1bb49e..ab6597a 100644 --- a/resources/js/components/AppHeader.vue +++ b/resources/js/components/AppHeader.vue @@ -35,7 +35,6 @@ import UserMenuContent from '@/components/UserMenuContent.vue'; import { useCurrentUrl } from '@/composables/useCurrentUrl'; import { getInitials } from '@/composables/useInitials'; import { toUrl } from '@/lib/utils'; -import { dashboard } from '@/routes'; import type { BreadcrumbItem, NavItem } from '@/types'; type Props = { @@ -56,7 +55,7 @@ const activeItemStyles = const mainNavItems: NavItem[] = [ { title: 'Dashboard', - href: dashboard(), + href: '/dashboard', icon: LayoutGrid, }, ]; @@ -146,7 +145,7 @@ const rightNavItems: NavItem[] = [ - + diff --git a/resources/js/components/AppSidebar.vue b/resources/js/components/AppSidebar.vue index 06fbed7..e6589b1 100644 --- a/resources/js/components/AppSidebar.vue +++ b/resources/js/components/AppSidebar.vue @@ -15,7 +15,6 @@ import { SidebarMenuButton, SidebarMenuItem, } from '@/components/ui/sidebar'; -import { dashboard } from '@/routes'; import type { NavItem } from '@/types'; const page = usePage(); @@ -36,7 +35,7 @@ const mainNavItems = computed(() => { const items: NavItem[] = [ { title: 'Dashboard', - href: dashboard(), + href: '/dashboard', icon: LayoutGrid, } ]; @@ -82,7 +81,7 @@ const footerNavItems = computed(() => { - + diff --git a/resources/js/components/TwoFactorRecoveryCodes.vue b/resources/js/components/TwoFactorRecoveryCodes.vue index d3069bf..b2afc4a 100644 --- a/resources/js/components/TwoFactorRecoveryCodes.vue +++ b/resources/js/components/TwoFactorRecoveryCodes.vue @@ -12,7 +12,6 @@ import { CardTitle, } from '@/components/ui/card'; import { useTwoFactorAuth } from '@/composables/useTwoFactorAuth'; -import { regenerateRecoveryCodes } from '@/routes/two-factor'; const { recoveryCodesList, fetchRecoveryCodes, errors } = useTwoFactorAuth(); const isRecoveryCodesVisible = ref(false); @@ -64,7 +63,7 @@ onMounted(async () => {
import { Link, usePage } from '@inertiajs/vue3'; -import { LayoutGrid, Gift, Settings, LogOut, Menu, X, Bell, CheckCircle, AlertCircle, Info, Trophy } from 'lucide-vue-next'; +import { LayoutGrid, Gift, Settings, LogOut, Menu, X, Bell, CheckCircle, AlertCircle, Info, Trophy, Users } from 'lucide-vue-next'; import { ref, watch, onMounted } from 'vue'; const isSidebarOpen = ref(false); // Default to closed on mobile @@ -12,6 +12,7 @@ const navItems = [ { title: 'Leaderboard', href: '/leaderboard', icon: Trophy, isExternal: true }, { title: 'Dashboard', href: '/dashboard', icon: LayoutGrid }, { title: 'Bonuses', href: '/admin/bonuses', icon: Gift }, + { title: 'Users', href: '/admin/users', icon: Users }, ]; const notification = ref<{ message: string; type: 'success' | 'error' | 'info' } | null>(null); @@ -190,10 +191,10 @@ onMounted(() => {
-
+
{{ ($page.props.auth?.user?.name || 'A').charAt(0) }}
diff --git a/resources/js/pages/Admin/Users/Create.vue b/resources/js/pages/Admin/Users/Create.vue new file mode 100644 index 0000000..40ce98d --- /dev/null +++ b/resources/js/pages/Admin/Users/Create.vue @@ -0,0 +1,116 @@ + + + diff --git a/resources/js/pages/Admin/Users/Edit.vue b/resources/js/pages/Admin/Users/Edit.vue new file mode 100644 index 0000000..632c6e5 --- /dev/null +++ b/resources/js/pages/Admin/Users/Edit.vue @@ -0,0 +1,123 @@ + + + diff --git a/resources/js/pages/Admin/Users/Index.vue b/resources/js/pages/Admin/Users/Index.vue new file mode 100644 index 0000000..8500f3d --- /dev/null +++ b/resources/js/pages/Admin/Users/Index.vue @@ -0,0 +1,103 @@ + + + diff --git a/resources/js/pages/settings/Appearance.vue b/resources/js/pages/settings/Appearance.vue index 2981f7c..520c3b3 100644 --- a/resources/js/pages/settings/Appearance.vue +++ b/resources/js/pages/settings/Appearance.vue @@ -2,14 +2,13 @@ import { Head } from '@inertiajs/vue3'; import AppearanceTabs from '@/components/AppearanceTabs.vue'; import Heading from '@/components/Heading.vue'; -import { edit } from '@/routes/appearance'; defineOptions({ layout: { breadcrumbs: [ { title: 'Appearance settings', - href: edit(), + href: '/settings/appearance', }, ], }, diff --git a/routes/web.php b/routes/web.php index e9be1d5..57923c9 100644 --- a/routes/web.php +++ b/routes/web.php @@ -3,6 +3,7 @@ use App\Http\Controllers\BonusController; use App\Http\Controllers\LiveStatusController; use App\Http\Controllers\TrackingController; +use App\Http\Controllers\Admin\UserController; use App\Models\Bonus; use App\Models\BonusStat; use Carbon\Carbon; @@ -146,6 +147,10 @@ Route::middleware(['auth', 'verified'])->group(function () { Route::middleware(['can:manage-bonuses'])->prefix('admin')->name('admin.')->group(function () { Route::resource('bonuses', BonusController::class); }); + + Route::middleware(['can:manage-users'])->prefix('admin')->name('admin.')->group(function () { + Route::resource('users', UserController::class); + }); }); Route::get('/api/live-status', [LiveStatusController::class, '__invoke']);