Skip to content

Commit 3a9b08d

Browse files
feat: record category management
1 parent da2042b commit 3a9b08d

File tree

15 files changed

+454
-6
lines changed

15 files changed

+454
-6
lines changed
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
<?php
2+
3+
namespace App\Http\Controllers;
4+
5+
use App\Http\Requests\RecordCategories\StoreRecordCategoryRequest;
6+
use App\Http\Requests\RecordCategories\UpdateRecordCategoryRequest;
7+
use App\Models\RecordCategory;
8+
use Illuminate\Contracts\View\View;
9+
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
10+
use Illuminate\Http\RedirectResponse;
11+
use Illuminate\Http\Request;
12+
13+
final class RecordCategoryController extends Controller
14+
{
15+
use AuthorizesRequests;
16+
17+
public function index(Request $request): View
18+
{
19+
/** @var \App\Models\User $user */
20+
$user = $request->user();
21+
22+
$categories = $user
23+
->recordCategories()
24+
->paginate();
25+
26+
return view('record-categories.index', [
27+
'recordCategories' => $categories->withQueryString(),
28+
]);
29+
}
30+
31+
/**
32+
* @throws \Illuminate\Auth\Access\AuthorizationException
33+
*/
34+
public function create(): View
35+
{
36+
$this->authorize('create', RecordCategory::class);
37+
38+
return view('record-categories.create');
39+
}
40+
41+
public function store(StoreRecordCategoryRequest $request): RedirectResponse
42+
{
43+
$category = new RecordCategory();
44+
$category->user()->associate($request->user());
45+
$category->name = $request->validated('name');
46+
$category->save();
47+
48+
return redirect()->route('record-categories.edit', $category);
49+
}
50+
51+
/**
52+
* @throws \Illuminate\Auth\Access\AuthorizationException
53+
*/
54+
public function edit(RecordCategory $recordCategory): View
55+
{
56+
$this->authorize('update', $recordCategory);
57+
58+
return view('record-categories.edit', [
59+
'recordCategory' => $recordCategory,
60+
]);
61+
}
62+
63+
public function update(UpdateRecordCategoryRequest $request, RecordCategory $recordCategory): RedirectResponse
64+
{
65+
$recordCategory->name = $request->validated('name');
66+
$recordCategory->save();
67+
68+
return redirect()->route('record-categories.index');
69+
}
70+
71+
72+
/**
73+
* @throws \Illuminate\Auth\Access\AuthorizationException
74+
*/
75+
public function destroy(Request $request, RecordCategory $recordCategory): RedirectResponse
76+
{
77+
$this->authorize('delete', $recordCategory);
78+
79+
$recordCategory->delete();
80+
81+
return redirect()->route('record-categories.index');
82+
}
83+
}

app/Http/Controllers/RecordController.php

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
use Illuminate\Contracts\View\View;
1212
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
1313
use Illuminate\Http\RedirectResponse;
14-
use Illuminate\Http\Request;
1514
use Illuminate\Support\Facades\DB;
1615

1716
final class RecordController extends Controller
@@ -20,16 +19,18 @@ final class RecordController extends Controller
2019

2120
public function index(IndexRecordRequest $request): View
2221
{
22+
/** @var \App\Models\User $user */
2323
$user = $request->user();
2424

25+
/** @var \Illuminate\Pagination\LengthAwarePaginator<int, \App\Models\Record> $records */
2526
$records = $user->records()
2627
->with('recordImages')
2728
->tap(new ApplyRecordFilters($request->filters()))
2829
->latest()
29-
->paginate();
30+
->paginate(9);
3031

3132
return view('records.index', [
32-
'records' => $records,
33+
'records' => $records->withQueryString(),
3334
]);
3435
}
3536

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
namespace App\Http\Requests\RecordCategories;
4+
5+
use App\Models\RecordCategory;
6+
use Illuminate\Foundation\Http\FormRequest;
7+
8+
final class StoreRecordCategoryRequest extends FormRequest
9+
{
10+
public function authorize(): bool
11+
{
12+
return $this->user()->can('create', RecordCategory::class);
13+
}
14+
15+
public function rules(): array
16+
{
17+
return [
18+
'name' => [
19+
'required',
20+
'string',
21+
'max:255',
22+
],
23+
];
24+
}
25+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
namespace App\Http\Requests\RecordCategories;
4+
5+
use Illuminate\Foundation\Http\FormRequest;
6+
7+
final class UpdateRecordCategoryRequest extends FormRequest
8+
{
9+
public function authorize(): bool
10+
{
11+
$category = $this->route('record_category');
12+
13+
return $this->user()->can('update', $category);
14+
}
15+
16+
public function rules(): array
17+
{
18+
return [
19+
'name' => ['required', 'string', 'max:255'],
20+
];
21+
}
22+
}

app/Models/RecordCategory.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
namespace App\Models;
4+
5+
use Illuminate\Database\Eloquent\Factories\HasFactory;
6+
use Illuminate\Database\Eloquent\Model;
7+
use Illuminate\Database\Eloquent\Relations\BelongsTo;
8+
9+
/**
10+
* @property-read int $id
11+
* @property int $user_id
12+
* @property string $name
13+
* @property \Carbon\Carbon $created_at
14+
* @property \Carbon\Carbon $updated_at
15+
* @property-read \App\Models\User $user
16+
*/
17+
final class RecordCategory extends Model
18+
{
19+
/** @use HasFactory<\Database\Factories\RecordCategoryFactory> */
20+
use HasFactory;
21+
22+
/**
23+
* Query the user.
24+
*
25+
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo<\App\Models\User, $this>
26+
*/
27+
public function user(): BelongsTo
28+
{
29+
return $this->belongsTo(User::class);
30+
}
31+
}

app/Models/User.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
* @property \Illuminate\Support\Carbon $created_at
1919
* @property \Illuminate\Support\Carbon $updated_at
2020
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Record> $records
21+
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\RecordCategory> $recordCategories
2122
*/
2223
class User extends Auth\User
2324
{
@@ -67,4 +68,14 @@ public function records(): HasMany
6768
{
6869
return $this->hasMany(Record::class);
6970
}
71+
72+
/**
73+
* Query the record categories.
74+
*
75+
* @return \Illuminate\Database\Eloquent\Relations\HasMany<\App\Models\Record, $this>
76+
*/
77+
public function recordCategories(): HasMany
78+
{
79+
return $this->hasMany(RecordCategory::class);
80+
}
7081
}

app/Policies/RecordCategoryPolicy.php

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<?php
2+
3+
namespace App\Policies;
4+
5+
use App\Models\RecordCategory;
6+
use App\Models\User;
7+
8+
class RecordCategoryPolicy
9+
{
10+
/**
11+
* Determine whether the use can view any record category.
12+
*
13+
* @param \App\Models\User $user
14+
* @return true
15+
*/
16+
public function viewAny(User $user): true
17+
{
18+
return true;
19+
}
20+
21+
/**
22+
* Determine whether the user can view the record category.
23+
*
24+
* @param \App\Models\User $user
25+
* @param \App\Models\RecordCategory $recordCategory
26+
* @return bool
27+
*/
28+
public function view(User $user, RecordCategory $recordCategory): bool
29+
{
30+
return $user->id === $recordCategory->user_id;
31+
}
32+
33+
/**
34+
* Determine whether the user can create record categories.
35+
*
36+
* @param \App\Models\User $user
37+
* @return bool
38+
*/
39+
public function create(User $user): bool
40+
{
41+
return $user->can('viewAny', RecordCategory::class);
42+
}
43+
44+
/**
45+
* Determine whether the user can update the specified category.
46+
*
47+
* @param \App\Models\User $user
48+
* @param \App\Models\RecordCategory $recordCategory
49+
* @return bool
50+
*/
51+
public function update(User $user, RecordCategory $recordCategory): bool
52+
{
53+
return $user->can('view', $recordCategory);
54+
}
55+
56+
/**
57+
* Determine whether the user can delete the specified category.
58+
*
59+
* @param \App\Models\User $user
60+
* @param \App\Models\RecordCategory $recordCategory
61+
* @return bool
62+
*/
63+
public function delete(User $user, RecordCategory $recordCategory): bool
64+
{
65+
return $user->can('update', $recordCategory);
66+
}
67+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
namespace Database\Factories;
4+
5+
use Illuminate\Database\Eloquent\Factories\Factory;
6+
7+
/**
8+
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\RecordCategory>
9+
*/
10+
class RecordCategoryFactory extends Factory
11+
{
12+
/**
13+
* Define the model's default state.
14+
*
15+
* @return array<string, mixed>
16+
*/
17+
public function definition(): array
18+
{
19+
return [
20+
//
21+
];
22+
}
23+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
3+
use Illuminate\Database\Migrations\Migration;
4+
use Illuminate\Database\Schema\Blueprint;
5+
use Illuminate\Support\Facades\Schema;
6+
7+
return new class extends Migration
8+
{
9+
/**
10+
* Run the migrations.
11+
*/
12+
public function up(): void
13+
{
14+
Schema::create('record_categories', function (Blueprint $table) {
15+
$table->id();
16+
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
17+
$table->string('name');
18+
$table->timestamps();
19+
});
20+
}
21+
22+
/**
23+
* Reverse the migrations.
24+
*/
25+
public function down(): void
26+
{
27+
Schema::dropIfExists('record_categories');
28+
}
29+
};

resources/views/components/layouts/main.blade.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<meta charset="UTF-8">
55
<meta
66
name="viewport"
7-
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
7+
content="width=device-width, initial-scale=1.0, maximum-scale=5.0, minimum-scale=1.0">
88
<meta http-equiv="X-UA-Compatible" content="ie=edge">
99
<title>{{ config('app.name', 'Disk union') }}</title>
1010

0 commit comments

Comments
 (0)