From 1632a2e51f71812b75ed2ae1c398dd0cbe61a795 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Cort=C3=A9s?= Date: Sun, 2 May 2021 19:15:35 -0400 Subject: [PATCH] API de restaurante --- backend/README.md | 158 +++++++++++++++++- .../Controllers/RestaurantesController.php | 137 +++++++++++++++ .../Http/Controllers/UsuariosController.php | 9 +- backend/app/Models/Restaurante.php | 16 +- backend/app/Models/Usuario.php | 5 + backend/routes/web.php | 1 + 6 files changed, 313 insertions(+), 13 deletions(-) create mode 100644 backend/app/Http/Controllers/RestaurantesController.php diff --git a/backend/README.md b/backend/README.md index 2c82ef2..aa5ceb7 100644 --- a/backend/README.md +++ b/backend/README.md @@ -9,12 +9,13 @@ administrar sus restaurantes. Esta API tendrá los siguientes endpoints -| Funcionalidad | Endpoint | -| --------------- | ----------------- | -| Usuario | `/api/v1/users/` | -| Bodega | `/api/v1/bodega/` | -| Venta | `/api/v1/venta/` | -| Administración | `/api/v1/admin/` | +| Funcionalidad | Endpoint | +| --------------- | ----------------------- | +| Usuario | `/api/v1/users/` | +| Restaurante | `/api/v1/restaurantes/` | +| Bodega | `/api/v1/bodega/` | +| Venta | `/api/v1/venta/` | +| Administración | `/api/v1/admin/` | ## Autorización @@ -193,7 +194,7 @@ para el modelo. ### Actualizar -Para actualizar un usuario se debe enviar un `POST` a la +Para actualizar un usuario se debe enviar un `PUT` a la ruta `/api/v1/users/{id}` donde `{id}` es el ID del usuario a buscar, este ID puede ser el UUID del usuario o el ID entregado por Auth0, y en el cuerpo se debe indicar los campos a actualizar. @@ -355,3 +356,146 @@ ejemplo, donde se eliminó del restaurante `4e47a419-9398-47ff-82e9-b78851e71226 ] } ``` + +## Restaurantes + +La API de restaurantes permite manipular los restaurantes de la aplicacion, +donde las siguientes acciones estan disponibles + +### Obtener todos + +Para obtener la lista completa de restaurantes se debe enviar un `GET` a la +ruta `/api/v1/restaurantes`, estos datos seran paginados, por lo que +opcionalmente se recibe el parámetro `page` para definir la página a obtener y +el parámetro `per_page` para definir cuantos elementos obtener por página. + +La respuesta de la API tiene la siguiente forma + +```json +{ + "pagination": { + "per_page": 15, + "from": 1, + "to": 2, + "total": 2, + "current_page": 1, + "last_page": 1, + "links": { + "first": "http:\/\/localhost:8080\/api\/v1\/restaurantes?page=1&per_page=15", + "prev": null, + "current": "http:\/\/localhost:8080\/api\/v1\/restaurantes?page=1&per_page=15", + "next": null, + "last": "http:\/\/localhost:8080\/api\/v1\/restaurantes?page=1&per_page=15" + } + }, + "data": [ + { + "id": "eb41e807-24ef-4620-aa5e-3aa9cf920ddf", + "nombre": "Todo Rico Restaurant", + "created_at": "2021-05-01T04:46:11.593213Z", + "updated_at": "2021-05-01T04:46:11.593213Z", + "deleted_at": null + }, + { + "id": "e7d1ce9c-fed1-4a01-ab91-0069d92eeea3", + "nombre": "Confiteria Central", + "created_at": "2021-05-02T16:40:56.000000Z", + "updated_at": "2021-05-02T16:52:26.000000Z", + "deleted_at": null + } + ] +} +``` + +La respuesta contendrá una serie de datos indicando el estado de la paginación, +además de una serie de links indicando a donde llamar para obtener la primera, +anterior, actual, siguiente y última página. + +Estos links pueden ser null en caso que no sea posible utilizarlo, por ejemplo +si hay 3 páginas y la página actual es la 3, el link `next` será nulo, ya que no +hay una cuarta página. + +### Obtener Restaurante + +Para obtener un restaurante se debe hacer un `GET` a la +ruta `/api/v1/restaurantes/{id}` +donde `{id}` es el ID del restaurante a buscar. + +Si el ID de restaurante existe, la siguiente sera la respuesta de la API + +```json +{ + "id": "eb41e807-24ef-4620-aa5e-3aa9cf920ddf", + "nombre": "Todo Rico Restaurant", + "created_at": "2021-05-01T04:46:11.593213Z", + "updated_at": "2021-05-01T04:46:11.593213Z", + "deleted_at": null +} +``` + +En caso que el ID no exista, la siguiente sera la respuesta de error + +```json +{ + "error": "restaurant_not_found", + "message": "El restaurant con id eb41e807-24ef-4620-aa5e-3aa9cf920dde no existe" +} +``` + +### Crear + +Para crear un nuevo restaurant se debe enviar un `POST` a la +ruta `/api/v1/restaurantes` con un payload como el del siguiente ejemplo + +```json +{ + "nombre": "Unified Restaurant" +} +``` + +Esto creará un restaurante con nombre "Unified Restaurant" y la API responderá +con el usuario creado. + +```json +{ + "id": "eb41e807-24ef-4620-aa5e-3aa9cf920ddf", + "nombre": "Todo Rico Restaurant", + "created_at": "2021-05-01T04:46:11.593213Z", + "updated_at": "2021-05-01T04:46:11.593213Z", + "deleted_at": null +} +``` + +### Actualizar + +Para actualizar un restaurant se debe enviar un `PUT` a la +ruta `/api/v1/restaurantes/{id}` donde `{id}` es el id del restaurante a editar + +El siguiente payload va a cambiar el nombre del restaurante + +```json +{ + "nombre": "Unified Restaurant 2: Electric Boongaloo" +} +``` + +Una vez modificado el dato, la API responderá con el restaurant actualizado + +```json +{ + "id": "6a2855cc-cc04-4bc1-ac97-e8f632918303", + "nombre": "Unified Restaurant 2: Electric Boongaloo", + "created_at": "2021-05-02T17:13:01.000000Z", + "updated_at": "2021-05-02T23:13:10.000000Z", + "deleted_at": null +} +``` + +### Eliminar + +Para eliminar un restaurant se envía un `DELETE` a la +ruta `/api/v1/restaurantes/{id}` donde `{id}` es el ID del restaurante a +eliminar. + +Al eliminar un restaurant, solo se marca como eliminado y se mostrara en ninguna +otra llamada, además de esto todas sus asociaciones son dejadas tal cual. diff --git a/backend/app/Http/Controllers/RestaurantesController.php b/backend/app/Http/Controllers/RestaurantesController.php new file mode 100644 index 0000000..f716fe8 --- /dev/null +++ b/backend/app/Http/Controllers/RestaurantesController.php @@ -0,0 +1,137 @@ +paginate( + perPage: $request->input('per_page', 15), + page: $request->input('page', 1), + total: Restaurante::all()->count(), + route: 'restaurant.all', + ); + + return response()->json([ + 'pagination' => $paginate, + 'data' => array_values(Restaurante::all()->skip($paginate['from'] - 1)->take($paginate['per_page'])->all()) + ]); + } + + /** + * Obtiene un restaurante por su id + * @param $id + * @return JsonResponse + */ + public function get($id) { + $restaurante = Restaurante::findOrNull($id); + + if (!$restaurante) { + return response()->json([ + 'error' => 'restaurant_not_found', + 'message' => 'El restaurant con id ' . $id . ' no existe' + ], 404); + } + + return response()->json($restaurante); + } + + /** + * Crea un nuevo restaurant + * @param Request $request + * @return JsonResponse + * @throws ValidationException + */ + public function create(Request $request) { + $this->validate($request, [ + 'nombre' => 'required' + ]); + + if (!$request->user->canManageRestaurants()) { + return response()->json([ + 'error' => 'cant_manage_restaurants', + 'message' => 'El usuario ' . $request->user->id . ' no tiene permisos para manipular restaurantes' + ], 403); + } + + $restaurant = Restaurante::create([ + 'id' => Uuid::uuid4(), + 'nombre' => $request->input('nombre') + ]); + + return response()->json($restaurant, 201); + } + + /** + * Actualiza un restaurante + * @param Request $request + * @param $id + * @return JsonResponse + * @throws ValidationException + */ + public function update(Request $request, $id) { + $this->validate($request, [ + 'nombre' => 'required' + ]); + + if (!$request->user->canManageRestaurants()) { + return response()->json([ + 'error' => 'cant_manage_restaurants', + 'message' => 'El usuario ' . $request->user->id . ' no tiene permisos para manipular restaurantes' + ], 403); + } + + $restaurant = Restaurante::findOrNull($id); + if(!$restaurant) { + return response()->json([ + 'error' => 'not_found', + 'message' => 'El restaurante con id ' . $id . ' no existe' + ], 404); + } + + $restaurant->nombre = $request->input('nombre'); + $restaurant->save(); + + return response()->json($restaurant); + } + + /** + * Elimina un restaurante + * @param Request $request + * @param $id + * @return JsonResponse + * @throws ValidationException + */ + public function delete(Request $request, $id) { + if (!$request->user->canManageRestaurants()) { + return response()->json([ + 'error' => 'cant_manage_restaurants', + 'message' => 'El usuario ' . $request->user->id . ' no tiene permisos para manipular restaurantes' + ], 403); + } + + $restaurant = Restaurante::findOrNull($id); + if(!$restaurant) { + return response()->json([ + 'error' => 'not_found', + 'message' => 'El restaurante con id ' . $id . ' no existe' + ], 404); + } + + $restaurant->delete(); + + return response()->json($restaurant); + } +} diff --git a/backend/app/Http/Controllers/UsuariosController.php b/backend/app/Http/Controllers/UsuariosController.php index 0131f2c..8668951 100644 --- a/backend/app/Http/Controllers/UsuariosController.php +++ b/backend/app/Http/Controllers/UsuariosController.php @@ -8,7 +8,6 @@ use App\Services\Auth0Service; use App\Services\PaginatorService; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; -use Illuminate\Support\Facades\Log; use Illuminate\Validation\Rule; use Illuminate\Validation\ValidationException; use Ramsey\Uuid\Uuid; @@ -24,7 +23,7 @@ class UsuariosController extends Controller { $paginate = app(PaginatorService::class)->paginate( perPage: $request->input('per_page', 15), page: $request->input('page', 1), - count: Usuario::all()->count(), + total: Usuario::all()->count(), route: 'users.all', ); @@ -67,7 +66,7 @@ class UsuariosController extends Controller { 'restaurant' => 'required|exists:restaurantes,id', ]); - $restaurant = Restaurante::find($request->input('restaurant')); + $restaurant = Restaurante::findOrNull($request->input('restaurant')); $cantManageUsersOrRestaurant = $this->cantManageUsersOrRestaurant($request->user, $restaurant); if ($cantManageUsersOrRestaurant) { @@ -214,7 +213,7 @@ class UsuariosController extends Controller { ], 404); } - $restaurant = Restaurante::find($restaurant); + $restaurant = Restaurante::findOrNull($restaurant); if (!$restaurant) { return response()->json([ 'error' => 'not_found', @@ -257,7 +256,7 @@ class UsuariosController extends Controller { ], 404); } - $restaurant = Restaurante::find($restaurant); + $restaurant = Restaurante::findOrNull($restaurant); if (!$restaurant) { return response()->json([ 'error' => 'not_found', diff --git a/backend/app/Models/Restaurante.php b/backend/app/Models/Restaurante.php index 1caec93..7a44380 100644 --- a/backend/app/Models/Restaurante.php +++ b/backend/app/Models/Restaurante.php @@ -5,9 +5,12 @@ namespace App\Models; use App\Traits\UuidPrimaryKey; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\SoftDeletes; +use Illuminate\Database\QueryException; +use Illuminate\Support\Facades\Log; /** - * @method static find(mixed $restaurant) + * @method static create(array $array) + * @method static find($id) * @property mixed id */ class Restaurante extends Model { @@ -15,6 +18,17 @@ class Restaurante extends Model { protected $table = 'restaurantes'; + protected $fillable = ['id', 'nombre']; + + public static function findOrNull($id) { + try { + return Restaurante::find($id); + } catch (QueryException $ex) { + Log::warning('Se intento obtener un restaurante con un id invalido', ['id' => $id]); + return null; + } + } + public function usuarios() { return $this->belongsToMany(Usuario::class, 'usuarios_restaurantes', 'restaurante_id', 'usuario_id'); } diff --git a/backend/app/Models/Usuario.php b/backend/app/Models/Usuario.php index 1a5789d..4a239ad 100644 --- a/backend/app/Models/Usuario.php +++ b/backend/app/Models/Usuario.php @@ -51,6 +51,11 @@ class Usuario extends Model { } } + public function canManageRestaurants() { + if (in_array('global_admin', $this->roles)) return true; + return false; + } + /** * Valida que el usuario tiene permisos sobre otro usuario * diff --git a/backend/routes/web.php b/backend/routes/web.php index c4fef8f..2953881 100644 --- a/backend/routes/web.php +++ b/backend/routes/web.php @@ -36,4 +36,5 @@ $router->get('/', function () use ($router) { $router->group(['prefix' => 'api/v1', 'middleware' => ['auth', 'log_endpoint']], function () use ($router) { registerUserApi($router); + registerRestaurantApi($router); });