Skip to content

Commit 4ef6476

Browse files
authored
Merge pull request #69 from trakli/feat/image-support
feat: Add Iconable to Group, Wallet & Party
2 parents 2b3b8bc + facdb40 commit 4ef6476

File tree

14 files changed

+860
-134
lines changed

14 files changed

+860
-134
lines changed

app/Http/Controllers/API/v1/CategoryController.php

Lines changed: 28 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,21 @@
55
use App\Http\Controllers\API\ApiController;
66
use App\Models\Category;
77
use App\Rules\Iso8601DateTime;
8-
use App\Traits\HasIcon;
8+
use App\Services\FileService;
99
use Illuminate\Http\JsonResponse;
1010
use Illuminate\Http\Request;
1111
use Illuminate\Support\Facades\DB;
1212
use Illuminate\Support\Facades\Validator;
13+
use Illuminate\Validation\ValidationException;
1314
use OpenApi\Attributes as OA;
1415

15-
#[OA\Tag(name: 'Categories', description: 'Endpoints for managing transaction categories')]
16+
#[OA\Tag(name: 'Category', description: 'Endpoints for managing transaction categories')]
1617
class CategoryController extends ApiController
1718
{
18-
use HasIcon;
19-
2019
#[OA\Get(
2120
path: '/categories',
2221
summary: 'List all categories',
23-
tags: ['Categories'],
22+
tags: ['Category'],
2423
parameters: [
2524
new OA\Parameter(
2625
name: 'type',
@@ -70,7 +69,7 @@ public function index(Request $request): JsonResponse
7069
]
7170
)
7271
),
73-
tags: ['Categories'],
72+
tags: ['Category'],
7473
parameters: [
7574
new OA\Parameter(
7675
name: 'id',
@@ -122,15 +121,20 @@ public function update(Request $request, int $id): JsonResponse
122121
if (! $category) {
123122
return $this->failure('Category not found', 404);
124123
}
125-
DB::transaction(function () use ($data, $request, &$category) {
126-
127-
$category->update($data);
128-
$this->updateIcon($category, $data, $request);
124+
try {
125+
DB::transaction(function () use ($data, $request, &$category) {
126+
$category->update($data);
127+
FileService::updateIcon($category, $data, $request);
128+
});
129129

130-
});
131-
$category->refresh();
130+
$category->refresh();
132131

133-
return $this->success($category, 'Category updated successfully');
132+
return $this->success($category, 'Category updated successfully');
133+
} catch (ValidationException $e) {
134+
return $this->failure('Validation error', 422, $e->errors());
135+
} catch (\Exception $e) {
136+
return $this->failure('Failed to update category', 500, [$e->getMessage()]);
137+
}
134138
}
135139

136140
#[OA\Post(
@@ -152,7 +156,7 @@ public function update(Request $request, int $id): JsonResponse
152156
]
153157
)
154158
),
155-
tags: ['Categories'],
159+
tags: ['Category'],
156160
responses: [
157161
new OA\Response(
158162
response: 201,
@@ -194,7 +198,7 @@ public function store(Request $request): JsonResponse
194198
}
195199

196200
try {
197-
DB::transaction(function () use ($data, $request, $user, &$category) {
201+
$category = DB::transaction(function () use ($data, $request, $user) {
198202
/** @var Category $category */
199203
$category = $user->categories()->create($data);
200204

@@ -203,23 +207,26 @@ public function store(Request $request): JsonResponse
203207
}
204208
$category->markAsSynced();
205209

206-
$this->updateIcon($category, $data, $request);
210+
FileService::updateIcon($category, $data, $request);
211+
212+
return $category;
207213
});
214+
208215
$category->refresh();
209216

210217
return $this->success($category, 'Category created successfully', 201);
218+
} catch (ValidationException $e) {
219+
return $this->failure('Validation error', 422, $e->errors());
211220
} catch (\Exception $e) {
212-
$status_code = intval($e->getCode());
213-
214-
return $this->failure('Failed to create category', $status_code > 100 ? $status_code : 500, [$e->getMessage()]);
221+
return $this->failure('Failed to create category', 500, [$e->getMessage()]);
215222
}
216223
}
217224

218225
#[
219226
OA\Get(
220227
path: '/categories/{id}',
221228
summary: 'Get a specific category',
222-
tags: ['Categories'],
229+
tags: ['Category'],
223230
parameters: [
224231
new OA\Parameter(
225232
name: 'id',
@@ -260,7 +267,7 @@ public function show(Request $request, int $id): JsonResponse
260267
#[OA\Delete(
261268
path: '/categories/{id}',
262269
summary: 'Delete a specific category',
263-
tags: ['Categories'],
270+
tags: ['Category'],
264271
parameters: [
265272
new OA\Parameter(
266273
name: 'id',

app/Http/Controllers/API/v1/GroupController.php

Lines changed: 47 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,12 @@
55
use App\Http\Controllers\API\ApiController;
66
use App\Models\Group;
77
use App\Rules\Iso8601DateTime;
8+
use App\Services\FileService;
89
use Illuminate\Http\JsonResponse;
910
use Illuminate\Http\Request;
11+
use Illuminate\Support\Facades\DB;
1012
use Illuminate\Support\Facades\Validator;
13+
use Illuminate\Validation\ValidationException;
1114
use OpenApi\Attributes as OA;
1215

1316
/**
@@ -63,8 +66,8 @@ public function index(Request $request): JsonResponse
6366
content: new OA\JsonContent(
6467
required: ['name'],
6568
properties: [
66-
new OA\Property(property: 'client_id', type: 'string', format: 'uuid',
67-
description: 'Unique identifier for your local client'),
69+
new OA\Property(property: 'client_id', description: 'Unique identifier for your local client', type: 'string',
70+
format: 'uuid'),
6871
new OA\Property(
6972
property: 'name',
7073
description: 'Name of the group',
@@ -75,6 +78,8 @@ public function index(Request $request): JsonResponse
7578
description: 'Description of the group',
7679
type: 'string'
7780
),
81+
new OA\Property(property: 'icon', description: 'The icon of the group (file or icon string)', type: 'string'),
82+
new OA\Property(property: 'icon_type', description: 'The type of the icon (icon or emoji or image)', type: 'string'),
7883
new OA\Property(property: 'created_at', type: 'string', format: 'date-time'),
7984
]
8085
)
@@ -102,27 +107,42 @@ public function store(Request $request): JsonResponse
102107
'client_id' => 'nullable|uuid',
103108
'name' => 'required|string|max:255',
104109
'description' => 'sometimes|string|max:255',
110+
'icon' => 'nullable',
111+
'icon_type' => 'required_with:icon|string|in:icon,image,emoji',
105112
'created_at' => ['nullable', new Iso8601DateTime],
106113
]);
107114

108115
if ($validator->fails()) {
109116
return $this->failure('Validation error', 422, $validator->errors()->all());
110117
}
111-
118+
$data = $validator->validated();
112119
$user = $request->user();
113120
try {
114-
/** @var Group */
115-
$group = $user->groups()->create($validator->validated());
121+
$group = DB::transaction(function () use ($data, $request, $user) {
122+
123+
/** @var Group $group */
124+
$group = $user->groups()->create($data);
125+
126+
if (isset($request['client_id'])) {
127+
$group->setClientGeneratedId($request['client_id']);
128+
}
129+
$group->markAsSynced();
130+
131+
FileService::updateIcon($group, $data, $request);
132+
133+
return $group;
116134

117-
if (isset($request['client_id'])) {
118-
$group->setClientGeneratedId($request['client_id']);
119-
}
120-
$group->markAsSynced();
135+
});
136+
$group->refresh();
137+
138+
return $this->success($group, 'Group created successfully', 201);
139+
140+
} catch (ValidationException $e) {
141+
return $this->failure('Validation error', 422, $e->errors());
121142
} catch (\Exception $e) {
122143
return $this->failure('Failed to create group', 500, [$e->getMessage()]);
123144
}
124145

125-
return $this->success($group, 'Group created successfully', 201);
126146
}
127147

128148
#[OA\Get(
@@ -178,6 +198,8 @@ public function show(int $id): JsonResponse
178198
description: 'Name of the group',
179199
type: 'string'
180200
),
201+
new OA\Property(property: 'icon', description: 'The icon of the group (file or icon string)', type: 'string'),
202+
new OA\Property(property: 'icon_type', description: 'The type of the icon (icon or emoji or image)', type: 'string'),
181203
]
182204
)
183205
),
@@ -216,6 +238,8 @@ public function update(Request $request, int $id): JsonResponse
216238
$validator = Validator::make($request->all(), [
217239
'name' => 'sometimes|required|string|max:255',
218240
'description' => 'sometimes|string|max:255',
241+
'icon' => 'nullable',
242+
'icon_type' => 'required_with:icon|string|in:icon,image,emoji',
219243
]);
220244

221245
if ($validator->fails()) {
@@ -224,14 +248,25 @@ public function update(Request $request, int $id): JsonResponse
224248

225249
$user = $request->user();
226250
$group = $user->groups()->find($id);
251+
$data = $validator->validated();
227252

228253
if (! $group) {
229254
return $this->failure('Group not found', 404);
230255
}
256+
try {
257+
DB::transaction(function () use ($data, $request, &$group) {
258+
$group->update($data);
259+
FileService::updateIcon($group, $data, $request);
260+
});
231261

232-
$group->update($validator->validated());
262+
$group->refresh();
233263

234-
return $this->success($group, 'Group updated successfully');
264+
return $this->success($group, 'Group updated successfully');
265+
} catch (ValidationException $e) {
266+
return $this->failure('Validation error', 422, $e->errors());
267+
} catch (\Exception $e) {
268+
return $this->failure('Failed to update group', 500, [$e->getMessage()]);
269+
}
235270
}
236271

237272
#[OA\Delete(

app/Http/Controllers/API/v1/PartyController.php

Lines changed: 45 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,11 @@
55
use App\Http\Controllers\API\ApiController;
66
use App\Models\Party;
77
use App\Rules\Iso8601DateTime;
8+
use App\Services\FileService;
89
use Illuminate\Http\JsonResponse;
910
use Illuminate\Http\Request;
11+
use Illuminate\Support\Facades\DB;
12+
use Illuminate\Validation\ValidationException;
1013
use OpenApi\Attributes as OA;
1114

1215
/**
@@ -69,10 +72,12 @@ public function index(Request $request): JsonResponse
6972
content: new OA\JsonContent(
7073
required: ['name'],
7174
properties: [
72-
new OA\Property(property: 'client_id', type: 'string', format: 'uuid',
73-
description: 'Unique identifier for your local client'),
75+
new OA\Property(property: 'client_id', description: 'Unique identifier for your local client', type: 'string',
76+
format: 'uuid'),
7477
new OA\Property(property: 'name', type: 'string', example: 'John Doe'),
7578
new OA\Property(property: 'description', type: 'string', example: 'Incomes from John Doe'),
79+
new OA\Property(property: 'icon', description: 'The icon of the party (file or icon string)', type: 'string'),
80+
new OA\Property(property: 'icon_type', description: 'The type of the icon (icon or emoji or image)', type: 'string'),
7681
new OA\Property(property: 'created_at', type: 'string', format: 'date-time'),
7782

7883
]
@@ -105,28 +110,41 @@ public function store(Request $request): JsonResponse
105110
'client_id' => 'nullable|uuid',
106111
'name' => 'required|string|max:255',
107112
'description' => 'sometimes|string',
113+
'icon' => 'nullable',
114+
'icon_type' => 'required_with:icon|string|in:icon,image,emoji',
108115
'created_at' => ['nullable', new Iso8601DateTime],
109116
]);
110117

111118
$user = $request->user();
112119
$validatedData['user_id'] = $user->id;
113-
$party = $user->parties()->where('name', $validatedData['name'])->first();
114-
if ($party) {
120+
$existing_party = $user->parties()->where('name', $validatedData['name'])->first();
121+
if ($existing_party) {
115122
return $this->failure('Party already exists', 400);
116123
}
117124

118125
try {
119-
/** @var Party */
120-
$party = $user->parties()->create($validatedData);
121-
if (! empty($validatedData['client_id'])) {
122-
$party->setClientGeneratedId($validatedData['client_id']);
123-
}
124-
$party->markAsSynced();
126+
$party = DB::transaction(function () use ($validatedData, $request, $user) {
127+
/** @var Party $party */
128+
$party = $user->parties()->create($validatedData);
129+
if (! empty($validatedData['client_id'])) {
130+
$party->setClientGeneratedId($validatedData['client_id']);
131+
}
132+
$party->markAsSynced();
133+
FileService::updateIcon($party, $validatedData, $request);
134+
135+
return $party;
136+
});
137+
138+
$party->refresh();
139+
140+
return $this->success($party, 'Party created successfully', 201);
141+
142+
} catch (ValidationException $e) {
143+
return $this->failure('Validation error', 422, $e->errors());
125144
} catch (\Exception $e) {
126145
return $this->failure('Failed to create party', 500, [$e->getMessage()]);
127146
}
128147

129-
return $this->success($party, 'Party created successfully', 201);
130148
}
131149

132150
#[OA\Get(
@@ -181,6 +199,8 @@ public function show(int $id): JsonResponse
181199
properties: [
182200
new OA\Property(property: 'name', type: 'string', example: 'Jane Doe'),
183201
new OA\Property(property: 'description', type: 'string', example: 'income from John Doe'),
202+
new OA\Property(property: 'icon', description: 'The icon of the party (file or icon string)', type: 'string'),
203+
new OA\Property(property: 'icon_type', description: 'The type of the icon (icon or emoji or image)', type: 'string'),
184204
]
185205
)
186206
),
@@ -222,6 +242,8 @@ public function update(Request $request, int $id): JsonResponse
222242
$validatedData = $request->validate([
223243
'name' => 'sometimes|required|string|max:255',
224244
'description' => 'sometimes|string',
245+
'icon' => 'nullable',
246+
'icon_type' => 'required_with:icon|string|in:icon,image,emoji',
225247
]);
226248

227249
$user = $request->user();
@@ -230,10 +252,20 @@ public function update(Request $request, int $id): JsonResponse
230252
if (! $party) {
231253
return $this->failure('Party not found', 404);
232254
}
255+
try {
256+
DB::transaction(function () use ($validatedData, $request, &$party) {
257+
$party->update($validatedData);
258+
FileService::updateIcon($party, $validatedData, $request);
259+
});
233260

234-
$party->update($validatedData);
261+
$party->refresh();
235262

236-
return $this->success($party, 'Party updated successfully');
263+
return $this->success($party, 'Party updated successfully');
264+
} catch (ValidationException $e) {
265+
return $this->failure('Validation error', 422, $e->errors());
266+
} catch (\Exception $e) {
267+
return $this->failure('Failed to update party', 500, [$e->getMessage()]);
268+
}
237269
}
238270

239271
#[OA\Delete(

app/Http/Controllers/API/v1/TransactionController.php

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use App\Http\Controllers\API\ApiController;
66
use App\Models\Transaction;
77
use App\Rules\Iso8601DateTime;
8+
use App\Services\FileService;
89
use Illuminate\Http\JsonResponse;
910
use Illuminate\Http\Request;
1011
use Illuminate\Support\Facades\DB;
@@ -108,16 +109,7 @@ public function uploadFiles(Request $request, $id)
108109

109110
try {
110111
DB::transaction(function () use ($request, $transaction) {
111-
112-
if ($request->hasFile('files')) {
113-
foreach ($request->file('files') as $file) {
114-
$path = $file->store('transactions');
115-
$transaction->files()->create([
116-
'path' => $path,
117-
'type' => 'file',
118-
]);
119-
}
120-
}
112+
FileService::uploadFiles($transaction, $request, 'files', 'transactions');
121113
});
122114

123115
} catch (\Throwable $e) {

0 commit comments

Comments
 (0)