diff --git a/app/Http/Controllers/Admin/UserController.php b/app/Http/Controllers/Admin/UserController.php new file mode 100644 index 0000000..22f58a4 --- /dev/null +++ b/app/Http/Controllers/Admin/UserController.php @@ -0,0 +1,103 @@ +when($request->filled('search'), function (Builder $query) use ($request) { + $search = $request->input('search'); + + $query->whereAny([ + 'first_name', + 'last_name', + 'email', + 'mobile', + 'id', + ], 'LIKE', "%{$search}%"); + }) + ->when($request->filled('mobile'), function (Builder $query) use ($request) { + $query->where('mobile', 'LIKE', '%' . $request->mobile . '%'); + }) + ->when($request->filled('email'), function (Builder $query) use ($request) { + $query->where('email', 'LIKE', '%' . $request->email . '%'); + }) + ->when($request->filled('from_date'), function (Builder $query) use ($request) { + $gregorianFrom = Verta::parse($request->from_date)->formatGregorian('Y-m-d'); + $query->whereDate('created_at', '>=', $gregorianFrom); + }) + ->when($request->filled('to_date'), function (Builder $query) use ($request) { + $gregorianTo = Verta::parse($request->to_date)->formatGregorian('Y-m-d'); + $query->whereDate('created_at', '<=', $gregorianTo); + }) + ->when($request->filled('sort'), function (Builder $query) use ($request) { + switch ($request->input('sort')) { + case 'oldest': + $query->orderBy('created_at'); + break; + + case 'name_asc': + $query->orderBy('first_name')->orderBy('last_name'); + break; + + case 'name_desc': + $query->orderByDesc('first_name')->orderByDesc('last_name'); + break; + + case 'newest': + default: + $query->orderByDesc('created_at'); + break; + } + }, function (Builder $query) { + $query->orderByDesc('created_at'); + }) + ->paginate(15) + ->withQueryString(); + + return view('admin.users.index', compact('users')); + } + + public function edit(User $user) + { + return view('admin.users.edit', compact('user')); + } + + public function update(UserUpdateRequest $request, User $user) + { + $inputs = $request->only([ + 'first_name', + 'last_name', + 'mobile', + 'email', + ]); + + if ($request->filled('password')) { + $inputs['password'] = Hash::make($request->password); + } + + $user->update($inputs); + + return redirect() + ->route('admin.users.index') + ->with('success', 'اطلاعات کاربر با موفقیت ویرایش شد.'); + } + + public function destroy(User $user) + { + $user->delete(); + + return redirect() + ->route('admin.users.index') + ->with('success', 'کاربر با موفقیت حذف شد.'); + } +} diff --git a/app/Http/Controllers/Auth/RegisterController.php b/app/Http/Controllers/Auth/RegisterController.php index d93ea55..46e1b9a 100644 --- a/app/Http/Controllers/Auth/RegisterController.php +++ b/app/Http/Controllers/Auth/RegisterController.php @@ -11,6 +11,7 @@ use App\Models\User; use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Hash; +use Illuminate\Auth\Events\Registered; class RegisterController extends Controller { @@ -33,7 +34,10 @@ class RegisterController extends Controller $imageName = time() . rand(11111, 99999) . '.' . $image->extension(); - $path = $image->storeAs('user_images', $imageName); + $path = $image->storeAs( + 'user_images', + $imageName, + 'public'); $file = File::create([ 'name' => $imageName, @@ -54,9 +58,11 @@ class RegisterController extends Controller $user = User::create($inputs); + event(new Registered($user)); + Auth::login($user); - return redirect()->route('index'); + return redirect()->route('verification.notice'); } public function cities(Province $province): JsonResponse diff --git a/app/Http/Requests/Admin/UserUpdateRequest.php b/app/Http/Requests/Admin/UserUpdateRequest.php new file mode 100644 index 0000000..da97b73 --- /dev/null +++ b/app/Http/Requests/Admin/UserUpdateRequest.php @@ -0,0 +1,62 @@ +|string> + */ + public function rules(): array + { + return [ + 'first_name' => [ + 'required', + 'persian_alpha', + 'min:2', + 'max:100', + ], + 'last_name' => [ + 'required', + 'persian_alpha', + 'min:3', + 'max:100', + + ], + 'mobile' => [ + 'required', + 'string', + 'ir_mobile:zero', + 'unique:users,mobile,' . $this->route('user')->id ], + + 'password' => [ + 'nullable', + 'string', + 'min:6', + 'max:255', + + ], + 'email' => [ + 'required', + 'max:150', + 'email', + 'unique:users,email,' . $this->route('user')->id + ] + ]; + } +} diff --git a/app/Models/User.php b/app/Models/User.php index e895339..9249162 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -8,9 +8,10 @@ namespace App\Models; use Carbon\Carbon; use Illuminate\Database\Eloquent\Collection; -use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Foundation\Auth\User as Authenticated; +use Illuminate\Contracts\Auth\MustVerifyEmail; +use Illuminate\Notifications\Notifiable; /** * Class User @@ -43,9 +44,9 @@ use Illuminate\Foundation\Auth\User as Authenticated; * * @package App\Models */ -class User extends Authenticated -{ - use SoftDeletes; +class User extends Authenticated implements MustVerifyEmail{ + + use SoftDeletes, Notifiable; protected $table = 'users'; public static $snakeAttributes = false; diff --git a/resources/views/auth/register.blade.php b/resources/views/auth/register.blade.php index 29dd6c3..3f7225b 100644 --- a/resources/views/auth/register.blade.php +++ b/resources/views/auth/register.blade.php @@ -361,7 +361,6 @@ }); - provinceSelect.addEventListener('change', function () { citySelect.innerHTML = ` diff --git a/routes/web.php b/routes/web.php index 5b6a15d..b0eb2b2 100644 --- a/routes/web.php +++ b/routes/web.php @@ -11,6 +11,8 @@ use App\Http\Controllers\FlightController; use App\Http\Controllers\IndexController; use App\Http\Controllers\TourController; use Illuminate\Support\Facades\Route; +use Illuminate\Http\Request; +use Illuminate\Foundation\Auth\EmailVerificationRequest; Route::get('/', [IndexController::class, 'index'])->name('index'); @@ -38,13 +40,35 @@ Route::controller(CommentController::class) Route::post('/tours/{tour}/comments', 'tourStore')->name('tours.comments.store'); }); +Route::get('/email/verify', function () { + return view('auth.verify-email'); +})->middleware('auth')->name('verification.notice'); + + +Route::get('/email/verify/{id}/{hash}', function (EmailVerificationRequest $request) { + + $request->fulfill(); + + return redirect()->route('account.profile'); + +})->middleware(['auth', 'signed'])->name('verification.verify'); + + +Route::post('/email/verification-notification', function (Request $request) { + + $request->user()->sendEmailVerificationNotification(); + + return back()->with('message', 'لینک فعال سازی مجدداً ارسال شد.'); + +})->middleware(['auth', 'throttle:6,1'])->name('verification.send'); + + Route::prefix('account')->name('account.')->middleware('auth')->group(function () { Route::get('profile', [ProfileController::class, 'index'])->name('profile'); - Route::get('wishlist', [WishlistController::class, 'index']) - ->name('wishlist'); + Route::get('wishlist', [WishlistController::class, 'index'])->name('wishlist'); Route::prefix('edit-profile')->name('edit-profile.')->controller(EditProfileController::class)->group(function () { @@ -52,10 +76,7 @@ Route::prefix('account')->name('account.')->middleware('auth')->group(function ( Route::put('/', 'post')->name('post'); }); - Route::post( - 'favorites/{type}/{id}/toggle', - [FavoriteController::class, 'toggle'] - )->name('favorites.toggle'); + Route::post('favorites/{type}/{id}/toggle', [FavoriteController::class, 'toggle'])->name('favorites.toggle'); Route::get('comments', [CommentStatusController::class, 'index']) ->name('comments');