Merge pull request #306 from nabeelio/issue-297/search-options

Add more search criteria/dev environment via docker-compose #297
This commit is contained in:
Nabeel Shahzad
2019-05-11 14:47:37 -05:00
committed by GitHub
22 changed files with 326 additions and 59 deletions

View File

@@ -55,6 +55,7 @@ if [ "$TRAVIS" = "true" ]; then
.sass-cache .sass-cache
.idea .idea
.travis .travis
docker
tests tests
_ide_helper.php _ide_helper.php
.dpl .dpl
@@ -64,6 +65,7 @@ if [ "$TRAVIS" = "true" ]; then
.styleci.yml .styleci.yml
env.php env.php
config.php config.php
docker-compose.yml
Makefile Makefile
phpunit.xml phpunit.xml
phpvms.iml phpvms.iml

View File

@@ -52,7 +52,7 @@ update: build
@echo "Done!" @echo "Done!"
.PHONY: reset .PHONY: reset
reset: cleanapp/Models/Traits/JournalTrait.php reset: clean
@php $(COMPOSER) dump-autoload @php $(COMPOSER) dump-autoload
@make reload-db @make reload-db

View File

@@ -1,5 +1,5 @@
dnsmasq: /usr/local/sbin/dnsmasq --keep-in-foreground #dnsmasq: /usr/local/sbin/dnsmasq --keep-in-foreground
php-fpm: /usr/local/sbin/php-fpm --nodaemonize php-fpm: /usr/local/sbin/php-fpm --nodaemonize
nginx: /usr/local/bin/nginx -g 'daemon off;' nginx: /usr/local/bin/nginx -g 'daemon off;'
#mysql: /usr/local/bin/mysqld mysql: docker-compose --file ~/docker/mysql/docker-compose.yml up
#mailhog: /usr/local/bin/mailhog #mailhog: /usr/local/bin/mailhog

View File

@@ -2,16 +2,15 @@
[![Build Status](https://travis-ci.org/nabeelio/phpvms.svg)](https://travis-ci.org/nabeelio/phpvms) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/d668bebb0a3c46bda381af16ce3d9450)](https://www.codacy.com/app/nabeelio/phpvms?utm_source=github.com&utm_medium=referral&utm_content=nabeelio/phpvms&utm_campaign=Badge_Grade) [![Latest Stable Version](https://poser.pugx.org/nabeel/phpvms/v/stable)](https://packagist.org/packages/nabeel/phpvms) ![StyleCI](https://github.styleci.io/repos/93688482/shield?branch=dev) [![License](https://poser.pugx.org/nabeel/phpvms/license)](https://packagist.org/packages/nabeel/phpvms) [![Build Status](https://travis-ci.org/nabeelio/phpvms.svg)](https://travis-ci.org/nabeelio/phpvms) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/d668bebb0a3c46bda381af16ce3d9450)](https://www.codacy.com/app/nabeelio/phpvms?utm_source=github.com&utm_medium=referral&utm_content=nabeelio/phpvms&utm_campaign=Badge_Grade) [![Latest Stable Version](https://poser.pugx.org/nabeel/phpvms/v/stable)](https://packagist.org/packages/nabeel/phpvms) ![StyleCI](https://github.styleci.io/repos/93688482/shield?branch=dev) [![License](https://poser.pugx.org/nabeel/phpvms/license)](https://packagist.org/packages/nabeel/phpvms)
The next phpvms version built on the laravel framework. work in progress. If you're looking for The next phpvms version built on the laravel framework. work in progress. The latest documentation, with installation instructions is available
the old, phpVMS classic, it's [available here](https://github.com/nabeelio/phpvms_v2). [on the phpVMS documentation](http://docs.phpvms.net/) page.
# installation # installation
A full distribution, with all of the composer dependencies, is available at this A full distribution, with all of the composer dependencies, is available at this
[GitHub Releases](https://github.com/nabeelio/phpvms/releases) link. [GitHub Releases](https://github.com/nabeelio/phpvms/releases) link.
The latest documentation, with installation instructions is available
[on the phpVMS documentation](http://docs.phpvms.net/) page.
## Requirements ## Requirements
@@ -30,6 +29,22 @@ The latest documentation, with installation instructions is available
## Installer ## Installer
1. Upload to your server 1. Upload to your server
2. Visit the site, and follow the link to the installer 1. Visit the site, and follow the link to the installer
[View installation details](http://docs.phpvms.net/setup/installation) [View installation details](http://docs.phpvms.net/setup/installation)
# development environment
A full development environment can be brought up using Docker:
```bash
composer install
npm install
docker-compose up
```
Then go to `http://localhost`. If you're using dnsmasq, the `app` container is listening on `phpvms.test`, or you can add to your `/etc/hosts` file:
```
127.0.0.1 phpvms.test
```

View File

@@ -22,7 +22,7 @@ $factory->define(App\Models\Flight::class, function (Faker $faker) {
'alt_airport_id' => function () { 'alt_airport_id' => function () {
return factory(App\Models\Airport::class)->create()->id; return factory(App\Models\Airport::class)->create()->id;
}, },
'distance' => $faker->numberBetween(0, 3000), 'distance' => $faker->numberBetween(0, 1000),
'route' => null, 'route' => null,
'level' => 0, 'level' => 0,
'dpt_time' => $faker->time(), 'dpt_time' => $faker->time(),
@@ -35,7 +35,7 @@ $factory->define(App\Models\Flight::class, function (Faker $faker) {
'start_date' => null, 'start_date' => null,
'end_date' => null, 'end_date' => null,
'created_at' => $faker->dateTimeBetween('-1 week', 'now'), 'created_at' => $faker->dateTimeBetween('-1 week', 'now'),
'updated_at' => function (array $flight) { 'updated_at' => static function (array $flight) {
return $flight['created_at']; return $flight['created_at'];
}, },
]; ];

View File

@@ -89,31 +89,37 @@ class FlightController extends Controller
*/ */
public function search(Request $request) public function search(Request $request)
{ {
$user = Auth::user(); $where = [
'active' => true,
try { 'visible' => true,
$where = [ ];
'active' => true,
'visible' => true,
];
// Allow the option to bypass some of these restrictions for the searches
if (!$request->filled('ignore_restrictions')
|| $request->get('ignore_restrictions') === '0'
) {
if (setting('pilots.restrict_to_company')) { if (setting('pilots.restrict_to_company')) {
$where['airline_id'] = Auth::user()->airline_id; $where['airline_id'] = Auth::user()->airline_id;
} }
if (setting('pilots.only_flights_from_current')) { if (setting('pilots.only_flights_from_current')) {
$where['dpt_airport_id'] = Auth::user()->curr_airport_id; $where['dpt_airport_id'] = Auth::user()->curr_airport_id;
} }
}
try {
$this->flightRepo->resetCriteria();
$this->flightRepo->searchCriteria($request); $this->flightRepo->searchCriteria($request);
$this->flightRepo->pushCriteria(new RequestCriteria($request));
$this->flightRepo->pushCriteria(new WhereCriteria($request, $where)); $this->flightRepo->pushCriteria(new WhereCriteria($request, $where));
$this->flightRepo->pushCriteria(new RequestCriteria($request));
$flights = $this->flightRepo->paginate(); $flights = $this->flightRepo->paginate();
} catch (RepositoryException $e) { } catch (RepositoryException $e) {
return response($e, 503); return response($e, 503);
} }
foreach ($flights as $flight) { foreach ($flights as $flight) {
$this->flightSvc->filterSubfleets($user, $flight); $this->flightSvc->filterSubfleets(Auth::user(), $flight);
} }
return FlightResource::collection($flights); return FlightResource::collection($flights);

View File

@@ -13,6 +13,7 @@ use Flash;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
use Log; use Log;
use Prettus\Repository\Criteria\RequestCriteria;
use Prettus\Repository\Exceptions\RepositoryException; use Prettus\Repository\Exceptions\RepositoryException;
/** /**
@@ -68,6 +69,7 @@ class FlightController extends Controller
try { try {
$this->flightRepo->pushCriteria(new WhereCriteria($request, $where)); $this->flightRepo->pushCriteria(new WhereCriteria($request, $where));
$this->flightRepo->pushCriteria(new RequestCriteria($request));
} catch (RepositoryException $e) { } catch (RepositoryException $e) {
Log::emergency($e); Log::emergency($e);
} }
@@ -137,6 +139,8 @@ class FlightController extends Controller
$where['dpt_airport_id'] = Auth::user()->curr_airport_id; $where['dpt_airport_id'] = Auth::user()->curr_airport_id;
} }
$this->flightRepo->resetCriteria();
try { try {
$this->flightRepo->pushCriteria(new WhereCriteria($request, $where)); $this->flightRepo->pushCriteria(new WhereCriteria($request, $where));
} catch (RepositoryException $e) { } catch (RepositoryException $e) {

View File

@@ -5,6 +5,7 @@ namespace App\Http\Controllers\Frontend;
use App\Interfaces\Controller; use App\Interfaces\Controller;
use App\Models\User; use App\Models\User;
use Illuminate\Database\QueryException; use Illuminate\Database\QueryException;
use Log;
/** /**
* Class HomeController * Class HomeController
@@ -18,10 +19,21 @@ class HomeController extends Controller
{ {
try { try {
$users = User::orderBy('created_at', 'desc')->take(4)->get(); $users = User::orderBy('created_at', 'desc')->take(4)->get();
debug($users);
} catch (\PDOException $e) {
Log::emergency($e);
return view('system/errors/database_error', [
'error' => $e->getMessage(),
]);
} catch (QueryException $e) { } catch (QueryException $e) {
return view('system/errors/not_installed'); return view('system/errors/not_installed');
} }
// No users
if (!$users) {
return view('system/errors/not_installed');
}
return view('home', [ return view('home', [
'users' => $users, 'users' => $users,
]); ]);

View File

@@ -18,6 +18,12 @@ class WhereCriteria implements CriteriaInterface
protected $request; protected $request;
protected $where; protected $where;
/**
* Create a new Where search.
*
* @param $request
* @param $where
*/
public function __construct($request, $where) public function __construct($request, $where)
{ {
$this->request = $request; $this->request = $request;

View File

@@ -18,15 +18,16 @@ class FlightRepository extends Repository implements CacheableInterface
protected $fieldSearchable = [ protected $fieldSearchable = [
'arr_airport_id', 'arr_airport_id',
'distance',
'dpt_airport_id', 'dpt_airport_id',
'flight_number' => 'like', 'flight_number' => 'like',
'flight_code' => 'like', 'route_code' => 'like',
'flight_leg' => 'like', 'route_leg' => 'like',
'route' => 'like', 'route' => 'like',
'notes' => 'like', 'notes' => 'like',
]; ];
public function model() public function model(): string
{ {
return Flight::class; return Flight::class;
} }
@@ -70,7 +71,7 @@ class FlightRepository extends Repository implements CacheableInterface
* *
* @return $this * @return $this
*/ */
public function searchCriteria(Request $request, bool $only_active = true) public function searchCriteria(Request $request, bool $only_active = true): self
{ {
$where = []; $where = [];
@@ -103,6 +104,16 @@ class FlightRepository extends Repository implements CacheableInterface
$where['arr_airport_id'] = $request->arr_icao; $where['arr_airport_id'] = $request->arr_icao;
} }
// Distance, greater than
if ($request->filled('dgt')) {
$where[] = ['distance', '>=', $request->dgt];
}
// Distance, less than
if ($request->filled('dlt')) {
$where[] = ['distance', '<=', $request->dlt];
}
$this->pushCriteria(new WhereCriteria($request, $where)); $this->pushCriteria(new WhereCriteria($request, $where));
return $this; return $this;

View File

@@ -1,5 +1,8 @@
<?php <?php
use App\Exceptions\SettingNotFound;
use Illuminate\Contracts\View\Factory;
if (!function_exists('in_mask')) { if (!function_exists('in_mask')) {
/** /**
* Return true/false if a value exists in a mask * Return true/false if a value exists in a mask
@@ -109,7 +112,7 @@ if (!function_exists('skin_view')) {
* @param array $vars * @param array $vars
* @param array $merge_data * @param array $merge_data
* *
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View * @return Factory|\Illuminate\View\View
*/ */
function skin_view($template, array $vars = [], array $merge_data = []) function skin_view($template, array $vars = [], array $merge_data = [])
{ {
@@ -136,7 +139,7 @@ if (!function_exists('setting')) {
try { try {
$value = $settingRepo->retrieve($key); $value = $settingRepo->retrieve($key);
} catch (\App\Exceptions\SettingNotFound $e) { } catch (SettingNotFound $e) {
return $default; return $default;
} }

View File

@@ -14,40 +14,41 @@
"ext-pdo": "*", "ext-pdo": "*",
"composer/composer": "1.8.x", "composer/composer": "1.8.x",
"composer/semver": "1.4.x", "composer/semver": "1.4.x",
"laravel/framework": "5.7.x",
"laravelcollective/html": "5.7.x",
"prettus/l5-repository": "2.6.x",
"nwidart/laravel-modules": "3.3.x",
"santigarcor/laratrust": "5.0.x",
"arrilot/laravel-widgets": "3.13.x",
"sebastiaanluca/laravel-helpers": "1.0.x",
"joshbrw/laravel-module-installer": "0.1.x",
"webpatser/laravel-uuid": "3.x",
"igaster/laravel-theme": "2.0.x",
"irazasyed/laravel-gamp": "1.3.x",
"toin0u/geotools-laravel": "1.0.x",
"spatie/laravel-pjax": "1.3.x",
"myclabs/deep-copy": "1.8.x",
"league/geotools": "0.8.x",
"fzaninotto/faker": "^1.8",
"hashids/hashids": "2.0.x",
"jackiedo/timezonelist": "5.x",
"tivie/php-os-detector": "1.1.x",
"pragmarx/version": "0.2.x",
"guzzlehttp/guzzle": "6.3.x",
"jmikola/geojson": "1.0.x",
"laracasts/flash": "3.0.x",
"nabeel/vacentral": "1.x",
"league/iso3166": "2.1.x",
"theiconic/php-ga-measurement-protocol": "2.7.x",
"vierbergenlars/php-semver": "3.0.x",
"php-units-of-measure/php-units-of-measure": "2.1.x",
"markrogoyski/math-php": "^0.38.0",
"akaunting/money": "1.0.x", "akaunting/money": "1.0.x",
"anhskohbo/no-captcha": "3.0.x", "anhskohbo/no-captcha": "3.0.x",
"league/csv": "9.2.x", "arrilot/laravel-widgets": "3.13.x",
"fzaninotto/faker": "^1.8",
"guzzlehttp/guzzle": "6.3.x",
"hashids/hashids": "2.0.x",
"igaster/laravel-theme": "2.0.x",
"intervention/image": "2.4.x", "intervention/image": "2.4.x",
"waavi/sanitizer": "1.0.x" "irazasyed/laravel-gamp": "1.3.x",
"jackiedo/timezonelist": "5.x",
"jmikola/geojson": "1.0.x",
"joshbrw/laravel-module-installer": "0.1.x",
"laracasts/flash": "3.0.x",
"laravel/framework": "5.7.x",
"laravelcollective/html": "5.7.x",
"league/csv": "9.2.x",
"league/geotools": "0.8.x",
"league/iso3166": "2.1.x",
"markrogoyski/math-php": "^0.38.0",
"myclabs/deep-copy": "1.8.x",
"nabeel/vacentral": "1.x",
"nwidart/laravel-modules": "3.3.x",
"php-units-of-measure/php-units-of-measure": "2.1.x",
"pragmarx/version": "0.2.x",
"prettus/l5-repository": "2.6.x",
"santigarcor/laratrust": "5.0.x",
"sebastiaanluca/laravel-helpers": "1.0.x",
"spatie/laravel-pjax": "1.3.x",
"symfony/polyfill-iconv": "^1.11",
"theiconic/php-ga-measurement-protocol": "2.7.x",
"tivie/php-os-detector": "1.1.x",
"toin0u/geotools-laravel": "1.0.x",
"vierbergenlars/php-semver": "3.0.x",
"waavi/sanitizer": "1.0.x",
"webpatser/laravel-uuid": "3.x"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": "7.5.x", "phpunit/phpunit": "7.5.x",

2
composer.lock generated
View File

@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "fb105f6d95ca2218f8e3e03c93371cd3", "content-hash": "290bc8970d44a12e8546926949d73e20",
"packages": [ "packages": [
{ {
"name": "akaunting/money", "name": "akaunting/money",

48
docker-compose.yml Normal file
View File

@@ -0,0 +1,48 @@
---
version: '3'
services:
app:
build:
context: ./docker/php
environment:
DB_HOST: mysql
volumes:
- ./:/var/www
- ./docker/php/www.conf:/usr/local/etc/php-fpm.d/www.conf
depends_on:
- mysql
nginx:
image: nginx:1.13.8
command: /bin/bash -c "exec nginx -g 'daemon off;'"
volumes:
- ./:/var/www
- ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf
ports:
- 80:80
depends_on:
- app
mysql:
image: mysql:5.7.26
environment:
MYSQL_DATABASE: phpvms
MYSQL_USER: phpvms
MYSQL_PASSWORD: phpvms
MYSQL_ROOT_PASSWORD:
MYSQL_ALLOW_EMPTY_PASSWORD: 'yes'
volumes:
- ./docker/data/mysql:/var/lib/mysql
ports:
- 3306:3306
# Use this to tail the logs so it's just all in a single window
logs:
image: busybox
command: tail -f -F -n 0 /var/www/storage/logs/laravel.log
restart: always
volumes:
- ./storage:/var/www/storage
depends_on:
- app

2
docker/data/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
*
!.gitignore

27
docker/nginx/default.conf Normal file
View File

@@ -0,0 +1,27 @@
server {
listen 80 default_server;
server_name phpvms.test;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
root /var/www/public;
index index.php index.html index.htm;
location / {
try_files $uri $uri/ /index.php$is_args$args;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass app:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include /etc/nginx/fastcgi_params;
}
location ~ /\.ht {
deny all;
}
}

12
docker/php/Dockerfile Normal file
View File

@@ -0,0 +1,12 @@
FROM php:7.3-fpm
RUN apt-get update
RUN apt-get install -y libgmp-dev
RUN ln -sf /dev/stderr /var/log/fpm-error.log
RUN docker-php-ext-install \
mysqli \
pdo \
pdo_mysql \
gmp

15
docker/php/www.conf Normal file
View File

@@ -0,0 +1,15 @@
[www]
user = www-data
group = www-data
listen = :9000
pm = dynamic
pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3
php_flag[display_errors] = on
php_admin_flag[log_errors] = on

View File

@@ -1,7 +1,7 @@
<?php <?php
/** /**
* phpVMS * phpVMS (root folder)
*/ */
$path_to_phpvms_folder = __DIR__; $path_to_phpvms_folder = __DIR__;

View File

@@ -62,7 +62,7 @@
<div class="row"> <div class="row">
<div class="col-12"> <div class="col-12">
<h2>Database Error</h2> <h2>Database Error</h2>
@yield('content') {{ $error }}
</div> </div>
</div> </div>
</div> </div>

64
swagger.yml Normal file
View File

@@ -0,0 +1,64 @@
---
swagger: "2.0"
info:
version: "7.0"
title: phpVMS API
description: All of the responses are contained in the "data" variable
basePath: /api/v1
schemes:
- https
paths:
"/flights/search":
get:
summary: Retrieve all the applications and flags
operationId: getFlightSearch
parameters:
- name: flight_id
in: query
type: string
required: false
description: ID of the flight
- name: airline_id
in: query
type: string
required: false
description: ID of the airline
- name: flight_number
in: query
type: string
required: false
description: Flight number to use
- name: route_code
in: query
type: string
required: false
description: The route code
- name: dep_icao
in: query
type: string
required: false
description: The departure ICAO
- name: arr_icao
in: query
type: string
required: false
description: The arrival ICAO
- name: dgt
in: query
type: integer
required: false
description: Flights with a distance greater than
- name: dgt
in: query
type: integer
required: false
description: Flights with a distance greater than
produces:
- application/json
responses:
200:
description: Returns flights from a search
schema:
$ref: '#/definitions/AppsWrapper'
tags:
- flights

View File

@@ -342,6 +342,45 @@ class FlightTest extends TestCase
$this->assertEquals($flight->id, $body['data'][0]['id']); $this->assertEquals($flight->id, $body['data'][0]['id']);
} }
public function testFlightSearchApiDistance()
{
$total_flights = 10;
$this->user = factory(App\Models\User::class)->create();
$flights = factory(App\Models\Flight::class, $total_flights)->create([
'airline_id' => $this->user->airline_id,
]);
// Max distance generated in factory is 1000, so set a random flight
// and try to find it again through the search
$flight = $flights->random();
$flight->distance = 1500;
$flight->save();
$distance_gt = 1100;
$distance_lt = 1600;
// look for all of the flights now less than the "factory default" of 1000
$query = 'dlt=1000&ignore_restrictions=1';
$req = $this->get('/api/flights/search?'.$query);
$body = $req->json();
$this->assertCount($total_flights - 1, $body['data']);
// Try using greater than
$query = 'dgt='.$distance_gt.'&ignore_restrictions=1';
$req = $this->get('/api/flights/search?'.$query);
$body = $req->json();
$this->assertCount(1, $body['data']);
$this->assertEquals($flight->id, $body['data'][0]['id']);
$query = 'dgt='.$distance_gt.'&dlt='.$distance_lt.'&ignore_restrictions=1';
$req = $this->get('/api/flights/search?'.$query);
$body = $req->json();
$this->assertCount(1, $body['data']);
$this->assertEquals($flight->id, $body['data'][0]['id']);
}
public function testAddSubfleet() public function testAddSubfleet()
{ {
$subfleet = factory(App\Models\Subfleet::class)->create(); $subfleet = factory(App\Models\Subfleet::class)->create();