Skip to content

Commit f9e056d

Browse files
authored
feat(request): implement Wishbox request model and API endpoints (#110)
Introduce Wishbox request model and create API endpoints for listing, showing, creating, and deleting requests. Implement permissions to control access for viewing and deleting requests. --- - Close: #23 - Close: #7 - Close: #8 - Close: #9 --------- Signed-off-by: Valentin Sickert <[email protected]>
1 parent 019baab commit f9e056d

File tree

9 files changed

+456
-0
lines changed

9 files changed

+456
-0
lines changed
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
<?php
2+
3+
namespace App\Http\Controllers;
4+
5+
use App\Http\Responses\ApiErrorResponse;
6+
use App\Http\Responses\ApiSuccessResponse;
7+
use App\Models\Request as WishRequest;
8+
use App\Permissions\RequestPermissions;
9+
use Illuminate\Http\Request;
10+
use Illuminate\Http\Response;
11+
12+
class RequestController extends Controller
13+
{
14+
15+
16+
/**
17+
* Constructor method for the RequestController class.
18+
* Applies middleware permissions for specific controller actions.
19+
*
20+
* @codeCoverageIgnore
21+
*
22+
* @return void
23+
*/
24+
public function __construct()
25+
{
26+
$this->middleware('permission:' . RequestPermissions::CAN_VIEW_REQUESTS)->only(['index', 'show']);
27+
$this->middleware('permission:' . RequestPermissions::CAN_DELETE_REQUESTS)->only(['destroy']);
28+
}
29+
30+
/**
31+
* Retrieve a paginated list of requests.
32+
*
33+
* @param Request $httpRequest
34+
* @return \Illuminate\Pagination\LengthAwarePaginator
35+
*/
36+
public function index(Request $httpRequest): \Illuminate\Pagination\LengthAwarePaginator
37+
{
38+
$httpRequest->validate([
39+
'sort' => 'string|in:id,id:asc,id:desc,name,name:asc,name:desc,created_at,created_at:asc,created_at:desc,',
40+
'per_page' => 'integer|between:1,50',
41+
]);
42+
43+
if ($httpRequest->sort !== null) {
44+
$sort = explode(':', $httpRequest->sort);
45+
$requests = WishRequest::orderBy($sort[0], $sort[1] ?? 'asc')->paginate($httpRequest->per_page ?? 25);
46+
} else {
47+
$requests = WishRequest::orderBy('created_at')->paginate($httpRequest->per_page ?? 25);
48+
}
49+
50+
return $requests;
51+
}
52+
53+
/**
54+
* Store a newly created resource in storage.
55+
*/
56+
public function store(Request $httpRequest)
57+
{
58+
$httpRequest->validate([
59+
'name' => 'required|string|max:255',
60+
'message' => 'required|string',
61+
]);
62+
63+
$request = WishRequest::create([
64+
'name' => $httpRequest->name,
65+
'message' => $httpRequest->message,
66+
]);
67+
68+
if ($request === null) {
69+
// @codeCoverageIgnoreStart
70+
return new ApiErrorResponse('Failed to create request');
71+
// @codeCoverageIgnoreEnd
72+
} else {
73+
return new ApiSuccessResponse($request, status: Response::HTTP_CREATED);
74+
}
75+
}
76+
77+
/**
78+
* Display the specified resource.
79+
*/
80+
public function show(WishRequest $request)
81+
{
82+
return new ApiSuccessResponse($request);
83+
}
84+
85+
/**
86+
* Remove the specified resource from storage.
87+
*/
88+
public function destroy(WishRequest $request)
89+
{
90+
if($request->delete()) {
91+
return new ApiSuccessResponse('', status: Response::HTTP_NO_CONTENT);
92+
} else {
93+
// @codeCoverageIgnoreStart
94+
return new ApiErrorResponse('Failed to delete');
95+
// @codeCoverageIgnoreEnd
96+
}
97+
}
98+
}

app/Models/Request.php

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
3+
namespace App\Models;
4+
5+
use Illuminate\Database\Eloquent\Factories\HasFactory;
6+
use Illuminate\Database\Eloquent\Model;
7+
8+
class Request extends Model
9+
{
10+
use HasFactory;
11+
12+
/**
13+
* The attributes that are mass assignable.
14+
*
15+
* @var array<int, string>
16+
*/
17+
protected $fillable = [
18+
'name',
19+
'message',
20+
];
21+
22+
/**
23+
* The attributes that should be hidden for serialization.
24+
*
25+
* @var array<int, string>
26+
*/
27+
protected $hidden = [
28+
'updated_at',
29+
];
30+
31+
/**
32+
* The attributes that should be cast.
33+
*
34+
* @var array<string, string>
35+
*/
36+
protected $casts = [
37+
'created_at' => 'datetime',
38+
'updated_at' => 'datetime',
39+
];
40+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
3+
namespace App\Permissions;
4+
5+
/**
6+
* Class RequestPermissions
7+
*
8+
* This class defines the permissions related to requests.
9+
*/
10+
class RequestPermissions
11+
{
12+
/** Permission for listing and view all users. */
13+
public const CAN_VIEW_REQUESTS = 'requests.view';
14+
15+
/** Permission for deleting users. */
16+
public const CAN_DELETE_REQUESTS = 'requests.delete';
17+
}

database/factories/RequestFactory.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
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\Request>
9+
*/
10+
class RequestFactory 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+
'name' => $this->faker->name,
21+
'message' => $this->faker->paragraph()
22+
];
23+
}
24+
}
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('requests', function (Blueprint $table) {
15+
$table->id();
16+
$table->string('name');
17+
$table->text('message')->max(2000);
18+
$table->timestamps();
19+
});
20+
}
21+
22+
/**
23+
* Reverse the migrations.
24+
*/
25+
public function down(): void
26+
{
27+
Schema::dropIfExists('requests');
28+
}
29+
};
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
3+
use Illuminate\Database\Migrations\Migration;
4+
use Spatie\Permission\Models\Permission;
5+
use Illuminate\Support\Facades\DB;
6+
7+
return new class extends Migration
8+
{
9+
/**
10+
* Run the migrations.
11+
*/
12+
public function up(): void
13+
{
14+
Permission::create([
15+
'name' => 'requests.view',
16+
'guard_name' => 'web',
17+
]);
18+
Permission::create([
19+
'name' => 'requests.delete',
20+
'guard_name' => 'web',
21+
]);
22+
}
23+
24+
/**
25+
* Reverse the migrations.
26+
*/
27+
public function down(): void
28+
{
29+
DB::table('permissions')->whereIn('name', [
30+
'requests.view',
31+
'requests.delete',
32+
])->delete();
33+
}
34+
};

routes/api.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,6 @@
2424
require __DIR__ . '/api/v1/auth.php';
2525
require __DIR__ . '/api/v1/user.php';
2626
require __DIR__ . '/api/v1/role.php';
27+
require __DIR__ . '/api/v1/request.php';
2728
require __DIR__ . '/api/v1/permission.php';
2829
});

routes/api/v1/request.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
use App\Http\Controllers\RequestController;
4+
use Illuminate\Support\Facades\Route;
5+
6+
7+
Route::post('/requests', [RequestController::class, 'store'])->name('api.v1.requests.store');
8+
9+
Route::group(['middleware' => 'auth:sanctum'], function () {
10+
Route::get('/requests', [RequestController::class, 'index'])->name('api.v1.requests.index');
11+
Route::get('/requests/{request}', [RequestController::class, 'show'])->name('api.v1.requests.show');
12+
Route::delete('/requests/{request}', [RequestController::class, 'destroy'])->name('api.v1.requests.destroy');
13+
});

0 commit comments

Comments
 (0)