From 9e1e0142e986e7698980e48a99071c3d4956f8e6 Mon Sep 17 00:00:00 2001 From: Nabeel Shahzad Date: Mon, 2 Apr 2018 12:55:37 -0500 Subject: [PATCH] Route downloads through controller; file IDs as hash to prevent guessing; download count; download list on airport page --- .../2018_04_01_193443_create_files_table.php | 6 ++- .../Controllers/Admin/FilesController.php | 2 +- .../Controllers/Frontend/FileController.php | 47 +++++++++++++++++++ app/Models/File.php | 39 ++++++++++++++- app/Routes/web.php | 3 ++ app/Widgets/CheckWx.php | 1 - .../views/admin/common/file_upload.blade.php | 4 +- .../layouts/default/airports/show.blade.php | 40 +++++++++++++--- 8 files changed, 131 insertions(+), 11 deletions(-) create mode 100644 app/Http/Controllers/Frontend/FileController.php diff --git a/app/Database/migrations/2018_04_01_193443_create_files_table.php b/app/Database/migrations/2018_04_01_193443_create_files_table.php index 57137620..1b97f757 100644 --- a/app/Database/migrations/2018_04_01_193443_create_files_table.php +++ b/app/Database/migrations/2018_04_01_193443_create_files_table.php @@ -13,15 +13,19 @@ class CreateFilesTable extends Migration public function up() { Schema::create('files', function (Blueprint $table) { - $table->increments('id'); + $table->string('id', \App\Interfaces\Model::ID_MAX_LENGTH); $table->string('name'); $table->string('description')->nullable(); $table->string('disk')->nullable(); $table->string('path'); $table->boolean('public')->default(true); + $table->unsignedInteger('download_count')->default(0); $table->string('ref_model', 50)->nullable(); $table->string('ref_model_id', 36)->nullable(); $table->timestamps(); + + $table->primary('id'); + $table->index(['ref_model', 'ref_model_id']); }); } diff --git a/app/Http/Controllers/Admin/FilesController.php b/app/Http/Controllers/Admin/FilesController.php index 5ff8d333..8ce12d09 100644 --- a/app/Http/Controllers/Admin/FilesController.php +++ b/app/Http/Controllers/Admin/FilesController.php @@ -57,7 +57,7 @@ class FilesController extends Controller $asset->description = $attrs['file_description']; $asset->disk = config('filesystems.public_files'); $asset->path = $file_path; - $asset->public = true; + $asset->public = false; // need to be logged in to see. default (for now) $asset->ref_model = $attrs['ref_model']; $asset->ref_model_id = $attrs['ref_model_id']; diff --git a/app/Http/Controllers/Frontend/FileController.php b/app/Http/Controllers/Frontend/FileController.php new file mode 100644 index 00000000..fd85c170 --- /dev/null +++ b/app/Http/Controllers/Frontend/FileController.php @@ -0,0 +1,47 @@ +back(); + } + + // Allowed to download? If not, direct to login + if (!$file->public && !Auth::check()) { + return redirect(config('app.login_redirect')); + } + + ++$file->download_count; + $file->save(); + + if($file->disk === 'public') { + $storage = Storage::disk('public'); + return $storage->download($file->path, $file->filename); + } + + // TODO: Config for streamed response? + return redirect()->to($file->url); + } +} diff --git a/app/Models/File.php b/app/Models/File.php index ac266282..210d2e11 100644 --- a/app/Models/File.php +++ b/app/Models/File.php @@ -4,23 +4,28 @@ namespace App\Models; use App\Interfaces\Model; +use App\Models\Traits\HashIdTrait; use App\Models\Traits\ReferenceTrait; use Illuminate\Support\Facades\Storage; /** - * File property * @property string $name * @property string $description * @property string $disk * @property string $path * @property boolean $public + * @property int $download_count + * @property string $url + * @property string $filename * @package App\Models */ class File extends Model { + use HashIdTrait; use ReferenceTrait; protected $table = 'files'; + public $incrementing = false; protected $fillable = [ 'name', @@ -32,10 +37,42 @@ class File extends Model 'ref_model_id', ]; + protected $casts = [ + 'public' => 'boolean', + ]; + public static $rules = [ 'name' => 'required', ]; + private $pathinfo; + + /** + * Return the file extension + * @return string + */ + public function getExtensionAttribute(): string + { + if (!$this->pathinfo) { + $this->pathinfo = pathinfo($this->path); + } + + return $this->pathinfo['extension']; + } + + /** + * Get just the filename + * @return string + */ + public function getFilenameAttribute() :string + { + if (!$this->pathinfo) { + $this->pathinfo = pathinfo($this->path); + } + + return $this->pathinfo['filename'].'.'.$this->pathinfo['extension']; + } + /** * Get the full URL to this attribute * @return string diff --git a/app/Routes/web.php b/app/Routes/web.php index ce33b1ec..91f45a12 100755 --- a/app/Routes/web.php +++ b/app/Routes/web.php @@ -27,6 +27,9 @@ Route::group([ Route::get('airports/{id}', 'AirportController@show')->name('airports.show'); + // Download a file + Route::get('files/{id}', 'FileController@show')->name('files.show'); + Route::get('flights/bids', 'FlightController@bids')->name('flights.bids'); Route::get('flights/search', 'FlightController@search')->name('flights.search'); Route::resource('flights', 'FlightController'); diff --git a/app/Widgets/CheckWx.php b/app/Widgets/CheckWx.php index 3743190c..ac15d84f 100644 --- a/app/Widgets/CheckWx.php +++ b/app/Widgets/CheckWx.php @@ -41,7 +41,6 @@ class CheckWx extends Widget return $data; }); - if($data->results === 1) { $data = $data->data[0]; } else { diff --git a/resources/views/admin/common/file_upload.blade.php b/resources/views/admin/common/file_upload.blade.php index 10f52af6..bfae7910 100644 --- a/resources/views/admin/common/file_upload.blade.php +++ b/resources/views/admin/common/file_upload.blade.php @@ -16,7 +16,8 @@ Pass in: Name - Current File + Direct Link + Downloads @@ -26,6 +27,7 @@ Pass in: {{ $file->name }} Link to file + {{$file->download_count}} {{ Form::open(['route' => ['admin.files.delete', $file->id], 'method' => 'delete']) }} {{ Form::hidden('id', $file->id) }} diff --git a/resources/views/layouts/default/airports/show.blade.php b/resources/views/layouts/default/airports/show.blade.php index 66bdb72c..bb093112 100644 --- a/resources/views/layouts/default/airports/show.blade.php +++ b/resources/views/layouts/default/airports/show.blade.php @@ -2,17 +2,19 @@ @section('title', $airport->full_name) @section('content') -
+

{{ $airport->full_name }}

-
+ {{-- Show the weather widget in one column --}} +
{{ Widget::checkWx([ 'icao' => $airport->icao, ]) }} -
+ + {{-- Show the airspace map in the other column --}}
{{ Widget::airspaceMap([ 'width' => '100%', @@ -22,21 +24,47 @@ ]) }}
-
+
+ {{-- There are files uploaded and a user is logged in--}} + @if($airport->files && Auth::check()) +
+

Downloads

+
    + @foreach($airport->files as $file) +
  • + + {{ $file->name }} + + {{-- only show description is one is provided --}} + @if($file->description) + - {{$file->description}} + @endif + {{$file->download_count}} downloads +
  • + @endforeach +
+
+ @endif

Inbound Flights

@if(!$inbound_flights) -
+
no flights found
@else @each('airports.table', $inbound_flights, 'flight') @endif

Outbound Flights

- @each('airports.table', $outbound_flights, 'flight') + @if(!$outbound_flights) +
+ no flights found +
+ @else + @each('airports.table', $outbound_flights, 'flight') + @endif
@endsection