mirror of https://github.com/kcal-app/kcal.git
Create "profile" controller and routes (WIP)
Views are incomplete and components need to be broken out from user edit.
This commit is contained in:
parent
104bbcd614
commit
a378936b72
|
|
@ -0,0 +1,42 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Traits\UpdatesUser;
|
||||||
|
use App\Http\Requests\UpdateUserRequest;
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Contracts\View\View;
|
||||||
|
use Illuminate\Http\RedirectResponse;
|
||||||
|
|
||||||
|
class ProfileController extends Controller
|
||||||
|
{
|
||||||
|
use UpdatesUser;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display a user profile page.
|
||||||
|
*/
|
||||||
|
public function show(User $user): View
|
||||||
|
{
|
||||||
|
return view('profiles.show')->with('user', $user);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the form for editing a user's profile data.
|
||||||
|
*/
|
||||||
|
public function edit(User $user): View
|
||||||
|
{
|
||||||
|
return view('profiles.edit')->with('user', $user);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the user profile data.
|
||||||
|
*/
|
||||||
|
public function update(UpdateUserRequest $request, User $user): RedirectResponse
|
||||||
|
{
|
||||||
|
$this->updateUser($request, $user);
|
||||||
|
$user->refresh();
|
||||||
|
session()->flash('message', "Profile updated!");
|
||||||
|
return redirect()->route('profiles.show', $user);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Traits;
|
||||||
|
|
||||||
|
use App\Http\Requests\UpdateUserRequest;
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Support\Facades\Hash;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
|
trait UpdatesUser
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates a user from a user update request.
|
||||||
|
*/
|
||||||
|
public function updateUser(UpdateUserRequest $request, User $user): void {
|
||||||
|
$input = $request->validated();
|
||||||
|
$input['remember_token'] = Str::random(10);
|
||||||
|
if (!empty($input['password'])) {
|
||||||
|
$input['password'] = Hash::make($input['password']);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
unset($input['password']);
|
||||||
|
}
|
||||||
|
$input['admin'] = $input['admin'] ?? false;
|
||||||
|
|
||||||
|
$user->fill($input)->save();
|
||||||
|
|
||||||
|
// Handle image.
|
||||||
|
if (!empty($input['image'])) {
|
||||||
|
/** @var \Illuminate\Http\UploadedFile $file */
|
||||||
|
$file = $input['image'];
|
||||||
|
$user->clearMediaCollection();
|
||||||
|
$user
|
||||||
|
->addMediaFromRequest('image')
|
||||||
|
->usingName($user->username)
|
||||||
|
->usingFileName("{$user->slug}.{$file->extension()}")
|
||||||
|
->toMediaCollection();
|
||||||
|
}
|
||||||
|
elseif (isset($input['remove_image']) && $input['remove_image']) {
|
||||||
|
$user->clearMediaCollection();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -2,15 +2,16 @@
|
||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Traits\UpdatesUser;
|
||||||
use App\Http\Requests\UpdateUserRequest;
|
use App\Http\Requests\UpdateUserRequest;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use Illuminate\Contracts\View\View;
|
use Illuminate\Contracts\View\View;
|
||||||
use Illuminate\Http\RedirectResponse;
|
use Illuminate\Http\RedirectResponse;
|
||||||
use Illuminate\Support\Facades\Hash;
|
|
||||||
use Illuminate\Support\Str;
|
|
||||||
|
|
||||||
class UserController extends Controller
|
class UserController extends Controller
|
||||||
{
|
{
|
||||||
|
use UpdatesUser;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Display a listing of the resource.
|
* Display a listing of the resource.
|
||||||
*/
|
*/
|
||||||
|
|
@ -50,33 +51,7 @@ class UserController extends Controller
|
||||||
*/
|
*/
|
||||||
public function update(UpdateUserRequest $request, User $user): RedirectResponse
|
public function update(UpdateUserRequest $request, User $user): RedirectResponse
|
||||||
{
|
{
|
||||||
$input = $request->validated();
|
$this->updateUser($request, $user);
|
||||||
$input['remember_token'] = Str::random(10);
|
|
||||||
if (!empty($input['password'])) {
|
|
||||||
$input['password'] = Hash::make($input['password']);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
unset($input['password']);
|
|
||||||
}
|
|
||||||
$input['admin'] = $input['admin'] ?? false;
|
|
||||||
|
|
||||||
$user->fill($input)->save();
|
|
||||||
|
|
||||||
// Handle image.
|
|
||||||
if (!empty($input['image'])) {
|
|
||||||
/** @var \Illuminate\Http\UploadedFile $file */
|
|
||||||
$file = $input['image'];
|
|
||||||
$user->clearMediaCollection();
|
|
||||||
$user
|
|
||||||
->addMediaFromRequest('image')
|
|
||||||
->usingName($user->username)
|
|
||||||
->usingFileName("{$user->slug}.{$file->extension()}")
|
|
||||||
->toMediaCollection();
|
|
||||||
}
|
|
||||||
elseif (isset($input['remove_image']) && $input['remove_image']) {
|
|
||||||
$user->clearMediaCollection();
|
|
||||||
}
|
|
||||||
|
|
||||||
session()->flash('message', "User {$user->name} updated!");
|
session()->flash('message', "User {$user->name} updated!");
|
||||||
return redirect()->route('users.index');
|
return redirect()->route('users.index');
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -83,6 +83,14 @@ final class User extends Authenticatable implements HasMedia
|
||||||
'admin' => 'bool',
|
'admin' => 'bool',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public function sluggable(): array
|
||||||
|
{
|
||||||
|
return ['slug' => ['source' => 'username']];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the User's goals.
|
* Get the User's goals.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,13 @@ class UserPolicy
|
||||||
return $user->admin;
|
return $user->admin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the user can edit a user via the "profile".
|
||||||
|
*/
|
||||||
|
public function editProfile(User $user, User $model): bool {
|
||||||
|
return $user->id === $model->id;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine whether the user can delete the model.
|
* Determine whether the user can delete the model.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -8,10 +8,9 @@ use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvid
|
||||||
|
|
||||||
class AuthServiceProvider extends ServiceProvider
|
class AuthServiceProvider extends ServiceProvider
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The policy mappings for the application.
|
* @inheritdoc
|
||||||
*
|
|
||||||
* @var array
|
|
||||||
*/
|
*/
|
||||||
protected $policies = [
|
protected $policies = [
|
||||||
User::class => UserPolicy::class,
|
User::class => UserPolicy::class,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,70 @@
|
||||||
|
<x-app-layout>
|
||||||
|
<x-slot name="title">Edit Profile</x-slot>
|
||||||
|
<x-slot name="header">
|
||||||
|
<h1 class="font-semibold text-xl text-gray-800 leading-tight">Edit Profile</h1>
|
||||||
|
</x-slot>
|
||||||
|
<form method="POST" enctype="multipart/form-data" action="{{ route('profiles.update', $user) }}">
|
||||||
|
@method('put')
|
||||||
|
@csrf
|
||||||
|
<div class="flex flex-col space-y-4">
|
||||||
|
<div class="flex flex-col space-y-4 md:flex-row md:space-x-4 md:space-y-0">
|
||||||
|
<!-- Username -->
|
||||||
|
<div class="flex-auto">
|
||||||
|
<x-inputs.label for="username" value="Username"/>
|
||||||
|
|
||||||
|
<x-inputs.input name="username"
|
||||||
|
type="text"
|
||||||
|
class="block mt-1 w-full"
|
||||||
|
autocapitalize="none"
|
||||||
|
:value="old('username', $user->username)"
|
||||||
|
:hasError="$errors->has('username')"
|
||||||
|
required />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Name -->
|
||||||
|
<div class="flex-auto">
|
||||||
|
<x-inputs.label for="name" value="Display name"/>
|
||||||
|
|
||||||
|
<x-inputs.input name="name"
|
||||||
|
type="text"
|
||||||
|
class="block mt-1 w-full"
|
||||||
|
:value="old('name', $user->name)"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-col space-y-4 md:flex-row md:space-x-4 md:space-y-0">
|
||||||
|
<!-- Password -->
|
||||||
|
<div class="flex-auto">
|
||||||
|
<x-inputs.label for="password" value="Password"/>
|
||||||
|
|
||||||
|
<x-inputs.input name="password"
|
||||||
|
type="password"
|
||||||
|
class="block mt-1 w-full"
|
||||||
|
:hasError="$errors->has('password')"
|
||||||
|
:required="!$user->exists"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Password confirm -->
|
||||||
|
<div class="flex-auto">
|
||||||
|
<x-inputs.label for="password_confirmation" value="Confirm Password"/>
|
||||||
|
|
||||||
|
<x-inputs.input name="password_confirmation"
|
||||||
|
type="password"
|
||||||
|
class="block mt-1 w-full"
|
||||||
|
:hasError="$errors->has('password')"
|
||||||
|
:required="!$user->exists"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Image -->
|
||||||
|
<div class="flex flex-col space-y-4 md:flex-row md:space-x-4 md:space-y-0">
|
||||||
|
<x-inputs.image :model="$user" preview_name="icon" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex items-center justify-end mt-4">
|
||||||
|
<x-inputs.button>Save</x-inputs.button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</x-app-layout>
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
<x-app-layout>
|
||||||
|
<x-slot name="title">Profile</x-slot>
|
||||||
|
<x-slot name="header">
|
||||||
|
<div class="flex justify-between items-center">
|
||||||
|
<h1 class="font-semibold text-2xl text-gray-800 leading-tight">Profile</h1>
|
||||||
|
</div>
|
||||||
|
</x-slot>
|
||||||
|
{{ $user->name }}
|
||||||
|
</x-app-layout>
|
||||||
|
|
@ -4,6 +4,7 @@ use App\Http\Controllers\FoodController;
|
||||||
use App\Http\Controllers\GoalController;
|
use App\Http\Controllers\GoalController;
|
||||||
use App\Http\Controllers\IngredientPickerController;
|
use App\Http\Controllers\IngredientPickerController;
|
||||||
use App\Http\Controllers\JournalEntryController;
|
use App\Http\Controllers\JournalEntryController;
|
||||||
|
use App\Http\Controllers\ProfileController;
|
||||||
use App\Http\Controllers\RecipeController;
|
use App\Http\Controllers\RecipeController;
|
||||||
use App\Http\Controllers\Auth\AuthenticatedSessionController;
|
use App\Http\Controllers\Auth\AuthenticatedSessionController;
|
||||||
use Illuminate\Support\Facades\Route;
|
use Illuminate\Support\Facades\Route;
|
||||||
|
|
@ -15,7 +16,9 @@ use Illuminate\Support\Facades\Route;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Route::middleware(['auth'])->group(function () {
|
Route::middleware(['auth'])->group(function () {
|
||||||
|
// Auth.
|
||||||
Route::post('/logout', [AuthenticatedSessionController::class, 'destroy'])->name('logout');
|
Route::post('/logout', [AuthenticatedSessionController::class, 'destroy'])->name('logout');
|
||||||
|
|
||||||
// Foods.
|
// Foods.
|
||||||
Route::resource('foods', FoodController::class);
|
Route::resource('foods', FoodController::class);
|
||||||
Route::get('/foods/{food}/delete', [FoodController::class, 'delete'])->name('foods.delete');
|
Route::get('/foods/{food}/delete', [FoodController::class, 'delete'])->name('foods.delete');
|
||||||
|
|
@ -36,4 +39,13 @@ Route::middleware(['auth'])->group(function () {
|
||||||
// Recipes.
|
// Recipes.
|
||||||
Route::resource('recipes', RecipeController::class);
|
Route::resource('recipes', RecipeController::class);
|
||||||
Route::get('/recipes/{recipe}/delete', [RecipeController::class, 'delete'])->name('recipes.delete');
|
Route::get('/recipes/{recipe}/delete', [RecipeController::class, 'delete'])->name('recipes.delete');
|
||||||
|
|
||||||
|
// Users.
|
||||||
|
Route::get('/profile/{user}', [ProfileController::class, 'show'])->name('profiles.show');
|
||||||
|
});
|
||||||
|
|
||||||
|
Route::middleware(['auth', 'can:editProfile,user'])->group(function () {
|
||||||
|
// Profiles (non-admin Users variant).
|
||||||
|
Route::get('/profile/{user}/edit', [ProfileController::class, 'edit'])->name('profiles.edit');
|
||||||
|
Route::put('/profile/{user}', [ProfileController::class, 'update'])->name('profiles.update');
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue