-
Notifications
You must be signed in to change notification settings - Fork 26
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #406 from karlomikus/calculator
Feat: Calculators
- Loading branch information
Showing
24 changed files
with
1,636 additions
and
46 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,192 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Kami\Cocktail\Http\Controllers; | ||
|
||
use Illuminate\Http\Request; | ||
use Illuminate\Http\Response; | ||
use OpenApi\Attributes as OAT; | ||
use Illuminate\Http\JsonResponse; | ||
use Kami\Cocktail\OpenAPI as BAO; | ||
use Kami\Cocktail\Models\Calculator; | ||
use Kami\Cocktail\Models\CalculatorBlock; | ||
use Illuminate\Http\Resources\Json\JsonResource; | ||
use Kami\Cocktail\Http\Resources\CalculatorResource; | ||
use Kami\Cocktail\OpenAPI\Schemas\CalculatorRequest; | ||
use Kami\Cocktail\OpenAPI\Schemas\CalculatorSolveRequest; | ||
use Kami\Cocktail\Http\Resources\CalculatorResultResource; | ||
use Kami\Cocktail\Http\Requests\CalculatorRequest as CalculatorFormRequest; | ||
|
||
class CalculatorController extends Controller | ||
{ | ||
#[OAT\Get(path: '/calculators', tags: ['Calculator'], operationId: 'listCalculators', description: 'Show a list of all calculators in a bar', summary: 'List calculators', parameters: [ | ||
new BAO\Parameters\BarIdHeaderParameter(), | ||
])] | ||
#[BAO\SuccessfulResponse(content: [ | ||
new BAO\WrapItemsWithData(BAO\Schemas\Calculator::class), | ||
])] | ||
public function index(): JsonResource | ||
{ | ||
$calculators = Calculator::filterByBar()->with('blocks')->get(); | ||
|
||
return CalculatorResource::collection($calculators); | ||
} | ||
|
||
#[OAT\Get(path: '/calculators/{id}', tags: ['Calculator'], operationId: 'showCalculator', description: 'Show a specific calculator', summary: 'Show calculator', parameters: [ | ||
new BAO\Parameters\DatabaseIdParameter(), | ||
])] | ||
#[BAO\SuccessfulResponse(content: [ | ||
new BAO\WrapObjectWithData(BAO\Schemas\Calculator::class), | ||
])] | ||
#[BAO\NotAuthorizedResponse] | ||
#[BAO\NotFoundResponse] | ||
public function show(Request $request, int $id): JsonResource | ||
{ | ||
$calculator = Calculator::with('blocks')->findOrFail($id); | ||
|
||
if ($request->user()->cannot('show', $calculator)) { | ||
abort(403); | ||
} | ||
|
||
return new CalculatorResource($calculator); | ||
} | ||
|
||
#[OAT\Post(path: '/calculators', tags: ['Calculator'], operationId: 'saveCalculator', description: 'Create a new calculator', summary: 'Create calculator', parameters: [ | ||
new BAO\Parameters\BarIdHeaderParameter(), | ||
], requestBody: new OAT\RequestBody( | ||
required: true, | ||
content: [ | ||
new OAT\JsonContent(ref: BAO\Schemas\CalculatorRequest::class), | ||
] | ||
))] | ||
#[OAT\Response(response: 201, description: 'Successful response', content: [ | ||
new BAO\WrapObjectWithData(BAO\Schemas\Calculator::class), | ||
], headers: [ | ||
new OAT\Header(header: 'Location', description: 'URL of the new resource', schema: new OAT\Schema(type: 'string')), | ||
])] | ||
#[BAO\NotAuthorizedResponse] | ||
public function store(CalculatorFormRequest $request): JsonResponse | ||
{ | ||
if ($request->user()->cannot('create', Calculator::class)) { | ||
abort(403); | ||
} | ||
|
||
$requestSchema = CalculatorRequest::fromArray($request->all()); | ||
|
||
$calculator = new Calculator(); | ||
$calculator->name = $requestSchema->name; | ||
$calculator->description = $requestSchema->description; | ||
$calculator->bar_id = bar()->id; | ||
$calculator->save(); | ||
|
||
foreach ($requestSchema->blocks as $block) { | ||
$calculatorBlock = new CalculatorBlock(); | ||
$calculatorBlock->type = $block->type; | ||
$calculatorBlock->label = $block->label; | ||
$calculatorBlock->variable_name = $block->variableName; | ||
$calculatorBlock->value = $block->value; | ||
$calculatorBlock->sort = $block->sort; | ||
$calculatorBlock->description = $block->description; | ||
$calculatorBlock->calculator_id = $calculator->id; | ||
$calculatorBlock->settings = $block->settings->toArray(); | ||
$calculatorBlock->save(); | ||
} | ||
|
||
return (new CalculatorResource($calculator)) | ||
->response() | ||
->setStatusCode(201) | ||
->header('Location', route('calculators.show', $calculator->id)); | ||
} | ||
|
||
#[OAT\Put(path: '/calculators/{id}', tags: ['Calculator'], operationId: 'updateCalculator', description: 'Update a specific calculator', summary: 'Update calculator', parameters: [ | ||
new BAO\Parameters\DatabaseIdParameter(), | ||
], requestBody: new OAT\RequestBody( | ||
required: true, | ||
content: [ | ||
new OAT\JsonContent(ref: BAO\Schemas\CalculatorRequest::class), | ||
] | ||
))] | ||
#[BAO\SuccessfulResponse(content: [ | ||
new BAO\WrapObjectWithData(BAO\Schemas\Calculator::class), | ||
])] | ||
#[BAO\NotAuthorizedResponse] | ||
#[BAO\NotFoundResponse] | ||
public function update(CalculatorFormRequest $request, int $id): JsonResource | ||
{ | ||
$calculator = Calculator::findOrFail($id); | ||
|
||
if ($request->user()->cannot('edit', $calculator)) { | ||
abort(403); | ||
} | ||
|
||
$requestSchema = CalculatorRequest::fromArray($request->all()); | ||
|
||
$calculator->name = $requestSchema->name; | ||
$calculator->description = $requestSchema->description; | ||
$calculator->updated_at = now(); | ||
$calculator->save(); | ||
|
||
$calculator->blocks()->delete(); | ||
foreach ($requestSchema->blocks as $block) { | ||
$calculatorBlock = new CalculatorBlock(); | ||
$calculatorBlock->type = $block->type; | ||
$calculatorBlock->label = $block->label; | ||
$calculatorBlock->variable_name = $block->variableName; | ||
$calculatorBlock->value = $block->value; | ||
$calculatorBlock->sort = $block->sort; | ||
$calculatorBlock->description = $block->description; | ||
$calculatorBlock->calculator_id = $calculator->id; | ||
$calculatorBlock->settings = $block->settings->toArray(); | ||
$calculatorBlock->save(); | ||
} | ||
|
||
return new CalculatorResource($calculator); | ||
} | ||
|
||
#[OAT\Delete(path: '/calculators/{id}', tags: ['Calculator'], operationId: 'deleteCalculator', description: 'Delete a specific calculator', summary: 'Delete calculator', parameters: [ | ||
new BAO\Parameters\DatabaseIdParameter(), | ||
])] | ||
#[OAT\Response(response: 204, description: 'Successful response')] | ||
#[BAO\NotAuthorizedResponse] | ||
#[BAO\NotFoundResponse] | ||
public function delete(Request $request, int $id): Response | ||
{ | ||
$calculator = Calculator::findOrFail($id); | ||
|
||
if ($request->user()->cannot('delete', $calculator)) { | ||
abort(403); | ||
} | ||
|
||
$calculator->delete(); | ||
|
||
return new Response(null, 204); | ||
} | ||
|
||
#[OAT\Post(path: '/calculators/{id}/solve', tags: ['Calculator'], operationId: 'solveCalculator', description: 'Solve calculator expressions. Takes a JSON body with the calculator input variables names as keys and their values as values and solves the defined evaluations. Results are objects with evaluation variable names as keys and solved expression result as values.', summary: 'Solve calculator', parameters: [ | ||
new BAO\Parameters\DatabaseIdParameter(), | ||
], requestBody: new OAT\RequestBody( | ||
required: true, | ||
content: [ | ||
new OAT\JsonContent(ref: BAO\Schemas\CalculatorSolveRequest::class), | ||
] | ||
))] | ||
#[BAO\SuccessfulResponse(content: [ | ||
new BAO\WrapObjectWithData(BAO\Schemas\CalculatorResult::class), | ||
])] | ||
#[BAO\NotAuthorizedResponse] | ||
#[BAO\NotFoundResponse] | ||
public function solve(Request $request, int $id): CalculatorResultResource | ||
{ | ||
$calculator = Calculator::with('blocks')->findOrFail($id); | ||
|
||
if ($request->user()->cannot('show', $calculator)) { | ||
abort(403); | ||
} | ||
|
||
$userInputs = CalculatorSolveRequest::fromArray($request->all()); | ||
$calculatorResult = $calculator->solve($userInputs); | ||
|
||
return new CalculatorResultResource($calculatorResult); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Kami\Cocktail\Http\Requests; | ||
|
||
use Illuminate\Foundation\Http\FormRequest; | ||
|
||
class CalculatorRequest extends FormRequest | ||
{ | ||
/** | ||
* Determine if the user is authorized to make this request. | ||
* | ||
* @return bool | ||
*/ | ||
public function authorize() | ||
{ | ||
return true; | ||
} | ||
|
||
/** | ||
* Get the validation rules that apply to the request. | ||
* | ||
* @return array<string, mixed> | ||
*/ | ||
public function rules() | ||
{ | ||
return [ | ||
'name' => 'required', | ||
]; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Kami\Cocktail\Http\Resources; | ||
|
||
use Illuminate\Http\Resources\Json\JsonResource; | ||
|
||
/** | ||
* @mixin \Kami\Cocktail\Models\CalculatorBlock | ||
*/ | ||
class CalculatorBlockResource extends JsonResource | ||
{ | ||
/** | ||
* Transform the resource into an array. | ||
* | ||
* @param \Illuminate\Http\Request $request | ||
* @return array<string, mixed> | ||
*/ | ||
public function toArray($request) | ||
{ | ||
return [ | ||
'id' => $this->id, | ||
'label' => $this->label, | ||
'variable_name' => $this->variable_name, | ||
'value' => $this->value, | ||
'sort' => $this->sort, | ||
'type' => $this->type->value, | ||
'description' => $this->description, | ||
'settings' => [ | ||
'suffix' => $this->settings->suffix ?? null, | ||
'prefix' => $this->settings->prefix ?? null, | ||
'decimal_places' => $this->settings->decimal_places ?? null, | ||
], | ||
]; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Kami\Cocktail\Http\Resources; | ||
|
||
use Illuminate\Http\Resources\Json\JsonResource; | ||
|
||
/** | ||
* @mixin \Kami\Cocktail\Models\Calculator | ||
*/ | ||
class CalculatorResource extends JsonResource | ||
{ | ||
/** | ||
* Transform the resource into an array. | ||
* | ||
* @param \Illuminate\Http\Request $request | ||
* @return array<string, mixed> | ||
*/ | ||
public function toArray($request) | ||
{ | ||
return [ | ||
'id' => $this->id, | ||
'name' => $this->name, | ||
'description' => $this->description, | ||
'blocks' => CalculatorBlockResource::collection($this->blocks), | ||
]; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Kami\Cocktail\Http\Resources; | ||
|
||
use Illuminate\Http\Resources\Json\JsonResource; | ||
|
||
/** | ||
* @mixin \Kami\Cocktail\OpenAPI\Schemas\CalculatorResult | ||
*/ | ||
class CalculatorResultResource extends JsonResource | ||
{ | ||
/** | ||
* Transform the resource into an array. | ||
* | ||
* @param \Illuminate\Http\Request $request | ||
* @return array<string, mixed> | ||
*/ | ||
public function toArray($request) | ||
{ | ||
return [ | ||
'inputs' => array_map('strval', $this->inputs), | ||
'results' => array_map('strval', $this->results), | ||
]; | ||
} | ||
} |
Oops, something went wrong.