diff --git a/backend/README.md b/backend/README.md index 5809976..8033f2c 100644 --- a/backend/README.md +++ b/backend/README.md @@ -3,12 +3,242 @@ Unified Restaurant es un servicio web que permitirá a sus usuarios operar y administrar sus restaurantes. -## Documentación +# Documentación 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/` | + +## Errores + +En caso que se presente algún error la API siempre responderá con un mensaje de +la siguiente forma + +```json +{ + "error": "error_code", + "message": "Mensaje explicativo del error en español" +} +``` + +Ahora, si el error lo presento Auth0, el campo de `error` siempre empezara el +código con `auth0_`, es util saber que el error es enviado desde Auth0 porque +sus mensajes de error están en ingles y si se deben mostrar al usuario se +deberán traducir manualmente + +## Usuario + +La API de usuario permite manipular a los usuarios de la aplicación, las +siguientes acciones están disponibles + +### Obtener todos + +Para obtener la lista completa de usuarios se debe enviar un `GET` a la +ruta `/api/v1/user`, estos datos serán 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/users?page=1&per_page=15", + "prev": null, + "current": "http://localhost:8080/api/v1/users?page=1&per_page=15", + "next": null, + "last": "http://localhost:8080/api/v1/users?page=1&per_page=15" + } + }, + "data": [ + // listado de usuarios + ] +} +``` + +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 Usuario + +Para obtener un usuario se debe hacer un `GET` 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, esto puede ser util si el frontend tiene +solamente acceso al ID entregado por auth0. + +Si el ID de usuario existe, la siguiente sera la respuesta de la API + +```json +{ + "id": "4014fd8d-26fd-4ce8-bdaa-99b8a325ee92", + "auth0_id": "123456", + "nombre": "Mesero", + "created_at": "2021-04-26T16:37:59.998642Z", + "updated_at": "2021-04-26T16:37:59.998642Z", + "deleted_at": null, + "roles": [ + "mesero" + ], + "restaurantes": [ + { + "id": "63f62e17-e011-4f6f-8c15-5eb65a5014be", + "nombre": "Todo Rico Restaurant", + "created_at": "2021-04-26T16:37:59.181869Z", + "updated_at": "2021-04-26T16:37:59.181869Z", + "deleted_at": null, + "pivot": { + "usuario_id": "4014fd8d-26fd-4ce8-bdaa-99b8a325ee92", + "restaurante_id": "63f62e17-e011-4f6f-8c15-5eb65a5014be" + } + } + ] +} +``` + +En caso que el usuario no exista se retornara el siguiente mensaje de error + +```json +{ + "error": "user_not_found", + "message": "El usuario con id o auth0_id {id} no existe" +} +``` + +### Crear + +Para crear un nuevo usuario se debe enviar un `POST` a la ruta `/api/v1/user` +con un payload como el del siguiente ejemplo + +```json +{ + "nombre": "John Doe", + "email": "john@doe.com", + "username": "johndoe", + "password": "superPasswordWith123NumbersAnd----Symbols", + "roles": [ + "admin", + "recaudador", + "mesero", + "productor" + ], + "restaurant": "63f62e17-e011-4f6f-8c15-5eb65a5014be" +} +``` + +Esto creará el usuario John Doe localmente y en auth0 por lo cual él podrá +entrar con el email y contraseña indicados + +Una vez creado, la API responderá con el usuario creado, no contendrá `username` +, +`email` ni `password` ya que estos valores los utiliza Auth0 y no son relevantes +para el modelo. + +```json +{ + "usuario": { + "id": "6430c9ac-6bce-4e23-8421-28bce08101d4", + "auth0_id": "auth0|608ba7866c9b520074d687d9", + "nombre": "John Doe", + "roles": [ + "admin", + "recaudador", + "mesero", + "productor" + ], + "updated_at": "2021-04-30T06:45:22.000000Z", + "created_at": "2021-04-30T06:45:22.000000Z", + "restaurantes": [ + { + "id": "63f62e17-e011-4f6f-8c15-5eb65a5014be", + "nombre": "Todo Rico Restaurant", + "created_at": "2021-04-26T16:37:59.181869Z", + "updated_at": "2021-04-26T16:37:59.181869Z", + "deleted_at": null, + "pivot": { + "usuario_id": "4014fd8d-26fd-4ce8-bdaa-99b8a325ee92", + "restaurante_id": "63f62e17-e011-4f6f-8c15-5eb65a5014be" + } + } + ] + } +} +``` + +### Actualizar + +Para actualizar un usuario se debe enviar un `POST` a la +ruta `/api/v1/users/{id}` y en el cuerpo se debe indicar los campos a +actualizar. + +Por ejemplo para actualizar el nombre del usuario se envía el siguiente payload + +```json +{ + "nombre": "Jhon 2" +} +``` + +O si se quieren cambiar sus roles, se envía el siguiente payload + +```json +{ + "roles": [ + "admin", + "recaudador" + ] +} +``` + +Una vez se modifiquen los datos del usuario, la API responderá con el usuario +actualizado + +```json +{ + "id": "340c8e54-9a15-4bd2-9b59-108f267d5872", + "auth0_id": "auth0|608ca16fcfc3df0068fea6a4", + "nombre": "Jhon 2", + "created_at": "2021-04-30T18:31:44.000000Z", + "updated_at": "2021-05-01T00:31:52.000000Z", + "deleted_at": null, + "roles": [ + "admin", + "recaudador" + ], + "restaurantes": [ + { + "id": "63f62e17-e011-4f6f-8c15-5eb65a5014be", + "nombre": "Todo Rico Restaurant", + "created_at": "2021-04-26T16:37:59.181869Z", + "updated_at": "2021-04-26T16:37:59.181869Z", + "deleted_at": null, + "pivot": { + "usuario_id": "340c8e54-9a15-4bd2-9b59-108f267d5872", + "restaurante_id": "63f62e17-e011-4f6f-8c15-5eb65a5014be" + } + } + ] +} +``` + +Ahora existe la posibilidad que se quieran actualizar multiples casos a la vez, +si esto es asi, hay que tomar en cuenta las limitaciones impuestas por Auth0, +donde ciertos campos no se pueden cambiar al mismo tiempo, para más detalles, +ver +la [documentación de Auth0](https://auth0.com/docs/api/management/v2#!/Users/patch_users_by_id) diff --git a/backend/app/Http/Controllers/UsuariosController.php b/backend/app/Http/Controllers/UsuariosController.php index 87c85e1..58864cd 100644 --- a/backend/app/Http/Controllers/UsuariosController.php +++ b/backend/app/Http/Controllers/UsuariosController.php @@ -32,7 +32,7 @@ class UsuariosController extends Controller { return response()->json([ 'pagination' => $paginate, - 'data' => array_values(Usuario::all()->skip($paginate['from'] - 1 )->take($paginate['per_page'])->all()) + 'data' => array_values(Usuario::with('restaurantes')->skip($paginate['from'] - 1 )->take($paginate['per_page'])->get()->all()) ]); } diff --git a/backend/app/Models/Usuario.php b/backend/app/Models/Usuario.php index 2229e1d..1a5789d 100644 --- a/backend/app/Models/Usuario.php +++ b/backend/app/Models/Usuario.php @@ -6,8 +6,8 @@ use App\Services\Auth0Service; use App\Traits\UuidPrimaryKey; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\SoftDeletes; -use phpDocumentor\Reflection\Types\Boolean; -use Ramsey\Uuid\Uuid; +use Illuminate\Database\QueryException; +use Illuminate\Support\Facades\Log; /** * Class Usuario @@ -40,9 +40,14 @@ class Usuario extends Model { */ public static function findByIdOrAuth0Id($id) { if (str_starts_with($id, 'auth0')) { - return Usuario::where('auth0_id', urldecode($id))->first(); + return Usuario::where('auth0_id', urldecode($id))->with('restaurantes')->first(); } else { - return Usuario::where('id', $id)->first(); + try { + return Usuario::where('id', $id)->with('restaurantes')->first(); + } catch (QueryException $ex) { + Log::warning('Se intento obtener un usuario con un id invalido', ['id' => $id]); + return null; + } } } diff --git a/backend/routes/web.php b/backend/routes/web.php index b0e2174..0ea20cf 100644 --- a/backend/routes/web.php +++ b/backend/routes/web.php @@ -2,6 +2,21 @@ use Laravel\Lumen\Routing\Router; +function register_user_api($router) { + $router->group(['prefix' => '/users'], function () use ($router) { + // Rutas del recurso + $router->get('/', ['as' => 'users.all', 'uses' => 'UsuariosController@all']); + $router->get('/{id}', ['as' => 'users.get', 'uses' => 'UsuariosController@get']); + $router->post('/', ['as' => 'users.create', 'uses' => 'UsuariosController@create']); + $router->put('/{id}', ['as' => 'users.update', 'uses' => 'UsuariosController@update']); + $router->delete('/{id}', ['as' => 'users.delete', 'uses' => 'UsuariosController@delete']); + + // Rutas de acciones + $router->put('/{id}/restaurantes', ['as' => 'users.add_restaurante', 'uses' => 'UsuariosController@addRestaurante']); + $router->delete('/{id}/restaurantes', ['as' => 'users.remove_restaurante', 'uses' => 'UsuariosController@removeRestaurante']); + }); +} + /** @var Router $router */ $router->get('/', function () use ($router) { @@ -9,11 +24,5 @@ $router->get('/', function () use ($router) { }); $router->group(['prefix' => 'api/v1', 'middleware' => ['auth', 'log_endpoint']], function () use ($router) { - $router->group(['prefix' => '/users'], function () use ($router) { - $router->get('/', ['as' => 'users.all', 'uses' => 'UsuariosController@all']); - $router->get('/{id}', ['as' => 'users.get', 'uses' => 'UsuariosController@get']); - $router->post('/', ['as' => 'users.create', 'uses' => 'UsuariosController@create']); - $router->put('/{id}', ['as' => 'users.update', 'uses' => 'UsuariosController@update']); - $router->delete('/{id}', ['as' => 'users.delete', 'uses' => 'UsuariosController@delete']); - }); + register_user_api($router); });