Skip to content
Snippets Groups Projects
Commit ce329bc8 authored by jorplaz's avatar jorplaz
Browse files

Merge branch '2-create-controllers' into 'develop'

Resolve "create-controllers"

See merge request !2
parents 1c37b8ba 09c2adb7
No related branches found
No related tags found
2 merge requests!3Develop,!2Resolve "create-controllers"
Showing
with 593 additions and 53 deletions
<p align="center"><a href="https://laravel.com" target="_blank"><img src="https://raw.githubusercontent.com/laravel/art/master/logo-lockup/5%20SVG/2%20CMYK/1%20Full%20Color/laravel-logolockup-cmyk-red.svg" width="400"></a></p> #Retobici Back End
<p align="center"> ## Despliegue Back End
<a href="https://travis-ci.org/laravel/framework"><img src="https://travis-ci.org/laravel/framework.svg" alt="Build Status"></a>
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/dt/laravel/framework" alt="Total Downloads"></a>
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/v/laravel/framework" alt="Latest Stable Version"></a>
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/l/laravel/framework" alt="License"></a>
</p>
## About Laravel A continuación se muestran los pasos a seguir para instalar e iniciar
del sistema Back End. Cabe destacar que estos pasos son los referentes
al entorno que se ha utilizado en el proyecto, en este caso se ha
utilizado el propio ordenador portátil como servidor, con un sistema
operativo macOS, por lo que en otro sistema operativo los comandos de
instalación serán diferentes. MacOS ofrece un sistema de paquetes
**[Homebrew](https://brew.sh/)** que facilita enormemente el proceso de
instalación y configuración de la gran mayoría de herramientas.
Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experience to be truly fulfilling. Laravel takes the pain out of development by easing common tasks used in many web projects, such as: ### Instalación PHP 8.0.8
- [Simple, fast routing engine](https://laravel.com/docs/routing). 1. Iniciar un emulador de terminal en cualquier directorio del sistema
- [Powerful dependency injection container](https://laravel.com/docs/container).
- Multiple back-ends for [session](https://laravel.com/docs/session) and [cache](https://laravel.com/docs/cache) storage.
- Expressive, intuitive [database ORM](https://laravel.com/docs/eloquent).
- Database agnostic [schema migrations](https://laravel.com/docs/migrations).
- [Robust background job processing](https://laravel.com/docs/queues).
- [Real-time event broadcasting](https://laravel.com/docs/broadcasting).
Laravel is accessible, powerful, and provides tools required for large, robust applications. 2. Ejecutar el comando `brew install php`
## Learning Laravel 3. Si el sistema no detecta automáticamente la instalación, se puede
cargar en el arranque del terminal de la siguiente manera
Laravel has the most extensive and thorough [documentation](https://laravel.com/docs) and video tutorial library of all modern web application frameworks, making it a breeze to get started with the framework. 1. Editar el contenido del fichero `.bashrc` o `.zshrc` dependiendo
de que lenguaje de bash utilices. Normalmente ubicado en el
directorio principal del usuario. Un comando para editar
`vim /.bashrc`
If you don't feel like reading, [Laracasts](https://laracasts.com) can help. Laracasts contains over 2000 video tutorials on a range of topics including Laravel, modern PHP, unit testing, and JavaScript. Boost your skills by digging into our comprehensive video library. 2. Exporta la ubicación de la instalación de PHP agregando la
siguiente línea `export PATH="/Applications/MAMP/bin/php/php8.0.8/bin:$PATH`.
## Laravel Sponsors ### Instalación PostgreSQL
We would like to extend our thanks to the following sponsors for funding Laravel development. If you are interested in becoming a sponsor, please visit the Laravel [Patreon page](https://patreon.com/taylorotwell). 1. Iniciar un emulador de terminal en cualquier directorio del sistema
### Premium Partners 2. Ejecutar el comando `brew install postgresql`
- **[Vehikl](https://vehikl.com/)** 3. Iniciar el servicio con `brew services start postgres`
- **[Tighten Co.](https://tighten.co)**
- **[Kirschbaum Development Group](https://kirschbaumdevelopment.com)**
- **[64 Robots](https://64robots.com)**
- **[Cubet Techno Labs](https://cubettech.com)**
- **[Cyber-Duck](https://cyber-duck.co.uk)**
- **[Many](https://www.many.co.uk)**
- **[Webdock, Fast VPS Hosting](https://www.webdock.io/en)**
- **[DevSquad](https://devsquad.com)**
- **[Curotec](https://www.curotec.com/services/technologies/laravel/)**
- **[OP.GG](https://op.gg)**
- **[WebReinvent](https://webreinvent.com/?utm_source=laravel&utm_medium=github&utm_campaign=patreon-sponsors)**
- **[Lendio](https://lendio.com)**
## Contributing 4. Entrar en la interfaz de comandos de postgresql con `psql postgres`
Thank you for considering contributing to the Laravel framework! The contribution guide can be found in the [Laravel documentation](https://laravel.com/docs/contributions). 5. Cambiar la contraseña del usuario que se vaya a usar, en este caso
root y de contraseña también root, es recomendable que para un
entorno de producción no se utilice ni el usuario root ni una
contraseña tan débil. El comando sería
`ALTER USER root WITH PASSWORD ’password’;`
## Code of Conduct 6. Crear la base de datos con el comando `create database retobici;`
In order to ensure that the Laravel community is welcoming to all, please review and abide by the [Code of Conduct](https://laravel.com/docs/contributions#code-of-conduct). ### Generar claves API Mapbox
## Security Vulnerabilities Para utilizar el sistema de mapas es necesaria una cuenta y generar las
claves para el uso del sistema. Una vez creada la cuenta, en la
dirección https://account.mapbox.com/ se pueden generar las dos claves, tanto la pública como la privada, que se
usarán más adelante en ambas partes del proyecto.
If you discover a security vulnerability within Laravel, please send an e-mail to Taylor Otwell via [taylor@laravel.com](mailto:taylor@laravel.com). All security vulnerabilities will be promptly addressed. ### Instalación Back End
## License El código se encuentra en este repositorio.
The Laravel framework is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT). 1. Si no está instalado el sistema de versiones git, el comando para
instalarlo en macOS `brew install git`.
2. Descargar o clonar el repositorio en el directorio deseado con el
comando\
`git clone https://gitlab.inf.uva.es/jorplaz/plazalazojorge_2022_backend.git`.
Ahora, con el código del repositorio descargado es necesario configurar
el entorno del proyecto:
1. Desde la carpeta raíz del proyecto copiar el fichero de entorno de
ejemplo con `cp .env.example .env`.
2. Agregar los contenidos al fichero .env
```
DB_CONNECTION=pgsql
DB_HOST=127.0.0.1
DB_PORT=5432
DB_DATABASE=retobici
DB_USERNAME=root
DB_PASSWORD=root
MAPBOX_TOKEN=clave pública generada en el paso anterior
```
3. Generar la clave de aplicación con el comando
`php artisan key:generate`
4. Instalar las dependencias del fichero `composer.yml` con el comando
`composer install`
Con la instalación y la configuración completada solo sería necesario
lanzar el servidor, para ello hay que tener en cuenta de que el proyecto
se ha desarrollado de manera local, entonces para que se comunique la
aplicación Android con el Back End, ambos tienen que estar en la misma
red WiFi.
1. Obtener la dirección IP del servidor en la red WiFi con el comando
`ifconfig`
2. Lanzar el servidor apuntando a la IP de la red WiFi obtenida en el
paso anterior\
`php artisan serv –host=192.168.65.9 –port=8000`
3. Migrar la base de datos para generar la estructura de las tablas y
poblar la base de datos de información con el comando
`php artisan migrate:fresh –seed`
...@@ -3,6 +3,10 @@ ...@@ -3,6 +3,10 @@
namespace App\Exceptions; namespace App\Exceptions;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler; use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Log;
use Throwable; use Throwable;
class Handler extends ExceptionHandler class Handler extends ExceptionHandler
...@@ -44,7 +48,21 @@ class Handler extends ExceptionHandler ...@@ -44,7 +48,21 @@ class Handler extends ExceptionHandler
public function register() public function register()
{ {
$this->reportable(function (Throwable $e) { $this->reportable(function (Throwable $e) {
// Log::error('exception: '.$e->getTraceAsString());
}); });
} }
/**
* @param Request $request
* @param Throwable $e
* @return Response|JsonResponse|\Symfony\Component\HttpFoundation\Response
* @throws Throwable
*/
public function render($request, Throwable $e): Response|JsonResponse|\Symfony\Component\HttpFoundation\Response
{
if ($e instanceof SactumAuthenticationException) {
return \response()->json('This process requires to be authenticated',401);
}
return parent::render($request, $e);
}
} }
<?php
namespace App\Exceptions;
use Exception;
use JetBrains\PhpStorm\Pure;
class SactumAuthenticationException extends Exception{}
<?php
namespace App\Http\Controllers;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Validator;
use Laravel\Sanctum\PersonalAccessToken;
class AuthController extends Controller
{
public function login(Request $request)
{
$validator = Validator::make($request->all(), [
'email' => 'required|string|email',
'password' => 'required|string|min:6'
]);
if ( $validator->fails() || !auth('api')->attempt($validator->validated()) ) {
return response()->json(['Invalid credentials'], 401);
}
return response()->json([
'token' => auth('api')->user()->createToken('API Token')->plainTextToken,
'user' => auth('api')->user()
]);
}
public function logout(Request $request)
{
$user = UserController::getUserByToken($request);
if(1 != $user->tokens()->delete()){
return "false";
}
return "true";
}
}
\ No newline at end of file
<?php
namespace App\Http\Controllers;
use App\Models\Bike;
use Illuminate\Http\Request;
class BikeController extends Controller
{
public function unlockBike(Bike $bike){
return true;
}
public function reserveBike(Bike $bike){
return true;
}
}
<?php
namespace App\Http\Controllers;
use App\Models\Stop;
use Illuminate\Support\Facades\Http;
class MapboxApiClient extends Http
{
private String $url;
public function __construct(Stop $init, Stop $end)
{
$lng1 = $init->lng;
$lng2 = $end->lng;
$lat1 = $init->lat;
$lat2 = $end->lat;
$coordinates = $lng1.",".$lat1.";".$lng2.",".$lat2;
$token = env('MAPBOX_TOKEN', null);
$this->url = "https://api.mapbox.com/directions/v5/mapbox/cycling/${coordinates}?alternatives=false&geometries=geojson&overview=full&steps=false&access_token=".$token;
}
public function buildRequest(){
return $this->url;
}
}
\ No newline at end of file
<?php
namespace App\Http\Controllers;
use App\Http\Resources\RewardResource;
use App\Http\Resources\RewardResourceObtained;
use App\Models\Reward;
use App\Models\User;
use Illuminate\Http\Request;
class RewardController extends Controller
{
public function getAllRewards(){
return RewardResource::collection(Reward::all());
}
public function getNotRedeemedRewards(Request $request){
$user = UserController::getUserByToken($request);
$userR = $user->rewards()->get(['user_reward.reward_id AS result'])->pluck('result');
return RewardResource::collection(Reward::all()->whereNotIn('id',$userR));
}
public function getUserRewards(Request $request){
$user = UserController::getUserByToken($request);
return RewardResourceObtained::collection($user->rewards()->orderByPivot('created_at', 'desc')->get());
}
public function obtainReward(Request $request, Reward $reward){
$user = UserController::getUserByToken($request);
if ($this->checkReward($user,$reward)){
$reward->redeemed += 1;
$reward->users()->attach($user);
$user->points -= $reward->points;
$reward->save();
$user->save();
return new RewardResourceObtained($reward);
}
return response()->json("Unable to redeem the reward", 500);
}
private function checkReward(User $user, Reward $reward){
if ($reward->total_available <= $reward->redeemed){
return false;
}
if ($user->rewards()->find($reward)){
return false;
}
if ($user->points < $reward->points){
return false;
}
return true;
}
}
<?php
namespace App\Http\Controllers;
use App\Http\Resources\RouteResource;
use App\Models\Bike;
use App\Models\ElectricBike;
use App\Models\Route;
use App\Models\Stop;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;
use PhpParser\Node\Expr\Cast\Int_;
class RouteController extends Controller
{
public function createRoute(Request $request, Bike $bike){
$user = UserController::getUserByToken($request);
$route = new Route;
$route->user_id = $user->id;
$route->initial_stop_id = $bike->stop()->first()->id;
$route->bike_id = $bike->id;
$route->save();
//Remove any user reservation
$reservation = $user->reservations()->first();
$reservation?->delete();
//Free the bike from the Stop
$bike->stop_id = null;
$bike->save();
return new RouteResource($route);
}
public function finishRoute(Request $request){
$route = Route::find($request->id);
if($request->missing(['duration', 'final_stop'])){
return false;
}
$initial_stop = Stop::find($route->initial_stop_id);
$final_stop = Stop::find($request->final_stop);
$mapboxClient = new MapboxApiClient($initial_stop,$final_stop);
$url = $mapboxClient->buildRequest();
$response = Http::get($url);
$mapbox_response = $response->json();
$distance = $response->json('routes')[0]['distance'];
$estimated_duration = $response->json('routes')[0]['duration'];
$route->final_stop_id = intval($request->final_stop);
$route->duration = intval($request->duration);
$route->mapbox_response = $mapbox_response;
$route->distance = intval($distance);
$route->estimated_duration = intval($estimated_duration);
$route->points = $this->calculatePoints($route);
$route->save();
$user = UserController::getUserByToken($request);
$user->points += $route->points;
$user->save();
$bike = $route->bike()->first();
$bike->stop_id = $route->final_stop_id;
$bike->save();
return new RouteResource($route);
}
public static function calculatePoints($route): Int{
if ($route->distance<=0) {
return 0;
}
$points = 50+(($route->distance*10)/100)-(($route->duration*5)/60);
if ($points<0) {
return 0;
}
else {
return $points;
}
}
}
<?php
namespace App\Http\Controllers;
use App\Http\Resources\BikeResource;
use App\Http\Resources\StopResource;
use App\Models\Bike;
use App\Models\ElectricBike;
use App\Models\Reservation;
use App\Models\Stop;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class StopController extends Controller
{
public function getAllStops(){
return StopResource::collection(Stop::all());
}
public function unlockBike(Request $request, Bike $bike){
$user = UserController::getUserByToken($request);
$stop = $bike->stop()->first();
$type = $bike->bikeable_type;
$bikes = $stop->bikes()->get()->where('bikeable_type', '=', $type);
$reservation = $user->reservations()->first();
if ($type=='App\Models\ElectricBike'){
$typable = 'electric';
}else{
$typable = 'pedal';
}
if (($reservation!=null && $reservation->bike_type==$typable) || $stop->check_availability_bikes($type)){
return new BikeResource($bikes->first());
}else{
return response()->json("No bikes available", 500);
}
}
public function lockBike(Stop $stop){
if ($stop->total_spaces>0){
return new StopResource($stop);
}
else{
return "No space available";
}
}
public function reserveBike(Request $request, Stop $stop, String $type){
if ($stop->check_availability_bikes($type)){
$user = UserController::getUserByToken($request);
$reservation = new Reservation();
$reservation->user_id = $user->id;
$reservation->stop_id = $stop->id;
$reservation->bike_type = $type;
$reservation->save();
return new StopResource($stop);
}
else{
return response()->json("No bikes available for reservation", 500);
}
}
}
<?php
namespace App\Http\Controllers;
use App\Models\User;
use Illuminate\Http\Request;
use Laravel\Sanctum\PersonalAccessToken;
class UserController extends Controller
{
public static function getUserByToken(Request $request):User|null
{
$token = PersonalAccessToken::findToken($request->bearerToken());
return ($token != null) ? $token->tokenable : null;
}
}
...@@ -2,20 +2,16 @@ ...@@ -2,20 +2,16 @@
namespace App\Http\Middleware; namespace App\Http\Middleware;
use App\Exceptions\SactumAuthenticationException;
use Illuminate\Auth\Middleware\Authenticate as Middleware; use Illuminate\Auth\Middleware\Authenticate as Middleware;
class Authenticate extends Middleware class Authenticate extends Middleware
{ {
/** /**
* Get the path the user should be redirected to when they are not authenticated. * @throws SactumAuthenticationException
*
* @param \Illuminate\Http\Request $request
* @return string|null
*/ */
protected function redirectTo($request) protected function unauthenticated($request, array $guards)
{ {
if (! $request->expectsJson()) { throw new SactumAuthenticationException("To access this endpoint you need to be authenticated",401);
return route('login');
}
} }
} }
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class BikeResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
*/
public function toArray($request)
{
if ($this->bikeable_type == "App\\Models\\ElectricBike"){
$battery = $this->bikeable->battery;
$resource = [
'bike_id' => $this->id,
'unlocked' => $this->unlocked,
'battery' => $battery
];
}
else{
$resource = [
'bike_id' => $this->id,
'unlocked' => $this->unlocked,
];
}
return $resource;
}
}
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class RewardResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
*/
public function toArray($request)
{
return [
"id"=> $this->id,
"title"=> $this->name,
"description"=> $this->description,
"points"=> $this->points,
"image" => $this->image,
];
}
}
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class RewardResourceObtained extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
*/
public function toArray($request)
{
return [
"id"=> $this->id,
"title"=> $this->name,
"description"=> $this->description,
"points"=> $this->points,
"image" => $this->image,
"obtained" => true,
];
}
}
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class RouteResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
*/
public function toArray($request)
{
return [
'id' => $this->id,
'user_id' => $this->user_id,
'bike' => new BikeResource($this->bike()->first()),
'initial_stop_id' => $this->initial_stop_id,
'final_stop_id' => $this->final_stop_id,
'distance' => $this->distance,
'duration' => $this->duration,
'points' => $this->points,
];
}
}
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class StopResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
*/
public function toArray($request)
{
return [
'id' => $this->id,
'lng' => $this->lng,
'lat' => $this->lat,
'address' => $this->address,
'totalSpaces' => $this->total_spaces,
'reserved_pedal_bikes' => $this->reserved_pedal_bikes(),
'reserved_electric_bikes' => $this->reserved_electric_bikes(),
'bikes' => BikeResource::collection($this->bikes()->get()),
];
}
}
...@@ -6,17 +6,25 @@ use Illuminate\Database\Eloquent\Factories\HasFactory; ...@@ -6,17 +6,25 @@ use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\HasMany;
use Nanigans\SingleTableInheritance\SingleTableInheritanceTrait;
/** /**
* @method static create(array $array) * @method static create(array $array)
* @method static find(int $int)
* @property mixed $id
* @property mixed $bikeable_type
* @property mixed|null $stop_id
*/ */
class Bike extends Model class Bike extends Model
{ {
use HasFactory; use HasFactory;
protected $table = "bikes";
protected $fillable = [ protected $fillable = [
'stop_id', 'stop_id',
'unlocked', 'unlocked',
'type'
]; ];
public function stop(): BelongsTo{ public function stop(): BelongsTo{
...@@ -26,4 +34,8 @@ class Bike extends Model ...@@ -26,4 +34,8 @@ class Bike extends Model
public function routes(): HasMany{ public function routes(): HasMany{
return $this->hasMany(Route::class); return $this->hasMany(Route::class);
} }
public function bikeable(){
return $this->morphTo();
}
} }
...@@ -14,4 +14,8 @@ class ElectricBike extends Bike ...@@ -14,4 +14,8 @@ class ElectricBike extends Bike
'id', 'id',
'battery', 'battery',
]; ];
public function bike(){
return $this->morphOne(Bike::class, 'bikeable');
}
} }
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
/**
* @property mixed $user_id
* @property mixed $stop_id
* @property mixed|String $bike_type
*/
class Reservation extends Model
{
use HasFactory;
public function user(): BelongsTo{
return $this->belongsTo(Route::class);
}
public function stop(): BelongsTo{
return $this->belongsTo(Stop::class);
}
}
...@@ -8,6 +8,9 @@ use Illuminate\Database\Eloquent\Relations\BelongsToMany; ...@@ -8,6 +8,9 @@ use Illuminate\Database\Eloquent\Relations\BelongsToMany;
/** /**
* @method static create(array $array) * @method static create(array $array)
* @property mixed $redeemed
* @property mixed $total_available
* @property mixed $points
*/ */
class Reward extends Model class Reward extends Model
{ {
...@@ -18,6 +21,10 @@ class Reward extends Model ...@@ -18,6 +21,10 @@ class Reward extends Model
'description', 'description',
'user_id', 'user_id',
'reward_id', 'reward_id',
'points',
'total_available',
'image',
'redeemed',
]; ];
public function users(): BelongsToMany{ public function users(): BelongsToMany{
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment