From 79367642b1b7bede0add08c982a29aea44382f98 Mon Sep 17 00:00:00 2001 From: snipe Date: Sat, 29 Sep 2018 21:33:52 -0700 Subject: [PATCH] [WIP] Added #5957 - Flysystem support (#6262) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Added AWS url to example env * Upgrader - added check for new storage path and attempt to move * Ignore symlink * Updated paths for models * Moved copy methods * Added AWS_URL support For some reasin, Flysystem was generating the wrong AWS url (with a region included) * Switch to Flysystem for image uploads * Nicer display of image preview * Updated image preview on edit blades to use Flysystem * Twiddled some more paths * Working filesystems config * Updated Asset Models and Departments to use Flysystem * Janky workaround for differing S3/local urls/paths * Try to smartly use S3 as public disk if S3 is configured * Use public disk Storage options for public files * Additional transformer edits for Flysystem * Removed debugging * Added missing use Storage directive * Updated seeders to use Flysystem * Default logo * Set a default width We can potentially override this in settings later * Use Flysystem for logo upload * Update downloadFile to use Flysystem * Updated AssetFilesController to use Flysystem * Updated acceptance signatures to use Flysystem * Updated signature view to use Flysystem This isn’t working 100% yet * Use Flysystem facade for displaying asset image * Set assets path Should clean all these up when we’re done here * Added Rackspace support for Flysystem * Added Flysystem migrator console command * Added use Storage directive for categories * Added user avatars to Flysystem * Added profile avatar to Flysystem * Added the option to delete local files with the migrator * Added a check to prevent people from trying to move from local to local * Fixed the selectlists for Flysystem * Fixed the getImageUrl method to reflect Flysystem * Fixed AWS copy process * Fixed models path * More selectlist updates for Flysystem * Updated example .envs with updated env variable names * *sigh* * Updated non-asset getImageUrl() methods to use Flysystem * Removed S3 hardcoding * Use Flysystem in email headers * Fixed typo * Removed camera support from asset file upload We’ll find a way to add this in later (and add that support to all of the other image uploads as well) * Fixed path for categories * WIP - Switched to standard handleImages for asset upload. This is currently broken as I refact the handleImages method. Because the assets store/create methods use their own Form Request, the handleImages method doesn’t exist in that Form Request so it wil error now. * Fixed css URL error * Updated Debugbar to latest version (#6265) v3.2 adds support for Laravel 5.7 * Fixed: Missing CSS file in basic.blade.php (#6264) * Fixed missing CSS file in basic.blade.php * Added * Changed stylesheet import for authorize.blade.php * Updated composer lock * Added AWS_BUCKET_ROOT as env variable * Use nicer image preview for logo upload * Removed AssetRequest form request * Removed asset form request, moved custom field validation into model * Added additional help text for logo upload * Increased the size of the image resize - should make this a setting tho * Few more formatting tweaks to logo section of branding blade preview * Use Flysystem for asset/license file uploads * Use Flysystem for removing images from models that have been deleted * Enable backups to use Flysystem This only handles part of the problem. This just makes it so we can ship files to S3 if we want, but does not account for how we backup files that are hosted on S3 * Use Flysystem to download license files * Updated audits to use Flysystem --- .env.example | 8 +- .env.testing | 8 +- .env.testing-ci | 8 +- app/Console/Commands/MoveUploadsToNewDisk.php | 183 ++++++++ app/Console/Kernel.php | 1 + .../Accessories/AccessoriesController.php | 10 + .../Account/AcceptanceController.php | 15 +- .../Controllers/Api/AssetModelsController.php | 5 +- app/Http/Controllers/Api/AssetsController.php | 5 +- .../Controllers/Api/CategoriesController.php | 3 +- .../Controllers/Api/CompaniesController.php | 2 +- .../Api/CustomFieldsetsController.php | 1 - .../Controllers/Api/DepartmentsController.php | 3 +- app/Http/Controllers/Api/ImportController.php | 3 +- .../Controllers/Api/LocationsController.php | 3 +- .../Api/ManufacturersController.php | 3 +- .../Controllers/Api/SuppliersController.php | 3 +- app/Http/Controllers/Api/UsersController.php | 9 + .../Controllers/AssetModelsController.php | 6 +- .../Assets/AssetFilesController.php | 26 +- .../Controllers/Assets/AssetsController.php | 118 ++--- app/Http/Controllers/CategoriesController.php | 3 +- app/Http/Controllers/CompaniesController.php | 10 + .../Components/ComponentsController.php | 11 + .../Controllers/DepartmentsController.php | 9 + .../Licenses/LicenseFilesController.php | 45 +- app/Http/Controllers/LocationsController.php | 12 +- .../Controllers/ManufacturersController.php | 7 +- app/Http/Controllers/ProfileController.php | 39 +- app/Http/Controllers/SettingsController.php | 84 ++-- app/Http/Controllers/SuppliersController.php | 1 + app/Http/Requests/AssetRequest.php | 68 --- app/Http/Requests/ImageUploadRequest.php | 36 +- .../Transformers/AccessoriesTransformer.php | 4 +- .../Transformers/ActionlogsTransformer.php | 2 +- .../Transformers/AssetModelsTransformer.php | 3 +- .../Transformers/CategoriesTransformer.php | 3 +- .../Transformers/CompaniesTransformer.php | 3 +- .../Transformers/ComponentsTransformer.php | 3 +- .../Transformers/ConsumablesTransformer.php | 3 +- .../Transformers/DepartmentsTranformer.php | 3 +- .../Transformers/LocationsTransformer.php | 3 +- .../Transformers/ManufacturersTransformer.php | 3 +- .../Transformers/SuppliersTransformer.php | 3 +- app/Models/Accessory.php | 3 +- app/Models/Asset.php | 32 +- app/Models/AssetModel.php | 3 +- app/Models/Consumable.php | 3 +- app/Presenters/UserPresenter.php | 3 +- app/Providers/SettingsServiceProvider.php | 41 +- composer.json | 1 + composer.lock | 406 ++++++++++++++---- config/backup.php | 7 +- config/filesystems.php | 83 ++-- database/seeds/AssetModelSeeder.php | 26 +- database/seeds/AssetSeeder.php | 15 +- database/seeds/CompanySeeder.php | 27 +- database/seeds/LocationSeeder.php | 27 +- database/seeds/ManufacturerSeeder.php | 26 +- public/img/demo/logo.png | Bin 0 -> 22482 bytes resources/lang/en/general.php | 1 + resources/views/accessories/edit.blade.php | 2 +- resources/views/account/profile.blade.php | 2 +- resources/views/categories/edit.blade.php | 2 +- resources/views/companies/edit.blade.php | 2 +- resources/views/components/edit.blade.php | 2 +- resources/views/consumables/edit.blade.php | 2 +- resources/views/departments/edit.blade.php | 2 +- resources/views/hardware/edit.blade.php | 131 +----- resources/views/hardware/view.blade.php | 4 +- resources/views/layouts/basic.blade.php | 2 +- resources/views/layouts/default.blade.php | 4 +- resources/views/locations/edit.blade.php | 4 +- resources/views/manufacturers/edit.blade.php | 2 +- resources/views/models/edit.blade.php | 2 +- .../forms/edit/image-upload.blade.php | 4 +- resources/views/settings/backups.blade.php | 2 +- resources/views/settings/branding.blade.php | 32 +- resources/views/users/view.blade.php | 6 +- .../views/vendor/mail/html/header.blade.php | 4 +- upgrade.php | 57 ++- 81 files changed, 1092 insertions(+), 661 deletions(-) create mode 100644 app/Console/Commands/MoveUploadsToNewDisk.php delete mode 100644 app/Http/Requests/AssetRequest.php create mode 100644 public/img/demo/logo.png diff --git a/.env.example b/.env.example index f6ad25fc1c..dee4985ccf 100644 --- a/.env.example +++ b/.env.example @@ -85,10 +85,12 @@ REDIS_PORT-null # -------------------------------------------- # OPTIONAL: AWS S3 SETTINGS # -------------------------------------------- -AWS_SECRET=null -AWS_KEY=null -AWS_REGION=null +AWS_SECRET_ACCESS_KEY=null +AWS_ACCESS_KEY_ID=null +AWS_DEFAULT_REGION=null AWS_BUCKET=null +AWS_BUCKET_ROOT=null +AWS_URL=null # -------------------------------------------- # OPTIONAL: LOGIN THROTTLING diff --git a/.env.testing b/.env.testing index f84dd82e9f..980f24f09e 100644 --- a/.env.testing +++ b/.env.testing @@ -40,10 +40,12 @@ IMAGE_LIB=gd # -------------------------------------------- # OPTIONAL: AWS S3 SETTINGS # -------------------------------------------- -AWS_SECRET=null -AWS_KEY=null -AWS_REGION=null +AWS_SECRET_ACCESS_KEY=null +AWS_ACCESS_KEY_ID=null +AWS_DEFAULT_REGION=null AWS_BUCKET=null +AWS_BUCKET_ROOT=null +AWS_URL=null # -------------------------------------------- diff --git a/.env.testing-ci b/.env.testing-ci index b12a99d442..978c1895a3 100644 --- a/.env.testing-ci +++ b/.env.testing-ci @@ -40,10 +40,12 @@ IMAGE_LIB=gd # -------------------------------------------- # OPTIONAL: AWS S3 SETTINGS # -------------------------------------------- -AWS_SECRET=null -AWS_KEY=null -AWS_REGION=null +AWS_SECRET_ACCESS_KEY=null +AWS_ACCESS_KEY_ID=null +AWS_DEFAULT_REGION=null AWS_BUCKET=null +AWS_BUCKET_ROOT=null +AWS_URL=null # -------------------------------------------- diff --git a/app/Console/Commands/MoveUploadsToNewDisk.php b/app/Console/Commands/MoveUploadsToNewDisk.php new file mode 100644 index 0000000000..505e260ce0 --- /dev/null +++ b/app/Console/Commands/MoveUploadsToNewDisk.php @@ -0,0 +1,183 @@ +error('Your current disk is set to local so we cannot proceed.'); + $this->warn("Please configure your .env settings for S3 or Rackspace, \nand change your FILESYSTEM_DISK value to 's3' or 'rackspace'."); + return false; + } + $delete_local = $this->argument('delete_local'); + + $public_uploads['accessories'] = glob('storage/app/public/accessories'."/*.*"); + $public_uploads['assets'] = glob('storage/app/public/assets'."/*.*"); + $public_uploads['avatars'] = glob('storage/app/public/avatars'."/*.*"); + $public_uploads['barcodes'] = glob('storage/app/public/barcodes'."/*.*"); + $public_uploads['categories'] = glob('storage/app/public/categories'."/*.*"); + $public_uploads['companies'] = glob('storage/app/public/companies'."/*.*"); + $public_uploads['components'] = glob('storage/app/public/components'."/*.*"); + $public_uploads['consumables'] = glob('storage/app/public/consumables'."/*.*"); + $public_uploads['departments'] = glob('storage/app/public/departments'."/*.*"); + $public_uploads['locations'] = glob('storage/app/public/locations'."/*.*"); + $public_uploads['manufacturers'] = glob('storage/app/public/manufacturers'."/*.*"); + $public_uploads['suppliers'] = glob('storage/app/public/suppliers'."/*.*"); + $public_uploads['assetmodels'] = glob('storage/app/public/models'."/*.*"); + + + // iterate files + foreach($public_uploads as $public_type => $public_upload) + { + $type_count = 0; + $this->info("\nThere are ".count($public_upload).' PUBLIC '.$public_type.' files.'); + + for ($i = 0; $i < count($public_upload); $i++) { + $type_count++; + $filename = basename($public_upload[$i]); + + try { + Storage::disk('public')->put($public_type.'/'.$filename, file_get_contents($public_upload[$i])); + $new_url = Storage::disk('public')->url($public_type.'/'.$filename, $filename); + $this->info($type_count.'. PUBLIC: '.$filename.' was copied to '.$new_url); + } catch (\Exception $e) { + \Log::debug($e); + $this->error($e); + } + + } + + } + + $logos = glob('public/uploads'."/logo*.*"); + $this->info("\nThere are ".count($logos).' files that might be logos.'); + $type_count=0; + + for ($l = 0; $l < count($logos); $l++) { + $type_count++; + $filename = basename($logos[$l]); + $new_url = Storage::disk('public')->url($logos[$l], file_get_contents($public_upload[$i])); + $this->info($type_count.'. LOGO: '.$filename.' was copied to '.$new_url); + } + + $private_uploads['assets'] = glob('storage/private_uploads/assets'."/*.*"); + $private_uploads['signatures'] = glob('storage/private_uploads/signatures'."/*.*"); + $private_uploads['audits'] = glob('storage/private_uploads/audits'."/*.*"); + $private_uploads['assetmodels'] = glob('storage/private_uploads/assetmodels'."/*.*"); + $private_uploads['imports'] = glob('storage/private_uploads/imports'."/*.*"); + $private_uploads['licenses'] = glob('storage/private_uploads/licenses'."/*.*"); + $private_uploads['users'] = glob('storage/private_uploads/users'."/*.*"); + + + foreach($private_uploads as $private_type => $private_upload) + { + $this->info("\nThere are ".count($private_upload).' PRIVATE '.$private_type.' files.'); + // $this->info(print_r($private_upload, true)); + + $type_count = 0; + for ($x = 0; $x < count($private_upload); $x++) { + $type_count++; + $filename = basename($private_upload[$x]); + + try { + Storage::disk('private_uploads')->put($private_type.'/'.$filename, file_get_contents($public_upload[$i])); + $new_url = Storage::url($private_type.'/'.$filename, $filename); + $this->info($type_count.'. PRIVATE: '.$filename.' was copied to '.$new_url); + + } catch (\Exception $e) { + \Log::debug($e); + $this->error($e); + } + + } + + } + + + if ($delete_local=='true') { + $public_delete_count = 0; + $private_delete_count = 0; + + $this->info("\n\n"); + $this->error('!!!!!!!!!!!!!!!!!!!!!!!!!!!!! WARNING!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!'); + $this->warn("\nTHIS WILL DELETE ALL OF YOUR LOCAL UPLOADED FILES. \n\nThis cannot be undone, so you should take a backup of your system before you proceed.\n"); + $this->error('!!!!!!!!!!!!!!!!!!!!!!!!!!!!! WARNING!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!'); + + if ($this->confirm("Do you wish to continue?")) { + + foreach($public_uploads as $public_type => $public_upload) { + + for ($i = 0; $i < count($public_upload); $i++) { + $filename = $public_upload[$i]; + try { + unlink($filename); + $public_delete_count++; + } catch (\Exception $e) { + \Log::debug($e); + $this->error($e); + } + + } + } + + foreach($private_uploads as $private_type => $private_upload) + { + + for ($i = 0; $i < count($private_upload); $i++) { + $filename = $private_upload[$i]; + try { + unlink($filename); + $private_delete_count++; + } catch (\Exception $e) { + \Log::debug($e); + $this->error($e); + } + + } + } + + $this->info($public_delete_count." PUBLIC local files and ".$private_delete_count." PRIVATE local files were delete from your filesystem."); + } + } + + + + + } +} diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index 750369df55..ad2d6dcfd3 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -32,6 +32,7 @@ class Kernel extends ConsoleKernel Commands\SyncAssetCounters::class, Commands\RestoreDeletedUsers::class, Commands\SendCurrentInventoryToUsers::class, + Commands\MoveUploadsToNewDisk::class, ]; /** diff --git a/app/Http/Controllers/Accessories/AccessoriesController.php b/app/Http/Controllers/Accessories/AccessoriesController.php index 53cceb46ac..0570297064 100755 --- a/app/Http/Controllers/Accessories/AccessoriesController.php +++ b/app/Http/Controllers/Accessories/AccessoriesController.php @@ -9,6 +9,7 @@ use App\Models\Company; use Illuminate\Support\Facades\Auth; use Illuminate\Http\Request; use Redirect; +use Illuminate\Support\Facades\Storage; /** This controller handles all actions related to Accessories for * the Snipe-IT Asset Management application. @@ -170,6 +171,15 @@ class AccessoriesController extends Controller if ($accessory->hasUsers() > 0) { return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.assoc_users', array('count'=> $accessory->hasUsers()))); } + + if ($accessory->image) { + try { + Storage::disk('public')->delete('accessories'.'/'.$accessory->image); + } catch (\Exception $e) { + \Log::debug($e); + } + } + $accessory->delete(); return redirect()->route('accessories.index')->with('success', trans('admin/accessories/message.delete.success')); } diff --git a/app/Http/Controllers/Account/AcceptanceController.php b/app/Http/Controllers/Account/AcceptanceController.php index 198e11e998..23cd29d2d0 100644 --- a/app/Http/Controllers/Account/AcceptanceController.php +++ b/app/Http/Controllers/Account/AcceptanceController.php @@ -15,6 +15,7 @@ use App\Models\License; use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Str; +use Illuminate\Support\Facades\Storage; class AcceptanceController extends Controller { @@ -40,7 +41,7 @@ class AcceptanceController extends Controller { $acceptance = CheckoutAcceptance::find($id); if (is_null($acceptance)) { - return redirect()->reoute('account.accept')->with('error', trans('admin/hardware/message.does_not_exist')); + return redirect()->route('account.accept')->with('error', trans('admin/hardware/message.does_not_exist')); } if (! $acceptance->isPending()) { @@ -70,7 +71,7 @@ class AcceptanceController extends Controller { $acceptance = CheckoutAcceptance::find($id); if (is_null($acceptance)) { - return redirect()->reoute('account.accept')->with('error', trans('admin/hardware/message.does_not_exist')); + return redirect()->route('account.accept')->with('error', trans('admin/hardware/message.does_not_exist')); } if (! $acceptance->isPending()) { @@ -92,13 +93,17 @@ class AcceptanceController extends Controller { /** * Get the signature and save it */ + + if (!Storage::exists('private_uploads/signatures')) Storage::makeDirectory('private_uploads/signatures', 775); + + + if ($request->filled('signature_output')) { - $path = config('app.private_uploads').'/signatures'; $sig_filename = "siglog-" .Str::uuid() . '-'.date('Y-m-d-his').".png"; $data_uri = e($request->input('signature_output')); $encoded_image = explode(",", $data_uri); $decoded_image = base64_decode($encoded_image[1]); - file_put_contents($path."/".$sig_filename, $decoded_image); + Storage::put('private_uploads/signatures/'.$sig_filename, (string)$decoded_image); } @@ -122,4 +127,4 @@ class AcceptanceController extends Controller { return redirect()->to('account/accept')->with('success', $return_msg); } -} \ No newline at end of file +} diff --git a/app/Http/Controllers/Api/AssetModelsController.php b/app/Http/Controllers/Api/AssetModelsController.php index c0011b61ae..289348f17c 100644 --- a/app/Http/Controllers/Api/AssetModelsController.php +++ b/app/Http/Controllers/Api/AssetModelsController.php @@ -9,6 +9,7 @@ use Illuminate\Http\Request; use App\Http\Transformers\AssetModelsTransformer; use App\Http\Transformers\AssetsTransformer; use App\Http\Transformers\SelectlistTransformer; +use Illuminate\Support\Facades\Storage; /** @@ -177,7 +178,7 @@ class AssetModelsController extends Controller if ($assetmodel->image) { try { - unlink(public_path().'/uploads/models/'.$assetmodel->image); + Storage::disk('public')->delete('assetmodels/'.$assetmodel->image); } catch (\Exception $e) { \Log::error($e); } @@ -234,7 +235,7 @@ class AssetModelsController extends Controller $assetmodel->use_text .= ' (#'.e($assetmodel->model_number).')'; } - $assetmodel->use_image = ($settings->modellistCheckedValue('image') && ($assetmodel->image)) ? url('/').'/uploads/models/'.$assetmodel->image : null; + $assetmodel->use_image = ($settings->modellistCheckedValue('image') && ($assetmodel->image)) ? Storage::disk('public')->url('assetmodels/'.e($assetmodel->image)) : null; } return (new SelectlistTransformer)->transformSelectlist($assetmodels); diff --git a/app/Http/Controllers/Api/AssetsController.php b/app/Http/Controllers/Api/AssetsController.php index dbed7be798..0b65508c5d 100644 --- a/app/Http/Controllers/Api/AssetsController.php +++ b/app/Http/Controllers/Api/AssetsController.php @@ -3,7 +3,6 @@ namespace App\Http\Controllers\Api; use App\Helpers\Helper; use App\Http\Controllers\Controller; -use App\Http\Requests\AssetRequest; use App\Http\Requests\AssetCheckoutRequest; use App\Http\Transformers\AssetsTransformer; use App\Models\Asset; @@ -400,7 +399,7 @@ class AssetsController extends Controller * @since [v4.0] * @return JsonResponse */ - public function store(AssetRequest $request) + public function store(Request $request) { $this->authorize('create', Asset::class); @@ -431,7 +430,7 @@ class AssetsController extends Controller // Update custom fields in the database. // Validation for these fields is handled through the AssetRequest form request $model = AssetModel::find($request->get('model_id')); - if ($model->fieldset) { + if (($model) && ($model->fieldset)) { foreach ($model->fieldset->fields as $field) { $asset->{$field->convertUnicodeDbSlug()} = e($request->input($field->convertUnicodeDbSlug(), null)); } diff --git a/app/Http/Controllers/Api/CategoriesController.php b/app/Http/Controllers/Api/CategoriesController.php index 3a208c64ae..1cee93110c 100644 --- a/app/Http/Controllers/Api/CategoriesController.php +++ b/app/Http/Controllers/Api/CategoriesController.php @@ -8,6 +8,7 @@ use App\Helpers\Helper; use App\Models\Category; use App\Http\Transformers\CategoriesTransformer; use App\Http\Transformers\SelectlistTransformer; +use Illuminate\Support\Facades\Storage; class CategoriesController extends Controller { @@ -158,7 +159,7 @@ class CategoriesController extends Controller // This lets us have more flexibility in special cases like assets, where // they may not have a ->name value but we want to display something anyway foreach ($categories as $category) { - $category->use_image = ($category->image) ? url('/').'/uploads/categories/'.$category->image : null; + $category->use_image = ($category->image) ? Storage::disk('public')->url('categories/'.$category->image, $category->image) : null; } return (new SelectlistTransformer)->transformSelectlist($categories); diff --git a/app/Http/Controllers/Api/CompaniesController.php b/app/Http/Controllers/Api/CompaniesController.php index d2dc5990c8..6b1c63f54b 100644 --- a/app/Http/Controllers/Api/CompaniesController.php +++ b/app/Http/Controllers/Api/CompaniesController.php @@ -178,7 +178,7 @@ class CompaniesController extends Controller // This lets us have more flexibility in special cases like assets, where // they may not have a ->name value but we want to display something anyway foreach ($companies as $company) { - $company->use_image = ($company->image) ? url('/').'/uploads/companies/'.$company->image : null; + $company->use_image = ($company->image) ? Storage::disk('public')->url('companies/'.$company->image, $company->image) : null; } return (new SelectlistTransformer)->transformSelectlist($companies); diff --git a/app/Http/Controllers/Api/CustomFieldsetsController.php b/app/Http/Controllers/Api/CustomFieldsetsController.php index f5cfafdf93..5ed9161522 100644 --- a/app/Http/Controllers/Api/CustomFieldsetsController.php +++ b/app/Http/Controllers/Api/CustomFieldsetsController.php @@ -16,7 +16,6 @@ use App\Http\Controllers\Controller; use App\Helpers\Helper; use App\Http\Transformers\CustomFieldsTransformer; use App\Http\Transformers\CustomFieldsetsTransformer; -use App\Http\Requests\AssetRequest; /** * This controller handles all actions related to Custom Asset Fieldsets for diff --git a/app/Http/Controllers/Api/DepartmentsController.php b/app/Http/Controllers/Api/DepartmentsController.php index 50a03baffa..1d0e11dcf9 100644 --- a/app/Http/Controllers/Api/DepartmentsController.php +++ b/app/Http/Controllers/Api/DepartmentsController.php @@ -9,6 +9,7 @@ use App\Http\Transformers\DepartmentsTransformer; use App\Helpers\Helper; use Auth; use App\Http\Transformers\SelectlistTransformer; +use Illuminate\Support\Facades\Storage; class DepartmentsController extends Controller { @@ -152,7 +153,7 @@ class DepartmentsController extends Controller // This lets us have more flexibility in special cases like assets, where // they may not have a ->name value but we want to display something anyway foreach ($departments as $department) { - $department->use_image = ($department->image) ? url('/').'/uploads/departments/'.$department->image : null; + $department->use_image = ($department->image) ? Storage::disk('public')->url('departments/'.$department->image, $department->image) : null; } return (new SelectlistTransformer)->transformSelectlist($departments); diff --git a/app/Http/Controllers/Api/ImportController.php b/app/Http/Controllers/Api/ImportController.php index e18acf3a7b..797df4d9ef 100644 --- a/app/Http/Controllers/Api/ImportController.php +++ b/app/Http/Controllers/Api/ImportController.php @@ -15,6 +15,7 @@ use League\Csv\Reader; use Symfony\Component\HttpFoundation\File\Exception\FileException; use Artisan; use App\Models\Asset; +use Illuminate\Support\Facades\Storage; class ImportController extends Controller { @@ -167,7 +168,7 @@ class ImportController extends Controller if ($import = Import::find($import_id)) { try { // Try to delete the file - unlink(config('app.private_uploads').'/imports/'.$import->file_path); + Storage::delete('imports/'.$import->file_path); $import->delete(); return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/hardware/message.import.file_delete_success'))); diff --git a/app/Http/Controllers/Api/LocationsController.php b/app/Http/Controllers/Api/LocationsController.php index 452b5b73b9..eaabc0ac30 100644 --- a/app/Http/Controllers/Api/LocationsController.php +++ b/app/Http/Controllers/Api/LocationsController.php @@ -8,6 +8,7 @@ use App\Helpers\Helper; use App\Models\Location; use App\Http\Transformers\LocationsTransformer; use App\Http\Transformers\SelectlistTransformer; +use Illuminate\Support\Facades\Storage; class LocationsController extends Controller { @@ -203,7 +204,7 @@ class LocationsController extends Controller // they may not have a ->name value but we want to display something anyway foreach ($locations as $location) { $location->use_text = $location->name; - $location->use_image = ($location->image) ? url('/').'/uploads/locations/'.$location->image : null; + $location->use_image = ($location->image) ? Storage::disk('public')->url('locations/'.$location->image, $location->image): null; } return (new SelectlistTransformer)->transformSelectlist($locations); diff --git a/app/Http/Controllers/Api/ManufacturersController.php b/app/Http/Controllers/Api/ManufacturersController.php index a943cc21d4..2d30b3d5f2 100644 --- a/app/Http/Controllers/Api/ManufacturersController.php +++ b/app/Http/Controllers/Api/ManufacturersController.php @@ -9,6 +9,7 @@ use App\Models\Manufacturer; use App\Http\Transformers\DatatablesTransformer; use App\Http\Transformers\ManufacturersTransformer; use App\Http\Transformers\SelectlistTransformer; +use Illuminate\Support\Facades\Storage; class ManufacturersController extends Controller { @@ -166,7 +167,7 @@ class ManufacturersController extends Controller // they may not have a ->name value but we want to display something anyway foreach ($manufacturers as $manufacturer) { $manufacturer->use_text = $manufacturer->name; - $manufacturer->use_image = ($manufacturer->image) ? url('/').'/uploads/manufacturers/'.$manufacturer->image : null; + $manufacturer->use_image = ($manufacturer->image) ? Storage::disk('public')->url('manufacturers/'.$manufacturer->image, $manufacturer->image) : null; } return (new SelectlistTransformer)->transformSelectlist($manufacturers); diff --git a/app/Http/Controllers/Api/SuppliersController.php b/app/Http/Controllers/Api/SuppliersController.php index b79fda773f..d15492b1bb 100644 --- a/app/Http/Controllers/Api/SuppliersController.php +++ b/app/Http/Controllers/Api/SuppliersController.php @@ -8,6 +8,7 @@ use App\Helpers\Helper; use App\Models\Supplier; use App\Http\Transformers\SuppliersTransformer; use App\Http\Transformers\SelectlistTransformer; +use Illuminate\Support\Facades\Storage; class SuppliersController extends Controller @@ -164,7 +165,7 @@ class SuppliersController extends Controller // they may not have a ->name value but we want to display something anyway foreach ($suppliers as $supplier) { $supplier->use_text = $supplier->name; - $supplier->use_image = ($supplier->image) ? url('/').'/uploads/suppliers/'.$supplier->image : null; + $supplier->use_image = ($supplier->image) ? Storage::disk('public')->url('suppliers/'.$supplier->image, $supplier->image) : null; } return (new SelectlistTransformer)->transformSelectlist($suppliers); diff --git a/app/Http/Controllers/Api/UsersController.php b/app/Http/Controllers/Api/UsersController.php index 7fca6bf3af..f787f46542 100644 --- a/app/Http/Controllers/Api/UsersController.php +++ b/app/Http/Controllers/Api/UsersController.php @@ -283,6 +283,15 @@ class UsersController extends Controller return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/users/message.error.delete_has_assets'))); } + // Remove the user's avatar if they have one + if (Storage::disk('public')->exists('avatars/'.$user->avatar)) { + try { + Storage::disk('public')->delete('avatars/'.$user->avatar); + } catch (\Exception $e) { + \Log::debug($e); + } + } + if ($user->delete()) { return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/users/message.success.delete'))); } diff --git a/app/Http/Controllers/AssetModelsController.php b/app/Http/Controllers/AssetModelsController.php index d97c36e137..790b8c9876 100755 --- a/app/Http/Controllers/AssetModelsController.php +++ b/app/Http/Controllers/AssetModelsController.php @@ -82,7 +82,7 @@ class AssetModelsController extends Controller $model->fieldset_id = e($request->input('custom_fieldset')); } - $model = $request->handleImages($model, app('models_upload_path')); + $model = $request->handleImages($model); // Was it created? if ($model->save()) { @@ -161,7 +161,7 @@ class AssetModelsController extends Controller } } - $model = $request->handleImages($model, app('models_upload_path')); + $model = $request->handleImages($model); if ($model->save()) { return redirect()->route("models.index")->with('success', trans('admin/models/message.update.success')); @@ -194,7 +194,7 @@ class AssetModelsController extends Controller if ($model->image) { try { - unlink(public_path().'/uploads/models/'.$model->image); + Storage::disk('public')->delete('models/'.$model->image); } catch (\Exception $e) { \Log::error($e); } diff --git a/app/Http/Controllers/Assets/AssetFilesController.php b/app/Http/Controllers/Assets/AssetFilesController.php index 9f31b80dc8..bc7f808135 100644 --- a/app/Http/Controllers/Assets/AssetFilesController.php +++ b/app/Http/Controllers/Assets/AssetFilesController.php @@ -31,13 +31,14 @@ class AssetFilesController extends Controller $this->authorize('update', $asset); if ($request->hasFile('file')) { + + if (!Storage::exists('private_uploads/assets')) Storage::makeDirectory('private_uploads/assets', 775); + foreach ($request->file('file') as $file) { $extension = $file->getClientOriginalExtension(); - $filename = 'hardware-'.$asset->id.'-'.str_random(8); - $filename .= '-'.str_slug(basename($file->getClientOriginalName(), '.'.$extension)).'.'.$extension; - - $file->storeAs('storage/private_uploads/assets', $filename); - $asset->logUpload($filename, e($request->get('notes'))); + $file_name = 'hardware-'.$asset->id.'-'.str_random(8).'-'.str_slug(basename($file->getClientOriginalName(), '.'.$extension)).'.'.$extension; + Storage::put('private_uploads/assets/'.$file_name, $file); + $asset->logUpload($file_name, e($request->get('notes'))); } return redirect()->back()->with('success', trans('admin/hardware/message.upload.success')); } @@ -67,24 +68,25 @@ class AssetFilesController extends Controller ->header('Content-Type', 'text/plain'); } - $file = $log->get_src('assets'); + $file = 'private_uploads/assets/'.$log->filename; + \Log::debug('Checking for '.$file); if ($log->action_type =='audit') { - $file = $log->get_src('audits'); + $file = 'private_uploads/audits/'.$log->filename; } - if (!file_exists($file)) { + if (!Storage::exists($file)) { return response('File '.$file.' not found on server', 404) ->header('Content-Type', 'text/plain'); } if ($download != 'true') { - if ($contents = file_get_contents($file)) { - return Response::make($contents)->header('Content-Type', mime_content_type($file)); + if ($contents = file_get_contents(Storage::url($file))) { + return Response::make(Storage::url($file)->header('Content-Type', mime_content_type($file))); } return JsonResponse::create(["error" => "Failed validation: "], 500); } - return Response::download($file); + return Storage::download($file); } // Prepare the error message $error = trans('admin/hardware/message.does_not_exist', ['id' => $fileId]); @@ -114,7 +116,7 @@ class AssetFilesController extends Controller $this->authorize('update', $asset); $log = Actionlog::find($fileId); if (file_exists(base_path().'/'.$rel_path.'/'.$log->filename)) { - Storage::delete($rel_path.'/'.$log->filename); + Storage::disk('public')->delete($rel_path.'/'.$log->filename); } $log->delete(); return redirect()->back() diff --git a/app/Http/Controllers/Assets/AssetsController.php b/app/Http/Controllers/Assets/AssetsController.php index ce0fa18862..1baf6235a7 100755 --- a/app/Http/Controllers/Assets/AssetsController.php +++ b/app/Http/Controllers/Assets/AssetsController.php @@ -3,7 +3,7 @@ namespace App\Http\Controllers\Assets; use App\Helpers\Helper; use App\Http\Controllers\Controller; -use App\Http\Requests\AssetRequest; +use App\Http\Requests\ImageUploadRequest; use App\Models\Actionlog; use App\Models\Asset; use App\Models\AssetModel; @@ -33,6 +33,7 @@ use TCPDF; use Validator; use View; use App\Models\CheckoutRequest; +use Illuminate\Support\Facades\Storage; /** * This class controls all actions related to assets for @@ -106,7 +107,7 @@ class AssetsController extends Controller * @since [v1.0] * @return Redirect */ - public function store(AssetRequest $request) + public function store(ImageUploadRequest $request) { $this->authorize(Asset::class); @@ -138,48 +139,14 @@ class AssetsController extends Controller $asset->location_id = $request->input('rtd_location_id', null); } - // Create the image (if one was chosen.) - if ($request->hasFile('image')) { - $image = $request->input('image'); - - // After modification, the image is prefixed by mime info like the following: - // data:image/jpeg;base64,; This causes the image library to be unhappy, so we need to remove it. - $header = explode(';', $image, 2)[0]; - // Grab the image type from the header while we're at it. - $extension = substr($header, strpos($header, '/')+1); - // Start reading the image after the first comma, postceding the base64. - $image = substr($image, strpos($image, ',')+1); - - $file_name = str_random(25).".".$extension; - - $directory= public_path('uploads/assets/'); - // Check if the uploads directory exists. If not, try to create it. - if (!file_exists($directory)) { - mkdir($directory, 0755, true); - } - $path = public_path('uploads/assets/'.$file_name); - try { - Image::make($image)->resize(500, 500, function ($constraint) { - $constraint->aspectRatio(); - $constraint->upsize(); - })->save($path); - $asset->image = $file_name; - } catch (\Exception $e) { - \Input::flash(); - $messageBag = new \Illuminate\Support\MessageBag(); - $messageBag->add('image', $e->getMessage()); - \Session()->flash('errors', \Session::get('errors', new \Illuminate\Support\ViewErrorBag) - ->put('default', $messageBag)); - return response()->json(['image' => $e->getMessage()], 422); - } - } + $asset = $request->handleImages($asset); // Update custom fields in the database. // Validation for these fields is handled through the AssetRequest form request $model = AssetModel::find($request->get('model_id')); - if ($model->fieldset) { + if (($model) && ($model->fieldset)) { foreach ($model->fieldset->fields as $field) { if ($field->field_encrypted=='1') { if (Gate::allows('admin')) { @@ -210,12 +177,11 @@ class AssetsController extends Controller $asset->checkOut($target, Auth::user(), date('Y-m-d H:i:s'), '', 'Checked out on asset creation', e($request->get('name')), $location); } // Redirect to the asset listing page - \Session::flash('success', trans('admin/hardware/message.create.success')); - return response()->json(['redirect_url' => route('hardware.index')]); + return redirect()->route('hardware.index') + ->with('success', trans('admin/hardware/message.create.success')); } - \Input::flash(); - \Session::flash('errors', $asset->getErrors()); - return response()->json(['errors' => $asset->getErrors()], 500); + return redirect()->back()->withInput()->withErrors($asset->getErrors()); + } /** @@ -293,7 +259,7 @@ class AssetsController extends Controller * @return Redirect */ - public function update(AssetRequest $request, $assetId = null) + public function update(ImageUploadRequest $request, $assetId = null) { // Check if the asset exists if (!$asset = Asset::find($assetId)) { @@ -338,38 +304,7 @@ class AssetsController extends Controller $asset->notes = $request->input('notes'); $asset->physical = '1'; - // Update the image - if ($request->filled('image')) { - $image = $request->input('image'); - // See postCreate for more explaination of the following. - $header = explode(';', $image, 2)[0]; - $extension = substr($header, strpos($header, '/')+1); - $image = substr($image, strpos($image, ',')+1); - - $directory= public_path('uploads/assets/'); - // Check if the uploads directory exists. If not, try to create it. - if (!file_exists($directory)) { - mkdir($directory, 0755, true); - } - - $file_name = str_random(25).".".$extension; - $path = public_path('uploads/assets/'.$file_name); - try { - Image::make($image)->resize(500, 500, function ($constraint) { - $constraint->aspectRatio(); - $constraint->upsize(); - })->save($path); - $asset->image = $file_name; - } catch (\Exception $e) { - \Input::flash(); - $messageBag = new \Illuminate\Support\MessageBag(); - $messageBag->add('image', $e->getMessage()); - \Session()->flash('errors', \Session::get('errors', new \Illuminate\Support\ViewErrorBag) - ->put('default', $messageBag)); - return response()->json(['image' => $e->getMessage()], 422); - } - $asset->image = $file_name; - } + $asset = $request->handleImages($asset); // Update custom fields in the database. // Validation for these fields is handlded through the AssetRequest form request @@ -421,6 +356,14 @@ class AssetsController extends Controller ->where('id', $asset->id) ->update(array('assigned_to' => null)); + if ($asset->image) { + try { + Storage::disk('public')->delete('assets'.'/'.$asset->image); + } catch (\Exception $e) { + \Log::debug($e); + } + } + $asset->delete(); return redirect()->route('hardware.index')->with('success', trans('admin/hardware/message.delete.success')); @@ -740,7 +683,7 @@ class AssetsController extends Controller } - public function auditStore(AssetFileRequest $request, $id) + public function auditStore(Request $request, $id) { $this->authorize('audit', Asset::class); @@ -773,22 +716,15 @@ class AssetsController extends Controller if ($asset->save()) { + $path = 'private_uploads/audits'; + if (!Storage::exists($path)) Storage::makeDirectory($path, 775); - $filename = ''; + $upload = $image = $request->file('image'); + $ext = $image->getClientOriginalExtension(); + $file_name = 'audit-'.str_random(18).'.'.$ext; + Storage::putFileAs($path, $upload, $file_name); - if ($request->hasFile('image')) { - $file = $request->file('image'); - try { - $destinationPath = config('app.private_uploads').'/audits'; - $extension = $file->getClientOriginalExtension(); - $filename = 'audit-'.$asset->id.'-'.str_slug(basename($file->getClientOriginalName(), '.'.$extension)).'.'.$extension; - $file->move($destinationPath, $filename); - } catch (\Exception $e) { - \Log::error($e); - } - } - - $asset->logAudit($request->input('note'), $request->input('location_id'), $filename); + $asset->logAudit($request->input('note'), $request->input('location_id'), $file_name); return redirect()->to("hardware")->with('success', trans('admin/hardware/message.audit.success')); } } diff --git a/app/Http/Controllers/CategoriesController.php b/app/Http/Controllers/CategoriesController.php index 2de5fd9a50..bc643841e9 100755 --- a/app/Http/Controllers/CategoriesController.php +++ b/app/Http/Controllers/CategoriesController.php @@ -17,6 +17,7 @@ use Str; use View; use Image; use App\Http\Requests\ImageUploadRequest; +use Illuminate\Support\Facades\Storage; /** * This class controls all actions related to Categories for @@ -182,7 +183,7 @@ class CategoriesController extends Controller return redirect()->route('categories.index')->with('error', trans('admin/categories/message.assoc_items', ['asset_type'=>'component'])); } - + Storage::disk('public')->delete('categories'.'/'.$category->image); $category->delete(); // Redirect to the locations management page return redirect()->route('categories.index')->with('success', trans('admin/categories/message.delete.success')); diff --git a/app/Http/Controllers/CompaniesController.php b/app/Http/Controllers/CompaniesController.php index 2ca0d15499..1e6a8473d3 100644 --- a/app/Http/Controllers/CompaniesController.php +++ b/app/Http/Controllers/CompaniesController.php @@ -5,6 +5,7 @@ use App\Models\Company; use Illuminate\Http\Request; use Image; use App\Http\Requests\ImageUploadRequest; +use Illuminate\Support\Facades\Storage; /** * This controller handles all actions related to Companies for @@ -142,6 +143,15 @@ final class CompaniesController extends Controller } try { + + if ($company->image) { + try { + Storage::disk('public')->delete('companies'.'/'.$company->image); + } catch (\Exception $e) { + \Log::debug($e); + } + } + $company->delete(); return redirect()->route('companies.index') ->with('success', trans('admin/companies/message.delete.success')); diff --git a/app/Http/Controllers/Components/ComponentsController.php b/app/Http/Controllers/Components/ComponentsController.php index 9e7d5d5a3a..6839e1604d 100644 --- a/app/Http/Controllers/Components/ComponentsController.php +++ b/app/Http/Controllers/Components/ComponentsController.php @@ -7,6 +7,7 @@ use App\Models\Company; use App\Models\Component; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Input; +use Illuminate\Support\Facades\Storage; /** * This class controls all actions related to Components for @@ -159,6 +160,16 @@ class ComponentsController extends Controller } $this->authorize('delete', $component); + + // Remove the image if one exists + if (Storage::disk('public')->exists('components/'.$component->image)) { + try { + Storage::disk('public')->delete('components/'.$component->image); + } catch (\Exception $e) { + \Log::debug($e); + } + } + $component->delete(); return redirect()->route('components.index')->with('success', trans('admin/components/message.delete.success')); } diff --git a/app/Http/Controllers/DepartmentsController.php b/app/Http/Controllers/DepartmentsController.php index 0922c41255..4afcd2a5a9 100644 --- a/app/Http/Controllers/DepartmentsController.php +++ b/app/Http/Controllers/DepartmentsController.php @@ -7,6 +7,7 @@ use App\Models\Department; use Illuminate\Support\Facades\Auth; use Image; use App\Http\Requests\ImageUploadRequest; +use Illuminate\Support\Facades\Storage; class DepartmentsController extends Controller { @@ -124,7 +125,15 @@ class DepartmentsController extends Controller return redirect()->to(route('departments.index'))->with('error', trans('admin/departments/message.assoc_users')); } + if ($department->image) { + try { + Storage::disk('public')->delete('departments'.'/'.$department->image); + } catch (\Exception $e) { + \Log::debug($e); + } + } $department->delete(); + return redirect()->back()->with('success', trans('admin/departments/message.delete.success')); } diff --git a/app/Http/Controllers/Licenses/LicenseFilesController.php b/app/Http/Controllers/Licenses/LicenseFilesController.php index a25b15ada2..4ff388335b 100644 --- a/app/Http/Controllers/Licenses/LicenseFilesController.php +++ b/app/Http/Controllers/Licenses/LicenseFilesController.php @@ -35,16 +35,20 @@ class LicenseFilesController extends Controller $this->authorize('update', $license); if (Input::hasFile('file')) { + + if (!Storage::exists('private_uploads/licenses')) Storage::makeDirectory('private_uploads/licenses', 775); + $upload_success = false; foreach (Input::file('file') as $file) { $extension = $file->getClientOriginalExtension(); - $filename = 'license-'.$license->id.'-'.str_random(8).'-'.str_slug(basename($file->getClientOriginalName(), '.'.$extension)).'.'.$extension; + $file_name = 'license-'.$license->id.'-'.str_random(8).'-'.str_slug(basename($file->getClientOriginalName(), '.'.$extension)).'.'.$extension; - $upload_success = $file->storeAs('storage/private_uploads/licenses', $filename); + $upload_success = Storage::put('private_uploads/licenses/'.$file_name, $file); //Log the upload to the log - $license->logUpload($filename, e($request->input('notes'))); + $license->logUpload($file_name, e($request->input('notes'))); } + // This being called from a modal seems to confuse redirect()->back() // It thinks we should go to the dashboard. As this is only used // from the modal at present, hardcode the redirect. Longterm @@ -76,15 +80,20 @@ class LicenseFilesController extends Controller { $license = License::find($licenseId); - $rel_path = 'storage/private_uploads/licenses'; - // the asset is valid if (isset($license->id)) { $this->authorize('update', $license); $log = Actionlog::find($fileId); - if (file_exists(base_path().'/'.$rel_path.'/'.$log->filename)) { - Storage::delete($rel_path.'/'.$log->filename); + + // Remove the file if one exists + if (Storage::exists('licenses/'.$log->filename)) { + try { + Storage::delete('licenses/'.$log->filename); + } catch (\Exception $e) { + \Log::debug($e); + } } + $log->delete(); return redirect()->back() ->with('success', trans('admin/hardware/message.deletefile.success')); @@ -114,34 +123,30 @@ class LicenseFilesController extends Controller // the license is valid if (isset($license->id)) { $this->authorize('view', $license); - $log = Actionlog::find($fileId); - $file = $log->get_src('licenses'); - - if ($file =='') { - return response('File not found on server', 404) + if (!$log = Actionlog::find($fileId)) { + return response('No matching record for that asset/file', 500) ->header('Content-Type', 'text/plain'); } - $mimetype = \File::mimeType($file); + $file = 'private_uploads/licenses/'.$log->filename; + \Log::debug('Checking for '.$file); - - if (!file_exists($file)) { + if (!Storage::exists($file)) { return response('File '.$file.' not found on server', 404) ->header('Content-Type', 'text/plain'); } if ($download != 'true') { - if ($contents = file_get_contents($file)) { - return Response::make($contents)->header('Content-Type', $mimetype); + if ($contents = file_get_contents(Storage::url($file))) { + return Response::make(Storage::url($file)->header('Content-Type', mime_content_type($file))); } return JsonResponse::create(["error" => "Failed validation: "], 500); } - return Response::download($file); + return Storage::download($file); } + return redirect()->route('hardware.index')->with('error', trans('admin/licenses/message.does_not_exist', ['id' => $fileId])); - - return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.does_not_exist')); } diff --git a/app/Http/Controllers/LocationsController.php b/app/Http/Controllers/LocationsController.php index 87ff779eb4..9314ede8b6 100755 --- a/app/Http/Controllers/LocationsController.php +++ b/app/Http/Controllers/LocationsController.php @@ -6,6 +6,7 @@ use App\Models\Location; use Illuminate\Support\Facades\Auth; use Image; use App\Http\Requests\ImageUploadRequest; +use Illuminate\Support\Facades\Storage; /** * This controller handles all actions related to Locations for @@ -89,7 +90,7 @@ class LocationsController extends Controller $location->manager_id = $request->input('manager_id'); $location->user_id = Auth::id(); - $location = $request->handleImages($location); + $location = $request->handleImages($location, 'public/uploads/locations'); if ($location->save()) { return redirect()->route("locations.index")->with('success', trans('admin/locations/message.create.success')); @@ -159,7 +160,7 @@ class LocationsController extends Controller $location->ldap_ou = $request->input('ldap_ou'); $location->manager_id = $request->input('manager_id'); - $location = $request->handleImages($location); + $location = $request->handleImages($location, 'public/uploads/locations'); if ($location->save()) { @@ -198,6 +199,13 @@ class LocationsController extends Controller } + if ($location->image) { + try { + Storage::disk('public')->delete('locations/'.$location->image); + } catch (\Exception $e) { + \Log::error($e); + } + } $location->delete(); return redirect()->to(route('locations.index'))->with('success', trans('admin/locations/message.delete.success')); } diff --git a/app/Http/Controllers/ManufacturersController.php b/app/Http/Controllers/ManufacturersController.php index 1bbd4466d4..c99ac10d95 100755 --- a/app/Http/Controllers/ManufacturersController.php +++ b/app/Http/Controllers/ManufacturersController.php @@ -7,6 +7,7 @@ use Illuminate\Support\Facades\Auth; use Redirect; use Illuminate\Http\Request; use Image; +use Illuminate\Support\Facades\Storage; /** * This controller handles all actions related to Manufacturers for @@ -72,7 +73,7 @@ class ManufacturersController extends Controller $manufacturer->support_email = $request->input('support_email'); - $manufacturer = $request->handleImages($manufacturer); + $manufacturer = $request->handleImages($manufacturer,'manufacturers'); @@ -162,9 +163,9 @@ class ManufacturersController extends Controller if ($manufacturer->image) { try { - unlink(public_path().'/uploads/manufacturers/'.$manufacturer->image); + Storage::disk('public')->delete('manufacturers/'.$manufacturer->image); } catch (\Exception $e) { - + \Log::error($e); } } diff --git a/app/Http/Controllers/ProfileController.php b/app/Http/Controllers/ProfileController.php index 492b65db0b..5b0a06ede3 100755 --- a/app/Http/Controllers/ProfileController.php +++ b/app/Http/Controllers/ProfileController.php @@ -12,6 +12,7 @@ use Gate; use Illuminate\Http\Request; use Illuminate\Support\Facades\Hash; use App\Http\Requests\ImageUploadRequest; +use Illuminate\Support\Facades\Storage; /** * This controller handles all actions related to User Profiles for @@ -61,18 +62,38 @@ class ProfileController extends Controller if (Gate::allows('self.edit_location') && (!config('app.lock_passwords'))) { $user->location_id = $request->input('location_id'); } - - if (Input::file('avatar')) { - $image = Input::file('avatar'); - $file_name = str_slug($user->first_name."-".$user->last_name).".".$image->getClientOriginalExtension(); - $path = public_path('uploads/avatars/'.$file_name); - Image::make($image->getRealPath())->resize(84, 84)->save($path); + + + if ($request->input('avatar_delete') == 1) { + $user->avatar = null; + } + + + if ($request->hasFile('avatar')) { + $path = 'avatars'; + + if(!Storage::disk('public')->exists($path)) Storage::disk('public')->makeDirectory($path, 775); + + $upload = $image = $request->file('avatar'); + $ext = $image->getClientOriginalExtension(); + $file_name = 'avatar-'.str_random(18).'.'.$ext; + + if ($image->getClientOriginalExtension()!='svg') { + $upload = Image::make($image->getRealPath())->resize(84, 84); + } + + // This requires a string instead of an object, so we use ($string) + Storage::disk('public')->put($path.'/'.$file_name, (string)$upload->encode()); + + // Remove Current image if exists + if (($user->avatar) && (Storage::disk('public')->exists($path.'/'.$user->avatar))) { + Storage::disk('public')->delete($path.'/'.$user->avatar); + } + $user->avatar = $file_name; } - if (Input::get('avatar_delete') == 1 && Input::file('avatar') == "") { - $user->avatar = null; - } + if ($user->save()) { return redirect()->route('profile')->with('success', 'Account successfully updated'); diff --git a/app/Http/Controllers/SettingsController.php b/app/Http/Controllers/SettingsController.php index 90391a23f8..067bbd5624 100755 --- a/app/Http/Controllers/SettingsController.php +++ b/app/Http/Controllers/SettingsController.php @@ -24,6 +24,7 @@ use App\Http\Requests\ImageUploadRequest; use App\Http\Requests\SettingsLdapRequest; use App\Helpers\Helper; use App\Notifications\FirstAdminNotification; +use Illuminate\Support\Facades\Storage; /** * This controller handles all actions related to Settings for @@ -418,25 +419,32 @@ class SettingsController extends Controller // If the user wants to clear the logo, reset the brand type if ($request->input('clear_logo')=='1') { + Storage::disk('public')->delete($setting->logo); $setting->logo = null; $setting->brand = 1; + // If they are uploading an image, validate it and upload it } elseif ($request->hasFile('image')) { - if (!config('app.lock_passwords')) { - $image = $request->file('image'); - $file_name = "logo.".$image->getClientOriginalExtension(); - $path = public_path('uploads'); - if ($image->getClientOriginalExtension()!='svg') { - Image::make($image->getRealPath())->resize(null, 150, function ($constraint) { - $constraint->aspectRatio(); - $constraint->upsize(); - })->save($path.'/'.$file_name); - } else { - $image->move($path, $file_name); - } - $setting->logo = $file_name; + $image = $request->file('image'); + $ext = $image->getClientOriginalExtension(); + $setting->logo = $file_name = 'logo.'.$ext; + + if ($image->getClientOriginalExtension()!='svg') { + $upload = Image::make($image->getRealPath())->resize(null, 150, function ($constraint) { + $constraint->aspectRatio(); + $constraint->upsize(); + }); + } + + + // This requires a string instead of an object, so we use ($string) + Storage::disk('public')->put($file_name, (string)$upload->encode()); + + // Remove Current image if exists + if (($setting->logo) && (file_exists($file_name))) { + Storage::disk('public')->delete($file_name); } } @@ -911,29 +919,22 @@ class SettingsController extends Controller public function getBackups() { - $path = storage_path().'/app/'.config('backup.backup.name'); + $path = 'backups'; + $backup_files = Storage::files($path); + $files = []; - $files = array(); + if (count($backup_files) > 0) { - if ($handle = opendir($path)) { - - /* This is the correct way to loop over the directory. */ - while (false !== ($entry = readdir($handle))) { - clearstatcache(); - if (substr(strrchr($entry, '.'), 1)=='zip') { - $files[] = array( - 'filename' => $entry, - 'filesize' => Setting::fileSizeConvert(filesize($path.'/'.$entry)), - 'modified' => filemtime($path.'/'.$entry) - ); - } + for ($f = 0; $f < count($backup_files); $f++) { + $files[] = array( + 'filename' => basename($backup_files[$f]), + 'filesize' => Setting::fileSizeConvert(Storage::size($backup_files[$f])), + 'modified' => Storage::lastModified($backup_files[$f]) + ); } - closedir($handle); - rsort($files); } - return view('settings/backups', compact('path', 'files')); } @@ -987,12 +988,10 @@ class SettingsController extends Controller public function downloadFile($filename = null) { if (!config('app.lock_passwords')) { - $path = storage_path().'/app/'.config('backup.backup.name'); - $file = $path.'/'.$filename; - if (file_exists($file)) { - return Response::download($file); - } else { + if (Storage::exists($filename)) { + return Response::download(Storage::url('').e($filename)); + } else { // Redirect to the backup page return redirect()->route('settings.backups.index')->with('error', trans('admin/settings/message.backup.file_not_found')); } @@ -1013,14 +1012,17 @@ class SettingsController extends Controller */ public function deleteFile($filename = null) { - if (!config('app.lock_passwords')) { + $path = 'backups'; + + if (Storage::exists($path.'/'.$filename)) { + try { + Storage::delete($path.'/'.$filename); + return redirect()->route('settings.backups.index')->with('success', trans('admin/settings/message.backup.file_deleted')); + } catch (\Exception $e) { + \Log::debug($e); + } - $path = storage_path().'/app/'.config('backup.backup.name'); - $file = $path.'/'.$filename; - if (file_exists($file)) { - unlink($file); - return redirect()->route('settings.backups.index')->with('success', trans('admin/settings/message.backup.file_deleted')); } else { return redirect()->route('settings.backups.index')->with('error', trans('admin/settings/message.backup.file_not_found')); } diff --git a/app/Http/Controllers/SuppliersController.php b/app/Http/Controllers/SuppliersController.php index 5af0097ee3..985c2d892a 100755 --- a/app/Http/Controllers/SuppliersController.php +++ b/app/Http/Controllers/SuppliersController.php @@ -6,6 +6,7 @@ use App\Models\Supplier; use Illuminate\Support\Facades\Auth; use Illuminate\Http\Request; use App\Http\Requests\ImageUploadRequest; +use Illuminate\Support\Facades\Storage; /** * This controller handles all actions related to Suppliers for diff --git a/app/Http/Requests/AssetRequest.php b/app/Http/Requests/AssetRequest.php deleted file mode 100644 index 4004dcec3f..0000000000 --- a/app/Http/Requests/AssetRequest.php +++ /dev/null @@ -1,68 +0,0 @@ - 'max:255|nullable', - 'model_id' => 'required|integer|exists:models,id', - 'status_id' => 'required|integer|exists:status_labels,id', - 'company_id' => 'integer|nullable', - 'warranty_months' => 'numeric|nullable', - 'physical' => 'integer|nullable', - 'checkout_date' => 'date', - 'checkin_date' => 'date', - 'supplier_id' => 'integer|nullable', - 'status' => 'integer|nullable', - 'purchase_cost' => 'numeric|nullable', - "assigned_user" => 'sometimes:required_without_all:assigned_asset,assigned_location', - "assigned_asset" => 'sometimes:required_without_all:assigned_user,assigned_location', - "assigned_location" => 'sometimes:required_without_all:assigned_user,assigned_asset', - ]; - - $settings = \App\Models\Setting::getSettings(); - - $rules['asset_tag'] = ($settings->auto_increment_assets == '1') ? 'max:255' : 'required'; - - if($this->request->get('model_id') != '') { - $model = AssetModel::find($this->request->get('model_id')); - - if (($model) && ($model->fieldset)) { - $rules += $model->fieldset->validation_rules(); - } - } - - return $rules; - - } - - public function response(array $errors) - { - $this->session()->flash('errors', Session::get('errors', new \Illuminate\Support\ViewErrorBag) - ->put('default', new \Illuminate\Support\MessageBag($errors))); - \Input::flash(); - return parent::response($errors); - } -} diff --git a/app/Http/Requests/ImageUploadRequest.php b/app/Http/Requests/ImageUploadRequest.php index a01df7b4f5..19a5453316 100644 --- a/app/Http/Requests/ImageUploadRequest.php +++ b/app/Http/Requests/ImageUploadRequest.php @@ -4,6 +4,8 @@ namespace App\Http\Requests; use App\Models\SnipeModel; use Intervention\Image\Facades\Image; +use Storage; +use Illuminate\Support\Facades\File; class ImageUploadRequest extends Request { @@ -41,36 +43,44 @@ class ImageUploadRequest extends Request * @param String $path location for uploaded images, defaults to uploads/plural of item type. * @return SnipeModel Target asset is being checked out to. */ - public function handleImages($item, $path = null) + public function handleImages($item, $w = 550, $path = null) { + $type = strtolower(class_basename(get_class($item))); + + if(is_null($path)) { + $path = str_plural($type); + } + + if ($this->hasFile('image')) { if (!config('app.lock_passwords')) { - if(is_null($path)) { - $type = strtolower(class_basename(get_class($item))); - $plural = str_plural($type); - $path = public_path('/uploads/'.$plural); - } - $image = $this->file('image'); + + if(!Storage::disk('public')->exists($path)) Storage::disk('public')->makeDirectory($path, 775); + + $upload = $image = $this->file('image'); $ext = $image->getClientOriginalExtension(); $file_name = $type.'-'.str_random(18).'.'.$ext; + if ($image->getClientOriginalExtension()!='svg') { - Image::make($image->getRealPath())->resize(null, 250, function ($constraint) { + $upload = Image::make($image->getRealPath())->resize(null, $w, function ($constraint) { $constraint->aspectRatio(); $constraint->upsize(); - })->save($path.'/'.$file_name); - } else { - $image->move($path, $file_name); + }); } - // Remove Current image if exists. + // This requires a string instead of an object, so we use ($string) + Storage::disk('public')->put($path.'/'.$file_name, (string)$upload->encode()); + + // Remove Current image if exists if (($item->image) && (file_exists($path.'/'.$item->image))) { - unlink($path.'/'.$item->image); + Storage::disk('public')->delete($path.'/'.$file_name); } $item->image = $file_name; } } elseif ($this->input('image_delete')=='1') { + Storage::disk('public')->delete($path.'/'.$item->image); $item->image = null; } return $item; diff --git a/app/Http/Transformers/AccessoriesTransformer.php b/app/Http/Transformers/AccessoriesTransformer.php index a4e935dab1..1f828bd1eb 100644 --- a/app/Http/Transformers/AccessoriesTransformer.php +++ b/app/Http/Transformers/AccessoriesTransformer.php @@ -5,6 +5,7 @@ use App\Models\Accessory; use Gate; use Illuminate\Database\Eloquent\Collection; use App\Helpers\Helper; +use Illuminate\Support\Facades\Storage; class AccessoriesTransformer { @@ -23,6 +24,7 @@ class AccessoriesTransformer $array = [ 'id' => $accessory->id, 'name' => e($accessory->name), + 'image' => ($accessory->image) ? Storage::disk('public')->url('accessories/'.e($accessory->image)) : null, 'company' => ($accessory->company) ? ['id' => $accessory->company->id,'name'=> e($accessory->company->name)] : null, 'manufacturer' => ($accessory->manufacturer) ? ['id' => $accessory->manufacturer->id,'name'=> e($accessory->manufacturer->name)] : null, 'supplier' => ($accessory->supplier) ? ['id' => $accessory->supplier->id,'name'=> e($accessory->supplier->name)] : null, @@ -36,7 +38,7 @@ class AccessoriesTransformer 'order_number' => ($accessory->order_number) ? e($accessory->order_number) : null, 'min_qty' => ($accessory->min_amt) ? (int) $accessory->min_amt : null, 'remaining_qty' => $accessory->numRemaining(), - 'image' => ($accessory->image) ? url('/').'/uploads/accessories/'.e($accessory->image) : null, + 'created_at' => Helper::getFormattedDateObject($accessory->created_at, 'datetime'), 'updated_at' => Helper::getFormattedDateObject($accessory->updated_at, 'datetime'), diff --git a/app/Http/Transformers/ActionlogsTransformer.php b/app/Http/Transformers/ActionlogsTransformer.php index 53ece05583..c5ea16f598 100644 --- a/app/Http/Transformers/ActionlogsTransformer.php +++ b/app/Http/Transformers/ActionlogsTransformer.php @@ -63,7 +63,7 @@ class ActionlogsTransformer ] : null, 'note' => ($actionlog->note) ? e($actionlog->note): null, - 'signature_file' => ($actionlog->accept_signature) ? route('log.signature.view', ['filename' => $actionlog->accept_signature ]) : null, + 'signature_file' => ($actionlog->signature_filename) ? route('log.signature.view', ['filename' => $actionlog->signature_filename ]) : null, 'log_meta' => ($actionlog->log_meta) ? json_decode($actionlog->log_meta): null, diff --git a/app/Http/Transformers/AssetModelsTransformer.php b/app/Http/Transformers/AssetModelsTransformer.php index 2bb0a9e1a9..a344e76d03 100644 --- a/app/Http/Transformers/AssetModelsTransformer.php +++ b/app/Http/Transformers/AssetModelsTransformer.php @@ -5,6 +5,7 @@ use App\Models\AssetModel; use Illuminate\Database\Eloquent\Collection; use Gate; use App\Helpers\Helper; +use Illuminate\Support\Facades\Storage; class AssetModelsTransformer { @@ -28,7 +29,7 @@ class AssetModelsTransformer 'id' => (int) $assetmodel->manufacturer->id, 'name'=> e($assetmodel->manufacturer->name) ] : null, - 'image' => ($assetmodel->image!='') ? app('models_upload_url').e($assetmodel->image) : null, + 'image' => ($assetmodel->image!='') ? Storage::disk('public')->url('assetmodels/'.e($assetmodel->image)) : null, 'model_number' => e($assetmodel->model_number), 'depreciation' => ($assetmodel->depreciation) ? [ 'id' => (int) $assetmodel->depreciation->id, diff --git a/app/Http/Transformers/CategoriesTransformer.php b/app/Http/Transformers/CategoriesTransformer.php index 710bf84bc5..b93790f771 100644 --- a/app/Http/Transformers/CategoriesTransformer.php +++ b/app/Http/Transformers/CategoriesTransformer.php @@ -5,6 +5,7 @@ use App\Models\Category; use Illuminate\Database\Eloquent\Collection; use Gate; use App\Helpers\Helper; +use Illuminate\Support\Facades\Storage; class CategoriesTransformer { @@ -25,7 +26,7 @@ class CategoriesTransformer $array = [ 'id' => (int) $category->id, 'name' => e($category->name), - 'image' => ($category->image) ? app('categories_upload_url').e($category->image) : null, + 'image' => ($category->image) ? Storage::disk('public')->url('categories/'.e($category->image)) : null, 'category_type' => e($category->category_type), 'eula' => ($category->getEula()) ? true : false, 'checkin_email' => ($category->checkin_email =='1') ? true : false, diff --git a/app/Http/Transformers/CompaniesTransformer.php b/app/Http/Transformers/CompaniesTransformer.php index 96951bdf85..7fac8ee6d0 100644 --- a/app/Http/Transformers/CompaniesTransformer.php +++ b/app/Http/Transformers/CompaniesTransformer.php @@ -5,6 +5,7 @@ use App\Models\Company; use Illuminate\Database\Eloquent\Collection; use Gate; use App\Helpers\Helper; +use Illuminate\Support\Facades\Storage; class CompaniesTransformer { @@ -25,7 +26,7 @@ class CompaniesTransformer $array = [ 'id' => (int) $company->id, 'name' => e($company->name), - 'image' => ($company->image) ? app('companies_upload_url').e($company->image) : null, + 'image' => ($company->image) ? Storage::disk('public')->url('companies/'.e($company->image)) : null, "created_at" => Helper::getFormattedDateObject($company->created_at, 'datetime'), "updated_at" => Helper::getFormattedDateObject($company->updated_at, 'datetime'), "assets_count" => (int) $company->assets_count, diff --git a/app/Http/Transformers/ComponentsTransformer.php b/app/Http/Transformers/ComponentsTransformer.php index cf51b55d79..6cd4b98c70 100644 --- a/app/Http/Transformers/ComponentsTransformer.php +++ b/app/Http/Transformers/ComponentsTransformer.php @@ -5,6 +5,7 @@ use App\Models\Component; use Illuminate\Database\Eloquent\Collection; use App\Helpers\Helper; use Gate; +use Illuminate\Support\Facades\Storage; class ComponentsTransformer { @@ -22,7 +23,7 @@ class ComponentsTransformer $array = [ 'id' => (int) $component->id, 'name' => e($component->name), - 'image' => ($component->image) ? e(url('/').'/uploads/components/'.e($component->image)) : null, + 'image' => ($component->image) ? Storage::disk('public')->url('components/'.e($component->image)) : null, 'serial' => ($component->serial) ? e($component->serial) : null, 'location' => ($component->location) ? [ 'id' => (int) $component->location->id, diff --git a/app/Http/Transformers/ConsumablesTransformer.php b/app/Http/Transformers/ConsumablesTransformer.php index 3d68697a58..36ec8d9c24 100644 --- a/app/Http/Transformers/ConsumablesTransformer.php +++ b/app/Http/Transformers/ConsumablesTransformer.php @@ -5,6 +5,7 @@ use App\Models\Consumable; use Illuminate\Database\Eloquent\Collection; use App\Helpers\Helper; use Gate; +use Illuminate\Support\Facades\Storage; class ConsumablesTransformer { @@ -23,7 +24,7 @@ class ConsumablesTransformer $array = [ 'id' => (int) $consumable->id, 'name' => e($consumable->name), - 'image' => ($consumable->image) ? e(url('/').'/uploads/consumables/'.e($consumable->image)) : null, + 'image' => ($consumable->image) ? Storage::disk('public')->url('consumables/'.e($consumable->image)) : null, 'category' => ($consumable->category) ? ['id' => $consumable->category->id, 'name' => e($consumable->category->name)] : null, 'company' => ($consumable->company) ? ['id' => (int) $consumable->company->id, 'name' => e($consumable->company->name)] : null, 'item_no' => e($consumable->item_no), diff --git a/app/Http/Transformers/DepartmentsTranformer.php b/app/Http/Transformers/DepartmentsTranformer.php index f81954f947..a24943b96e 100644 --- a/app/Http/Transformers/DepartmentsTranformer.php +++ b/app/Http/Transformers/DepartmentsTranformer.php @@ -5,6 +5,7 @@ use App\Models\Department; use Illuminate\Database\Eloquent\Collection; use Gate; use App\Helpers\Helper; +use Illuminate\Support\Facades\Storage; class DepartmentsTransformer { @@ -25,7 +26,7 @@ class DepartmentsTransformer $array = [ 'id' => (int) $department->id, 'name' => e($department->name), - 'image' => ($department->image) ? app('departments_upload_url').e($department->image) : null, + 'image' => ($department->image) ? Storage::disk('public')->url(app('departments_upload_url').e($department->image)) : null, 'company' => ($department->company) ? [ 'id' => (int) $department->company->id, 'name'=> e($department->company->name) diff --git a/app/Http/Transformers/LocationsTransformer.php b/app/Http/Transformers/LocationsTransformer.php index 5d93db4def..ce018d4f6c 100644 --- a/app/Http/Transformers/LocationsTransformer.php +++ b/app/Http/Transformers/LocationsTransformer.php @@ -5,6 +5,7 @@ use App\Models\Location; use Illuminate\Database\Eloquent\Collection; use Gate; use App\Helpers\Helper; +use Illuminate\Support\Facades\Storage; class LocationsTransformer { @@ -33,7 +34,7 @@ class LocationsTransformer $array = [ 'id' => (int) $location->id, 'name' => e($location->name), - 'image' => ($location->image) ? app('locations_upload_url').e($location->image) : null, + 'image' => ($location->image) ? Storage::disk('public')->url('locations/'.e($location->image)) : null, 'address' => ($location->address) ? e($location->address) : null, 'address2' => ($location->address2) ? e($location->address2) : null, 'city' => ($location->city) ? e($location->city) : null, diff --git a/app/Http/Transformers/ManufacturersTransformer.php b/app/Http/Transformers/ManufacturersTransformer.php index 3db65ee9f0..5457d1c947 100644 --- a/app/Http/Transformers/ManufacturersTransformer.php +++ b/app/Http/Transformers/ManufacturersTransformer.php @@ -5,6 +5,7 @@ use App\Models\Manufacturer; use Illuminate\Database\Eloquent\Collection; use Gate; use App\Helpers\Helper; +use Illuminate\Support\Facades\Storage; class ManufacturersTransformer { @@ -26,7 +27,7 @@ class ManufacturersTransformer 'id' => (int) $manufacturer->id, 'name' => e($manufacturer->name), 'url' => e($manufacturer->url), - 'image' => ($manufacturer->image) ? app('manufacturers_upload_url').e($manufacturer->image) : null, + 'image' => ($manufacturer->image) ? Storage::disk('public')->url('manufacturers/'.e($manufacturer->image)) : null, 'support_url' => e($manufacturer->support_url), 'support_phone' => e($manufacturer->support_phone), 'support_email' => e($manufacturer->support_email), diff --git a/app/Http/Transformers/SuppliersTransformer.php b/app/Http/Transformers/SuppliersTransformer.php index ea636e4a6c..a3bb8c6f27 100644 --- a/app/Http/Transformers/SuppliersTransformer.php +++ b/app/Http/Transformers/SuppliersTransformer.php @@ -5,6 +5,7 @@ use App\Models\Supplier; use Illuminate\Database\Eloquent\Collection; use Gate; use App\Helpers\Helper; +use Illuminate\Support\Facades\Storage; class SuppliersTransformer { @@ -25,7 +26,7 @@ class SuppliersTransformer $array = [ 'id' => (int) $supplier->id, 'name' => e($supplier->name), - 'image' => ($supplier->image) ? app('suppliers_upload_url').e($supplier->image) : null, + 'image' => ($supplier->image) ? Storage::disk('public')->url('suppliers/'.e($supplier->image)) : null, 'url' => e($supplier->url), 'address' => ($supplier->address) ? e($supplier->address) : null, 'address2' => ($supplier->address2) ? e($supplier->address2) : null, diff --git a/app/Models/Accessory.php b/app/Models/Accessory.php index 76b50704c6..41dee8ef13 100755 --- a/app/Models/Accessory.php +++ b/app/Models/Accessory.php @@ -8,6 +8,7 @@ use Illuminate\Database\Eloquent\SoftDeletes; use Watson\Validating\ValidatingTrait; use App\Notifications\CheckinAccessoryNotification; use App\Notifications\CheckoutAccessoryNotification; +use Illuminate\Support\Facades\Storage; /** * Model for Accessories. @@ -219,7 +220,7 @@ class Accessory extends SnipeModel */ public function getImageUrl() { if ($this->image) { - return url('/').'/uploads/accessories/'.$this->image; + return Storage::disk('public')->url(app('accessories_upload_path').$this->image); } return false; diff --git a/app/Models/Asset.php b/app/Models/Asset.php index c2d48cee2b..e0918d20ad 100644 --- a/app/Models/Asset.php +++ b/app/Models/Asset.php @@ -21,6 +21,7 @@ use Watson\Validating\ValidatingTrait; use DB; use App\Notifications\CheckinAssetNotification; use App\Notifications\CheckoutAssetNotification; +use Illuminate\Support\Facades\Storage; /** * Model for Assets. * @@ -159,7 +160,32 @@ class Asset extends Depreciable 'model' => ['name', 'model_number'], 'model.category' => ['name'], 'model.manufacturer' => ['name'], - ]; + ]; + + + /** + * This handles the custom field validation for assets + * + * @var array + */ + public function save($params = []) + { + $settings = \App\Models\Setting::getSettings(); + + // I don't remember why we have this here? Asset tag would always be required, even if auto increment is on... + $this->rules['asset_tag'] = ($settings->auto_increment_assets == '1') ? 'max:255' : 'required'; + + if($this->model_id != '') { + $model = AssetModel::find($this->model_id); + + if (($model) && ($model->fieldset)) { + $this->rules += $model->fieldset->validation_rules(); + } + } + + return parent::save($params); + } + public function getDisplayNameAttribute() { @@ -486,9 +512,9 @@ class Asset extends Depreciable public function getImageUrl() { if ($this->image && !empty($this->image)) { - return url('/').'/uploads/assets/'.$this->image; + return Storage::disk('public')->url(app('assets_upload_path').e($this->image)); } elseif ($this->model && !empty($this->model->image)) { - return url('/').'/uploads/models/'.$this->model->image; + return Storage::disk('public')->url(app('models_upload_path').e($this->model->image)); } return false; } diff --git a/app/Models/AssetModel.php b/app/Models/AssetModel.php index a570cd8c75..1998b277de 100755 --- a/app/Models/AssetModel.php +++ b/app/Models/AssetModel.php @@ -8,6 +8,7 @@ use App\Presenters\Presentable; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\SoftDeletes; use Watson\Validating\ValidatingTrait; +use Illuminate\Support\Facades\Storage; /** * Model for Asset Models. Asset Models contain higher level @@ -175,7 +176,7 @@ class AssetModel extends SnipeModel */ public function getImageUrl() { if ($this->image) { - return url('/').'/uploads/models/'.$this->image; + return Storage::disk('public')->url(app('models_upload_path').$this->image); } return false; } diff --git a/app/Models/Consumable.php b/app/Models/Consumable.php index 596106c262..853c524933 100644 --- a/app/Models/Consumable.php +++ b/app/Models/Consumable.php @@ -7,6 +7,7 @@ use App\Presenters\Presentable; use Illuminate\Database\Eloquent\SoftDeletes; use Watson\Validating\ValidatingTrait; use App\Notifications\CheckoutConsumableNotification; +use Illuminate\Support\Facades\Storage; class Consumable extends SnipeModel { @@ -203,7 +204,7 @@ class Consumable extends SnipeModel */ public function getImageUrl() { if ($this->image) { - return url('/').'/uploads/consumables/'.$this->image; + return Storage::disk('public')->url(app('consumables_upload_path').$this->image); } return false; diff --git a/app/Presenters/UserPresenter.php b/app/Presenters/UserPresenter.php index 0d49852263..cc6c16968f 100644 --- a/app/Presenters/UserPresenter.php +++ b/app/Presenters/UserPresenter.php @@ -6,6 +6,7 @@ use App\Helpers\Helper; use App\Models\Setting; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Gate; +use Illuminate\Support\Facades\Storage; /** * Class UserPresenter @@ -320,7 +321,7 @@ class UserPresenter extends Presenter { if ($this->avatar) { - return config('app.url').'/uploads/avatars/'.$this->avatar; + return Storage::disk('public')->url('avatars/'.$this->avatar, $this->avatar); } if ((Setting::getSettings()->load_remote=='1') && ($this->email!='')) { diff --git a/app/Providers/SettingsServiceProvider.php b/app/Providers/SettingsServiceProvider.php index ed965bf9c7..63ed2e68ed 100644 --- a/app/Providers/SettingsServiceProvider.php +++ b/app/Providers/SettingsServiceProvider.php @@ -39,76 +39,85 @@ class SettingsServiceProvider extends ServiceProvider * Set some common variables so that they're globally available. * The paths should always be public (versus private uploads) */ + + + // Model paths and URLs + + \App::singleton('assets_upload_path', function(){ + return 'assets/'; + }); + + \App::singleton('models_upload_path', function(){ - return public_path('/uploads/models/'); + return 'assetmodels/'; }); \App::singleton('models_upload_url', function(){ - return url('/').'/uploads/models/'; + return 'assetmodels/'; }); // Categories \App::singleton('categories_upload_path', function(){ - return public_path('/uploads/categories/'); + return 'categories/'; }); \App::singleton('categories_upload_url', function(){ - return url('/').'/uploads/categories/'; + return 'categories/'; }); // Locations \App::singleton('locations_upload_path', function(){ - return public_path('/uploads/locations/'); + return 'locations/'; }); \App::singleton('locations_upload_url', function(){ - return url('/').'/uploads/locations/'; + return 'storage/public_uploads/locations/'; }); // Users \App::singleton('users_upload_path', function(){ - return public_path('/uploads/users/'); + return 'users/'; }); \App::singleton('users_upload_url', function(){ - return url('/').'/uploads/users/'; + return 'public_uploads/users/'; }); // Manufacturers \App::singleton('manufacturers_upload_path', function(){ - return public_path('/uploads/manufacturers/'); + return 'manufacturers/'; }); \App::singleton('manufacturers_upload_url', function(){ - return url('/').'/uploads/manufacturers/'; + return 'public_uploads/manufacturers/'; }); // Suppliers \App::singleton('suppliers_upload_path', function(){ - return public_path('/uploads/suppliers/'); + return 'suppliers/'; }); \App::singleton('suppliers_upload_url', function(){ - return url('/').'/uploads/suppliers/'; + return 'storage/public_uploads/suppliers/'; }); // Departments \App::singleton('departments_upload_path', function(){ - return public_path('/uploads/departments/'); + return 'departments/'; }); \App::singleton('departments_upload_url', function(){ - return url('/').'/uploads/departments/'; + return 'departments/'; }); // Company paths and URLs \App::singleton('companies_upload_path', function(){ - return public_path('/uploads/companies/'); + return 'companies/'; }); \App::singleton('companies_upload_url', function(){ - return url('/').'/uploads/companies/'; + return 'storage/public_uploads/companies/'; }); diff --git a/composer.json b/composer.json index 41e35cdf92..d927040775 100644 --- a/composer.json +++ b/composer.json @@ -24,6 +24,7 @@ "league/csv": "^9.0", "league/flysystem-aws-s3-v3": "~1.0", "league/flysystem-cached-adapter": "~1.0", + "league/flysystem-rackspace": "^1.0", "league/flysystem-sftp": "~1.0", "maknz/slack": "^1.7", "neitanod/forceutf8": "^2.0", diff --git a/composer.lock b/composer.lock index 027871bbde..d18eed45cd 100644 --- a/composer.lock +++ b/composer.lock @@ -4,20 +4,20 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "94a7bad067cd5d3ea24175dce2f318d6", + "content-hash": "1b2d866e20b5d160ea9d055221d1fec4", "packages": [ { "name": "aws/aws-sdk-php", - "version": "3.67.7", + "version": "3.67.22", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "002577f67703af64a1be35d65edd6a74842c1e65" + "reference": "0d05816beeaf187a3897c28aaa68d683974818d9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/002577f67703af64a1be35d65edd6a74842c1e65", - "reference": "002577f67703af64a1be35d65edd6a74842c1e65", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/0d05816beeaf187a3897c28aaa68d683974818d9", + "reference": "0d05816beeaf187a3897c28aaa68d683974818d9", "shasum": "" }, "require": { @@ -84,7 +84,7 @@ "s3", "sdk" ], - "time": "2018-09-06T22:05:51+00:00" + "time": "2018-09-28T18:46:40+00:00" }, { "name": "bacon/bacon-qr-code", @@ -1108,16 +1108,16 @@ }, { "name": "egulias/email-validator", - "version": "2.1.5", + "version": "2.1.6", "source": { "type": "git", "url": "https://github.com/egulias/EmailValidator.git", - "reference": "54859fabea8b3beecbb1a282888d5c990036b9e3" + "reference": "0578b32b30b22de3e8664f797cf846fc9246f786" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/54859fabea8b3beecbb1a282888d5c990036b9e3", - "reference": "54859fabea8b3beecbb1a282888d5c990036b9e3", + "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/0578b32b30b22de3e8664f797cf846fc9246f786", + "reference": "0578b32b30b22de3e8664f797cf846fc9246f786", "shasum": "" }, "require": { @@ -1161,7 +1161,7 @@ "validation", "validator" ], - "time": "2018-08-16T20:49:45+00:00" + "time": "2018-09-25T20:47:26+00:00" }, { "name": "erusev/parsedown", @@ -1309,6 +1309,99 @@ "homepage": "https://github.com/firebase/php-jwt", "time": "2017-06-27T22:17:23+00:00" }, + { + "name": "guzzle/guzzle", + "version": "v3.8.1", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "4de0618a01b34aa1c8c33a3f13f396dcd3882eba" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/4de0618a01b34aa1c8c33a3f13f396dcd3882eba", + "reference": "4de0618a01b34aa1c8c33a3f13f396dcd3882eba", + "shasum": "" + }, + "require": { + "ext-curl": "*", + "php": ">=5.3.3", + "symfony/event-dispatcher": ">=2.1" + }, + "replace": { + "guzzle/batch": "self.version", + "guzzle/cache": "self.version", + "guzzle/common": "self.version", + "guzzle/http": "self.version", + "guzzle/inflection": "self.version", + "guzzle/iterator": "self.version", + "guzzle/log": "self.version", + "guzzle/parser": "self.version", + "guzzle/plugin": "self.version", + "guzzle/plugin-async": "self.version", + "guzzle/plugin-backoff": "self.version", + "guzzle/plugin-cache": "self.version", + "guzzle/plugin-cookie": "self.version", + "guzzle/plugin-curlauth": "self.version", + "guzzle/plugin-error-response": "self.version", + "guzzle/plugin-history": "self.version", + "guzzle/plugin-log": "self.version", + "guzzle/plugin-md5": "self.version", + "guzzle/plugin-mock": "self.version", + "guzzle/plugin-oauth": "self.version", + "guzzle/service": "self.version", + "guzzle/stream": "self.version" + }, + "require-dev": { + "doctrine/cache": "*", + "monolog/monolog": "1.*", + "phpunit/phpunit": "3.7.*", + "psr/log": "1.0.*", + "symfony/class-loader": "*", + "zendframework/zend-cache": "<2.3", + "zendframework/zend-log": "<2.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.8-dev" + } + }, + "autoload": { + "psr-0": { + "Guzzle": "src/", + "Guzzle\\Tests": "tests/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Guzzle Community", + "homepage": "https://github.com/guzzle/guzzle/contributors" + } + ], + "description": "Guzzle is a PHP HTTP client library and framework for building RESTful web service clients", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "rest", + "web service" + ], + "abandoned": "guzzlehttp/guzzle", + "time": "2014-01-28T22:29:15+00:00" + }, { "name": "guzzlehttp/guzzle", "version": "6.3.3", @@ -1562,32 +1655,32 @@ }, { "name": "jakub-onderka/php-console-color", - "version": "0.1", + "version": "v0.2", "source": { "type": "git", "url": "https://github.com/JakubOnderka/PHP-Console-Color.git", - "reference": "e0b393dacf7703fc36a4efc3df1435485197e6c1" + "reference": "d5deaecff52a0d61ccb613bb3804088da0307191" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/JakubOnderka/PHP-Console-Color/zipball/e0b393dacf7703fc36a4efc3df1435485197e6c1", - "reference": "e0b393dacf7703fc36a4efc3df1435485197e6c1", + "url": "https://api.github.com/repos/JakubOnderka/PHP-Console-Color/zipball/d5deaecff52a0d61ccb613bb3804088da0307191", + "reference": "d5deaecff52a0d61ccb613bb3804088da0307191", "shasum": "" }, "require": { - "php": ">=5.3.2" + "php": ">=5.4.0" }, "require-dev": { "jakub-onderka/php-code-style": "1.0", - "jakub-onderka/php-parallel-lint": "0.*", + "jakub-onderka/php-parallel-lint": "1.0", "jakub-onderka/php-var-dump-check": "0.*", - "phpunit/phpunit": "3.7.*", + "phpunit/phpunit": "~4.3", "squizlabs/php_codesniffer": "1.*" }, "type": "library", "autoload": { - "psr-0": { - "JakubOnderka\\PhpConsoleColor": "src/" + "psr-4": { + "JakubOnderka\\PhpConsoleColor\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -1597,11 +1690,10 @@ "authors": [ { "name": "Jakub Onderka", - "email": "jakub.onderka@gmail.com", - "homepage": "http://www.acci.cz" + "email": "jakub.onderka@gmail.com" } ], - "time": "2014-04-08T15:00:19+00:00" + "time": "2018-09-29T17:23:10+00:00" }, { "name": "jakub-onderka/php-console-highlighter", @@ -1679,16 +1771,16 @@ }, { "name": "laravel/framework", - "version": "v5.7.2", + "version": "v5.7.6", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "86e1f98a6d2aab018e0257a7cb2ef2110d64a873" + "reference": "93e761bb5367166ce98ba908d5eb0edd6be76792" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/86e1f98a6d2aab018e0257a7cb2ef2110d64a873", - "reference": "86e1f98a6d2aab018e0257a7cb2ef2110d64a873", + "url": "https://api.github.com/repos/laravel/framework/zipball/93e761bb5367166ce98ba908d5eb0edd6be76792", + "reference": "93e761bb5367166ce98ba908d5eb0edd6be76792", "shasum": "" }, "require": { @@ -1816,7 +1908,7 @@ "framework", "laravel" ], - "time": "2018-09-06T14:01:05+00:00" + "time": "2018-09-25T14:29:00+00:00" }, { "name": "laravel/passport", @@ -2195,26 +2287,26 @@ }, { "name": "league/flysystem", - "version": "1.0.46", + "version": "1.0.47", "source": { "type": "git", "url": "https://github.com/thephpleague/flysystem.git", - "reference": "f3e0d925c18b92cf3ce84ea5cc58d62a1762a2b2" + "reference": "a11e4a75f256bdacf99d20780ce42d3b8272975c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/f3e0d925c18b92cf3ce84ea5cc58d62a1762a2b2", - "reference": "f3e0d925c18b92cf3ce84ea5cc58d62a1762a2b2", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/a11e4a75f256bdacf99d20780ce42d3b8272975c", + "reference": "a11e4a75f256bdacf99d20780ce42d3b8272975c", "shasum": "" }, "require": { + "ext-fileinfo": "*", "php": ">=5.5.9" }, "conflict": { "league/flysystem-sftp": "<1.0.6" }, "require-dev": { - "ext-fileinfo": "*", "phpspec/phpspec": "^3.4", "phpunit/phpunit": "^5.7.10" }, @@ -2275,20 +2367,20 @@ "sftp", "storage" ], - "time": "2018-08-22T07:45:22+00:00" + "time": "2018-09-14T15:30:29+00:00" }, { "name": "league/flysystem-aws-s3-v3", - "version": "1.0.19", + "version": "1.0.20", "source": { "type": "git", "url": "https://github.com/thephpleague/flysystem-aws-s3-v3.git", - "reference": "f135691ef6761542af301b7c9880f140fb12dc74" + "reference": "398c56027e49653712a8fba1eb12600d2a83f3b7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem-aws-s3-v3/zipball/f135691ef6761542af301b7c9880f140fb12dc74", - "reference": "f135691ef6761542af301b7c9880f140fb12dc74", + "url": "https://api.github.com/repos/thephpleague/flysystem-aws-s3-v3/zipball/398c56027e49653712a8fba1eb12600d2a83f3b7", + "reference": "398c56027e49653712a8fba1eb12600d2a83f3b7", "shasum": "" }, "require": { @@ -2322,7 +2414,7 @@ } ], "description": "Flysystem adapter for the AWS S3 SDK v3.x", - "time": "2018-03-27T20:33:59+00:00" + "time": "2018-09-25T12:02:44+00:00" }, { "name": "league/flysystem-cached-adapter", @@ -2371,6 +2463,53 @@ "description": "An adapter decorator to enable meta-data caching.", "time": "2018-07-09T20:51:04+00:00" }, + { + "name": "league/flysystem-rackspace", + "version": "1.0.5", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/flysystem-rackspace.git", + "reference": "ba877e837f5dce60e78a0555de37eb9bfc7dd6b9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/flysystem-rackspace/zipball/ba877e837f5dce60e78a0555de37eb9bfc7dd6b9", + "reference": "ba877e837f5dce60e78a0555de37eb9bfc7dd6b9", + "shasum": "" + }, + "require": { + "league/flysystem": "~1.0", + "php": ">=5.4.0", + "rackspace/php-opencloud": "~1.16" + }, + "require-dev": { + "mockery/mockery": "0.9.*", + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Flysystem\\Rackspace\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frenky.net" + } + ], + "description": "Flysystem adapter for Rackspace", + "time": "2016-03-11T12:13:42+00:00" + }, { "name": "league/flysystem-sftp", "version": "1.0.16", @@ -2533,6 +2672,34 @@ "time": "2015-06-03T03:35:16+00:00" }, { + "name": "mikemccabe/json-patch-php", + "version": "0.1.0", + "source": { + "type": "git", + "url": "https://github.com/mikemccabe/json-patch-php.git", + "reference": "b3af30a6aec7f6467c773cd49b2d974a70f7c0d4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/mikemccabe/json-patch-php/zipball/b3af30a6aec7f6467c773cd49b2d974a70f7c0d4", + "reference": "b3af30a6aec7f6467c773cd49b2d974a70f7c0d4", + "shasum": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "mikemccabe\\JsonPatch\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-3.0" + ], + "description": "Produce and apply json-patch objects", + "time": "2015-01-05T21:19:54+00:00" + }, + { + "name": "monolog/monolog", "version": "1.23.0", "source": { @@ -2701,16 +2868,16 @@ }, { "name": "nesbot/carbon", - "version": "1.33.0", + "version": "1.34.0", "source": { "type": "git", "url": "https://github.com/briannesbitt/Carbon.git", - "reference": "55667c1007a99e82030874b1bb14d24d07108413" + "reference": "1dbd3cb01c5645f3e7deda7aa46ef780d95fcc33" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/55667c1007a99e82030874b1bb14d24d07108413", - "reference": "55667c1007a99e82030874b1bb14d24d07108413", + "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/1dbd3cb01c5645f3e7deda7aa46ef780d95fcc33", + "reference": "1dbd3cb01c5645f3e7deda7aa46ef780d95fcc33", "shasum": "" }, "require": { @@ -2752,20 +2919,20 @@ "datetime", "time" ], - "time": "2018-08-07T08:39:47+00:00" + "time": "2018-09-20T19:36:25+00:00" }, { "name": "nikic/php-parser", - "version": "v4.0.3", + "version": "v4.0.4", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "bd088dc940a418f09cda079a9b5c7c478890fb8d" + "reference": "fa6ee28600d21d49b2b4e1006b48426cec8e579c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/bd088dc940a418f09cda079a9b5c7c478890fb8d", - "reference": "bd088dc940a418f09cda079a9b5c7c478890fb8d", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/fa6ee28600d21d49b2b4e1006b48426cec8e579c", + "reference": "fa6ee28600d21d49b2b4e1006b48426cec8e579c", "shasum": "" }, "require": { @@ -2803,7 +2970,7 @@ "parser", "php" ], - "time": "2018-07-15T17:25:16+00:00" + "time": "2018-09-18T07:03:24+00:00" }, { "name": "paragonie/constant_time_encoding", @@ -3768,6 +3935,63 @@ ], "time": "2018-09-05T11:40:09+00:00" }, + { + "name": "rackspace/php-opencloud", + "version": "v1.16.0", + "source": { + "type": "git", + "url": "https://github.com/rackspace/php-opencloud.git", + "reference": "d6b71feed7f9e7a4b52e0240a79f06473ba69c8c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/rackspace/php-opencloud/zipball/d6b71feed7f9e7a4b52e0240a79f06473ba69c8c", + "reference": "d6b71feed7f9e7a4b52e0240a79f06473ba69c8c", + "shasum": "" + }, + "require": { + "guzzle/guzzle": "~3.8", + "mikemccabe/json-patch-php": "~0.1", + "php": ">=5.4", + "psr/log": "~1.0" + }, + "require-dev": { + "apigen/apigen": "~4.0", + "fabpot/php-cs-fixer": "1.0.*@dev", + "jakub-onderka/php-parallel-lint": "0.*", + "phpspec/prophecy": "~1.4", + "phpunit/phpunit": "4.3.*", + "satooshi/php-coveralls": "0.6.*@dev" + }, + "type": "library", + "autoload": { + "psr-0": { + "OpenCloud": [ + "lib/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Jamie Hannaford", + "email": "jamie.hannaford@rackspace.com", + "homepage": "https://github.com/jamiehannaford" + } + ], + "description": "PHP SDK for Rackspace/OpenStack APIs", + "keywords": [ + "Openstack", + "nova", + "opencloud", + "rackspace", + "swift" + ], + "time": "2016-01-29T10:34:57+00:00" + }, { "name": "ramsey/uuid", "version": "3.8.0", @@ -4277,16 +4501,16 @@ }, { "name": "spatie/db-dumper", - "version": "2.10.1", + "version": "2.11.1", "source": { "type": "git", "url": "https://github.com/spatie/db-dumper.git", - "reference": "1192bb0df9f49ee1f0bdecb7aa921d2647b4c7c7" + "reference": "858ea38e341e2e5f74a5b59cc8184c5c7e94b50d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/db-dumper/zipball/1192bb0df9f49ee1f0bdecb7aa921d2647b4c7c7", - "reference": "1192bb0df9f49ee1f0bdecb7aa921d2647b4c7c7", + "url": "https://api.github.com/repos/spatie/db-dumper/zipball/858ea38e341e2e5f74a5b59cc8184c5c7e94b50d", + "reference": "858ea38e341e2e5f74a5b59cc8184c5c7e94b50d", "shasum": "" }, "require": { @@ -4323,7 +4547,7 @@ "mysqldump", "spatie" ], - "time": "2018-08-30T12:10:16+00:00" + "time": "2018-09-27T06:30:34+00:00" }, { "name": "spatie/laravel-backup", @@ -4441,16 +4665,16 @@ }, { "name": "swiftmailer/swiftmailer", - "version": "v6.1.2", + "version": "v6.1.3", "source": { "type": "git", "url": "https://github.com/swiftmailer/swiftmailer.git", - "reference": "7d760881d266d63c5e7a1155cbcf2ac656a31ca8" + "reference": "8ddcb66ac10c392d3beb54829eef8ac1438595f4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/7d760881d266d63c5e7a1155cbcf2ac656a31ca8", - "reference": "7d760881d266d63c5e7a1155cbcf2ac656a31ca8", + "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/8ddcb66ac10c392d3beb54829eef8ac1438595f4", + "reference": "8ddcb66ac10c392d3beb54829eef8ac1438595f4", "shasum": "" }, "require": { @@ -4496,7 +4720,7 @@ "mail", "mailer" ], - "time": "2018-07-13T07:04:35+00:00" + "time": "2018-09-11T07:12:52+00:00" }, { "name": "symfony/console", @@ -6195,22 +6419,23 @@ }, { "name": "codeception/codeception", - "version": "2.4.5", + "version": "2.5.0", "source": { "type": "git", "url": "https://github.com/Codeception/Codeception.git", - "reference": "5fee32d5c82791548931cbc34806b4de6aa1abfc" + "reference": "dee493561daf644134c95cf176fd2c25aff59ea9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Codeception/Codeception/zipball/5fee32d5c82791548931cbc34806b4de6aa1abfc", - "reference": "5fee32d5c82791548931cbc34806b4de6aa1abfc", + "url": "https://api.github.com/repos/Codeception/Codeception/zipball/dee493561daf644134c95cf176fd2c25aff59ea9", + "reference": "dee493561daf644134c95cf176fd2c25aff59ea9", "shasum": "" }, "require": { "behat/gherkin": "^4.4.0", "codeception/phpunit-wrapper": "^6.0.9|^7.0.6", "codeception/stub": "^2.0", + "ext-curl": "*", "ext-json": "*", "ext-mbstring": "*", "facebook/webdriver": ">=1.1.3 <2.0", @@ -6258,7 +6483,7 @@ }, "autoload": { "psr-4": { - "Codeception\\": "src\\Codeception", + "Codeception\\": "src/Codeception", "Codeception\\Extension\\": "ext" } }, @@ -6282,7 +6507,7 @@ "functional testing", "unit testing" ], - "time": "2018-08-01T07:21:49+00:00" + "time": "2018-09-24T09:33:01+00:00" }, { "name": "codeception/phpunit-wrapper", @@ -6419,16 +6644,16 @@ }, { "name": "filp/whoops", - "version": "2.2.0", + "version": "2.2.1", "source": { "type": "git", "url": "https://github.com/filp/whoops.git", - "reference": "181c4502d8f34db7aed7bfe88d4f87875b8e947a" + "reference": "e79cd403fb77fc8963a99ecc30e80ddd885b3311" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filp/whoops/zipball/181c4502d8f34db7aed7bfe88d4f87875b8e947a", - "reference": "181c4502d8f34db7aed7bfe88d4f87875b8e947a", + "url": "https://api.github.com/repos/filp/whoops/zipball/e79cd403fb77fc8963a99ecc30e80ddd885b3311", + "reference": "e79cd403fb77fc8963a99ecc30e80ddd885b3311", "shasum": "" }, "require": { @@ -6447,7 +6672,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.1-dev" + "dev-master": "2.2-dev" } }, "autoload": { @@ -6476,7 +6701,7 @@ "throwable", "whoops" ], - "time": "2018-03-03T17:56:25+00:00" + "time": "2018-06-30T13:14:06+00:00" }, { "name": "fzaninotto/faker", @@ -7127,6 +7352,17 @@ { "name": "roave/security-advisories", "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/Roave/SecurityAdvisories.git", + "reference": "8605f2e74f558d3e349b219e58414b75b0adc30e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/8605f2e74f558d3e349b219e58414b75b0adc30e", + "reference": "8605f2e74f558d3e349b219e58414b75b0adc30e", + "shasum": "" + }, "conflict": { "3f/pygmentize": "<1.2", "adodb/adodb-php": "<5.20.12", @@ -7134,6 +7370,7 @@ "amphp/http": "<1.0.1", "asymmetricrypt/asymmetricrypt": ">=0,<9.9.99", "aws/aws-sdk-php": ">=3,<3.2.1", + "brightlocal/phpwhois": "<=4.2.5", "bugsnag/bugsnag-laravel": ">=2,<2.0.2", "cakephp/cakephp": ">=1.3,<1.3.18|>=2,<2.4.99|>=2.5,<2.5.99|>=2.6,<2.6.12|>=2.7,<2.7.6|>=3,<3.0.15|>=3.1,<3.1.4|>=3.4,<3.4.14|>=3.5,<3.5.17|>=3.6,<3.6.4", "cart2quote/module-quotation": ">=4.1.6,<=4.4.5|>=5,<5.4.4", @@ -7145,6 +7382,7 @@ "contao/core-bundle": ">=4,<4.4.18|>=4.5,<4.5.8", "contao/listing-bundle": ">=4,<4.4.8", "contao/newsletter-bundle": ">=4,<4.1", + "david-garcia/phpwhois": "<=4.3.1", "doctrine/annotations": ">=1,<1.2.7", "doctrine/cache": ">=1,<1.3.2|>=1.4,<1.4.2", "doctrine/common": ">=2,<2.4.3|>=2.5,<2.5.1", @@ -7159,6 +7397,7 @@ "drupal/drupal": ">=7,<7.59|>=8,<8.4.8|>=8.5,<8.5.3", "erusev/parsedown": "<1.7", "ezsystems/ezpublish-legacy": ">=5.3,<5.3.12.3|>=5.4,<5.4.11.3|>=2017.8,<2017.8.1.1|>=2017.12,<2017.12.2.1", + "ezyang/htmlpurifier": "<4.1.1", "firebase/php-jwt": "<2", "friendsofsymfony/rest-bundle": ">=1.2,<1.2.2", "friendsofsymfony/user-bundle": ">=1.2,<1.3.5", @@ -7170,7 +7409,11 @@ "illuminate/cookie": ">=4,<=4.0.11|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.42|>=5.6,<5.6.30", "illuminate/database": ">=4,<4.0.99|>=4.1,<4.1.29", "illuminate/encryption": ">=4,<=4.0.11|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.40|>=5.6,<5.6.15", + "ivankristianto/phpwhois": "<=4.3", + "james-heinrich/getid3": "<1.9.9", "joomla/session": "<1.3.1", + "jsmitty12/phpwhois": "<5.1", + "kazist/phpwhois": "<=4.2.6", "kreait/firebase-php": ">=3.2,<3.8.1", "laravel/framework": ">=4,<4.0.99|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.42|>=5.6,<5.6.30", "laravel/socialite": ">=1,<1.0.99|>=2,<2.0.10", @@ -7180,6 +7423,7 @@ "monolog/monolog": ">=1.8,<1.12", "namshi/jose": "<2.2", "onelogin/php-saml": "<2.10.4", + "openid/php-openid": "<2.3", "oro/crm": ">=1.7,<1.7.4", "oro/platform": ">=1.7,<1.7.4", "padraic/humbug_get_contents": "<1.1.2", @@ -7188,21 +7432,25 @@ "paypal/merchant-sdk-php": "<3.12", "phpmailer/phpmailer": ">=5,<5.2.24", "phpunit/phpunit": ">=4.8.19,<4.8.28|>=5.0.10,<5.6.3", + "phpwhois/phpwhois": "<=4.2.5", "phpxmlrpc/extras": "<0.6.1", "propel/propel": ">=2.0.0-alpha1,<=2.0.0-alpha7", "propel/propel1": ">=1,<=1.7.1", "pusher/pusher-php-server": "<2.2.1", "sabre/dav": ">=1.6,<1.6.99|>=1.7,<1.7.11|>=1.8,<1.8.9", "sensiolabs/connect": "<4.2.3", + "serluck/phpwhois": "<=4.2.6", "shopware/shopware": "<5.3.7", "silverstripe/cms": ">=3,<=3.0.11|>=3.1,<3.1.11", "silverstripe/forum": "<=0.6.1|>=0.7,<=0.7.3", "silverstripe/framework": ">=3,<3.3", "silverstripe/userforms": "<3", + "simple-updates/phpwhois": "<=1", "simplesamlphp/saml2": "<1.10.6|>=2,<2.3.8|>=3,<3.1.4", "simplesamlphp/simplesamlphp": "<1.15.2", "simplesamlphp/simplesamlphp-module-infocard": "<1.0.1", "slim/slim": "<2.6", + "smarty/smarty": "<3.1.33", "socalnick/scn-social-auth": "<1.15.2", "squizlabs/php_codesniffer": ">=1,<2.8.1|>=3,<3.0.1", "stormpath/sdk": ">=0,<9.9.99", @@ -7229,8 +7477,10 @@ "symfony/web-profiler-bundle": ">=2,<2.3.19|>=2.4,<2.4.9|>=2.5,<2.5.4", "symfony/yaml": ">=2,<2.0.22|>=2.1,<2.1.7", "thelia/backoffice-default-template": ">=2.1,<2.1.2", - "thelia/thelia": ">=2.1,<2.1.2|>=2.1.0-beta1,<2.1.3", + "thelia/thelia": ">=2.1.0-beta1,<2.1.3|>=2.1,<2.1.2", + "theonedemon/phpwhois": "<=4.2.5", "titon/framework": ">=0,<9.9.99", + "truckersmp/phpwhois": "<=4.3.1", "twig/twig": "<1.20", "typo3/cms": ">=6.2,<6.2.30|>=7,<7.6.30|>=8,<8.7.17|>=9,<9.3.2", "typo3/cms-core": ">=8,<8.7.17|>=9,<9.3.2", @@ -7283,7 +7533,7 @@ } ], "description": "Prevents installation of composer packages with known security vulnerabilities: no API, simply require it", - "time": "2018-08-14T15:39:17+00:00" + "time": "2018-09-17T20:20:31+00:00" }, { "name": "sebastian/code-unit-reverse-lookup", @@ -7610,16 +7860,16 @@ }, { "name": "squizlabs/php_codesniffer", - "version": "3.3.1", + "version": "3.3.2", "source": { "type": "git", "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", - "reference": "628a481780561150481a9ec74709092b9759b3ec" + "reference": "6ad28354c04b364c3c71a34e4a18b629cc3b231e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/628a481780561150481a9ec74709092b9759b3ec", - "reference": "628a481780561150481a9ec74709092b9759b3ec", + "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/6ad28354c04b364c3c71a34e4a18b629cc3b231e", + "reference": "6ad28354c04b364c3c71a34e4a18b629cc3b231e", "shasum": "" }, "require": { @@ -7657,7 +7907,7 @@ "phpcs", "standards" ], - "time": "2018-07-26T23:47:18+00:00" + "time": "2018-09-23T23:08:17+00:00" }, { "name": "symfony/browser-kit", diff --git a/config/backup.php b/config/backup.php index bc45801f4a..898f467ff2 100644 --- a/config/backup.php +++ b/config/backup.php @@ -14,8 +14,7 @@ return [ 'backup' => [ /* - * The name of this application. You can use this name to monitor - * the backups. + * I don't know why they call it name - it's used in the path for uploads */ 'name' => 'backups', @@ -27,8 +26,6 @@ return [ * The list of directories and files that will be included in the backup. */ 'include' => [ - public_path('uploads'), - storage_path('private_uploads'), storage_path('oauth-private.key'), storage_path('oauth-public.key'), (env('BACKUP_ENV')=='true') ? base_path('.env') : base_path('.env.example'), @@ -76,7 +73,7 @@ return [ * The disk names on which the backups will be stored. */ 'disks' => [ - 'local', + env('FILESYSTEM_DISK'), ], ], ], diff --git a/config/filesystems.php b/config/filesystems.php index 6fcf1386b4..dd64eda585 100644 --- a/config/filesystems.php +++ b/config/filesystems.php @@ -1,15 +1,6 @@ 's3', + 'cloud' => env('FILESYSTEM_CLOUD', 's3'), /* |-------------------------------------------------------------------------- @@ -48,52 +37,54 @@ return [ | may even configure multiple disks of the same driver. Defaults have | been setup for each driver as an example of the required options. | + | Supported Drivers: "local", "ftp", "sftp", "s3", "rackspace" + | */ 'disks' => [ 'local' => [ 'driver' => 'local', - 'root' => base_path(), + 'root' => storage_path('app'), ], - 'ftp' => [ - 'driver' => 'ftp', - 'host' => env('FTP_HOST', 'ftp.yourhost.com'), - 'username' => env('FTP_USERNAME', 'ftp-user'), - 'password' => env('FTP_PASSWORD', 'ftp-pass'), - 'port' => env('FTP_PORT', '21'), - 'root' => env('FTP_ROOT', ''), - 'passive' => env('FTP_PASSIVE', true), - 'ssl' => env('FTP_SSL', true), - 'timeout' => env('FTP_TIMEOUT', 30), - ], - - 'sftp' => [ - 'driver' => 'sftp', - 'host' => env('SFTP_HOST', 'sftp.yourhost.com'), - 'username' => env('SFTP_USERNAME', 'sftp-user'), - 'password' => env('SFTP_PASSWORD', 'sftp-pass'), - 'port' => env('SFTP_PORT', '22'), - 'root' => env('SFTP_ROOT', ''), - 'timeout' => env('SFTP_TIMEOUT', 30), + // This applies the LOCAL public only, not S3/FTP/etc + 'public' => [ + 'driver' => 'local', + 'root' => storage_path('app/public'), + 'url' => env('APP_URL').'/storage', + 'visibility' => 'public', ], 's3' => [ 'driver' => 's3', - 'key' => env('AWS_KEY', null), - 'secret' => env('AWS_SECRET', null), - 'region' => env('AWS_REGION', null), - 'bucket' => env('AWS_BUCKET', null), - - 'cache' => [ - 'store' => env('AWS_CACHE_STORE', 'memcached'), - 'expire' => env('AWS_CACHE_EXPIRES', 600), - 'prefix' => env('AWS_CACHE_PREFIX', 'cache-prefix'), - ], + 'key' => env('AWS_ACCESS_KEY_ID'), + 'secret' => env('AWS_SECRET_ACCESS_KEY'), + 'region' => env('AWS_DEFAULT_REGION'), + 'bucket' => env('AWS_BUCKET'), + 'url' => env('AWS_URL'), + 'root' => env('AWS_BUCKET_ROOT'), ], + 'rackspace' => [ + 'driver' => 'rackspace', + 'username' => env('RACKSPACE_USERNAME'), + 'key' => env('RACKSPACE_KEY'), + 'container' => env('RACKSPACE_CONTAINER'), + 'endpoint' => 'https://identity.api.rackspacecloud.com/v2.0/', + 'region' => env('RACKSPACE_REGION'), + 'url_type' => env('RACKSPACE_URL_TYPE'), + ], ], ]; + +// When you're dealing with local file storage, the paths will be different than S3 +if (env('FILESYSTEM_DISK')!='local') +{ + $config['disks']['public'] = $config['disks'][env('FILESYSTEM_DISK')]; + $config['disks']['public']['visibility'] = 'public'; +} + +return $config; diff --git a/database/seeds/AssetModelSeeder.php b/database/seeds/AssetModelSeeder.php index fdb1adef0a..03c7fb5095 100755 --- a/database/seeds/AssetModelSeeder.php +++ b/database/seeds/AssetModelSeeder.php @@ -2,6 +2,7 @@ use Illuminate\Database\Seeder; use App\Models\AssetModel; +use Illuminate\Support\Facades\Storage; class AssetModelSeeder extends Seeder { @@ -39,21 +40,30 @@ class AssetModelSeeder extends Seeder factory(AssetModel::class, 1)->states('ultrafine')->create(); // 17 factory(AssetModel::class, 1)->states('ultrasharp')->create(); // 18 - $src = public_path('/img/demo/models'); - $dst = public_path('/uploads/models'); - - $del_files = glob($dst."/*.*"); + $src = public_path('/img/demo/models/'); + $dst = 'assetmodels'.'/'; + $del_files = Storage::files($dst); foreach($del_files as $del_file){ // iterate files - if(is_file($del_file)) - unlink($del_file); // delete file + $file_to_delete = str_replace($src,'',$del_file); + \Log::debug('Deleting: '.$file_to_delete); + try { + Storage::disk('public')->delete($dst.$del_file); + } catch (\Exception $e) { + \Log::debug($e); + } } $add_files = glob($src."/*.*"); foreach($add_files as $add_file){ - $file_to_copy = str_replace($src,$dst,$add_file); - copy($add_file, $file_to_copy); + $file_to_copy = str_replace($src,'',$add_file); + \Log::debug('Copying: '.$file_to_copy); + try { + Storage::disk('public')->put($dst.$file_to_copy, file_get_contents($src.$file_to_copy)); + } catch (\Exception $e) { + \Log::debug($e); + } } diff --git a/database/seeds/AssetSeeder.php b/database/seeds/AssetSeeder.php index 79e47d6113..f9c2f1fc83 100644 --- a/database/seeds/AssetSeeder.php +++ b/database/seeds/AssetSeeder.php @@ -1,7 +1,7 @@ states('ultrasharp')->create(); - $dst = public_path('/uploads/assets'); - - $del_files = glob($dst."/*.*"); - + $del_files = Storage::files('companies'); foreach($del_files as $del_file){ // iterate files - if(is_file($del_file)) - unlink($del_file); // delete file + \Log::debug('Deleting: '.$del_files); + try { + Storage::disk('public')->delete('assets'.'/'.$del_files); + } catch (\Exception $e) { + \Log::debug($e); + } } DB::table('checkout_requests')->truncate(); diff --git a/database/seeds/CompanySeeder.php b/database/seeds/CompanySeeder.php index 3885b939f4..eeae5492b7 100644 --- a/database/seeds/CompanySeeder.php +++ b/database/seeds/CompanySeeder.php @@ -12,26 +12,37 @@ class CompanySeeder extends Seeder */ public function run() { - // + \Log::debug('Seed companies'); Company::truncate(); factory(Company::class, 4)->create(); - $src = public_path('/img/demo/companies'); - $dst = public_path('/uploads/companies'); - $del_files = glob($dst."/*.*"); + $src = public_path('/img/demo/companies/'); + $dst = 'companies'.'/'; + $del_files = Storage::files('companies/'.$dst); foreach($del_files as $del_file){ // iterate files - if(is_file($del_file)) - unlink($del_file); // delete file + $file_to_delete = str_replace($src,'',$del_file); + \Log::debug('Deleting: '.$file_to_delete); + try { + Storage::disk('public')->delete($dst.$del_file); + } catch (\Exception $e) { + \Log::debug($e); + } } $add_files = glob($src."/*.*"); foreach($add_files as $add_file){ - $file_to_copy = str_replace($src,$dst,$add_file); - copy($add_file, $file_to_copy); + $file_to_copy = str_replace($src,'',$add_file); + \Log::debug('Copying: '.$file_to_copy); + try { + Storage::disk('public')->put($dst.$file_to_copy, file_get_contents($src.$file_to_copy)); + } catch (\Exception $e) { + \Log::debug($e); + } } + } } diff --git a/database/seeds/LocationSeeder.php b/database/seeds/LocationSeeder.php index 40d389792f..f7d857f34d 100644 --- a/database/seeds/LocationSeeder.php +++ b/database/seeds/LocationSeeder.php @@ -1,7 +1,7 @@ create(); - $src = public_path('/img/demo/locations'); - $dst = public_path('/uploads/locations'); - - $del_files = glob($dst."/*.*"); + $src = public_path('/img/demo/locations/'); + $dst = 'locations'.'/'; + $del_files = Storage::files($dst); foreach($del_files as $del_file){ // iterate files - if(is_file($del_file)) - unlink($del_file); // delete file + $file_to_delete = str_replace($src,'',$del_file); + \Log::debug('Deleting: '.$file_to_delete); + try { + Storage::disk('public')->delete($dst.$del_file); + } catch (\Exception $e) { + \Log::debug($e); + } } $add_files = glob($src."/*.*"); foreach($add_files as $add_file){ - $file_to_copy = str_replace($src,$dst,$add_file); - copy($add_file, $file_to_copy); + $file_to_copy = str_replace($src,'',$add_file); + \Log::debug('Copying: '.$file_to_copy); + try { + Storage::disk('public')->put($dst.$file_to_copy, file_get_contents($src.$file_to_copy)); + } catch (\Exception $e) { + \Log::debug($e); + } } } diff --git a/database/seeds/ManufacturerSeeder.php b/database/seeds/ManufacturerSeeder.php index f6d9a2451e..a65d12a2e4 100644 --- a/database/seeds/ManufacturerSeeder.php +++ b/database/seeds/ManufacturerSeeder.php @@ -1,6 +1,7 @@ states('avery')->create(); // 10 factory(Manufacturer::class, 1)->states('crucial')->create(); // 10 - $src = public_path('/img/demo/manufacturers'); - $dst = public_path('/uploads/manufacturers'); - - $del_files = glob($dst."/*.*"); + $src = public_path('/img/demo/manufacturers/'); + $dst = 'manufacturers'.'/'; + $del_files = Storage::files($dst); foreach($del_files as $del_file){ // iterate files - if(is_file($del_file)) - unlink($del_file); // delete file + $file_to_delete = str_replace($src,'',$del_file); + \Log::debug('Deleting: '.$file_to_delete); + try { + Storage::disk('public')->delete($dst.$del_file); + } catch (\Exception $e) { + \Log::debug($e); + } } $add_files = glob($src."/*.*"); foreach($add_files as $add_file){ - $file_to_copy = str_replace($src,$dst,$add_file); - copy($add_file, $file_to_copy); + $file_to_copy = str_replace($src,'',$add_file); + \Log::debug('Copying: '.$file_to_copy); + try { + Storage::disk('public')->put($dst.$file_to_copy, file_get_contents($src.$file_to_copy)); + } catch (\Exception $e) { + \Log::debug($e); + } } diff --git a/public/img/demo/logo.png b/public/img/demo/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..423a5b74906c4a1f67dab665a59a6731f0dbaa98 GIT binary patch literal 22482 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 literal 0 HcmV?d00001 diff --git a/resources/lang/en/general.php b/resources/lang/en/general.php index ea339cf9a7..69690be019 100644 --- a/resources/lang/en/general.php +++ b/resources/lang/en/general.php @@ -125,6 +125,7 @@ 'feature_disabled' => 'This feature has been disabled for the demo installation.', 'location' => 'Location', 'locations' => 'Locations', + 'logo_size' => 'Square logos look best with Logo + Text. Logo maximum display size is 50px high x 500px wide. ', 'logout' => 'Logout', 'lookup_by_tag' => 'Lookup by Asset Tag', 'maintenances' => 'Maintenances', diff --git a/resources/views/accessories/edit.blade.php b/resources/views/accessories/edit.blade.php index 6b2065a089..9148c8b139 100755 --- a/resources/views/accessories/edit.blade.php +++ b/resources/views/accessories/edit.blade.php @@ -29,7 +29,7 @@
{{ Form::checkbox('image_delete') }} - + {!! $errors->first('image_delete', ':message') !!}
diff --git a/resources/views/account/profile.blade.php b/resources/views/account/profile.blade.php index 18a8287035..bbff2a602f 100755 --- a/resources/views/account/profile.blade.php +++ b/resources/views/account/profile.blade.php @@ -90,7 +90,7 @@
{{ Form::checkbox('avatar_delete') }} - + {!! $errors->first('avatar_delete', ':message') !!}
diff --git a/resources/views/categories/edit.blade.php b/resources/views/categories/edit.blade.php index 88bc6457be..ca43c49bb8 100755 --- a/resources/views/categories/edit.blade.php +++ b/resources/views/categories/edit.blade.php @@ -79,7 +79,7 @@
{{ Form::checkbox('image_delete') }} - + {!! $errors->first('image_delete', ':message') !!}
diff --git a/resources/views/companies/edit.blade.php b/resources/views/companies/edit.blade.php index 8f63b05c4f..ee77efc4f5 100644 --- a/resources/views/companies/edit.blade.php +++ b/resources/views/companies/edit.blade.php @@ -16,7 +16,7 @@
{{ Form::checkbox('image_delete') }} - + {!! $errors->first('image_delete', ':message') !!}
diff --git a/resources/views/components/edit.blade.php b/resources/views/components/edit.blade.php index 8e9be37381..9bfdf6a433 100644 --- a/resources/views/components/edit.blade.php +++ b/resources/views/components/edit.blade.php @@ -27,7 +27,7 @@
{{ Form::checkbox('image_delete') }} - + {!! $errors->first('image_delete', ':message') !!}
diff --git a/resources/views/consumables/edit.blade.php b/resources/views/consumables/edit.blade.php index 9496019e41..4392c1f1b4 100644 --- a/resources/views/consumables/edit.blade.php +++ b/resources/views/consumables/edit.blade.php @@ -27,7 +27,7 @@
{{ Form::checkbox('image_delete') }} - + {!! $errors->first('image_delete', ':message') !!}
diff --git a/resources/views/departments/edit.blade.php b/resources/views/departments/edit.blade.php index ff5bbfd16f..4d3952528e 100644 --- a/resources/views/departments/edit.blade.php +++ b/resources/views/departments/edit.blade.php @@ -29,7 +29,7 @@
{{ Form::checkbox('image_delete') }} - + {!! $errors->first('image_delete', ':message') !!}
diff --git a/resources/views/hardware/edit.blade.php b/resources/views/hardware/edit.blade.php index c3c5d9be2a..708d296eaf 100755 --- a/resources/views/hardware/edit.blade.php +++ b/resources/views/hardware/edit.blade.php @@ -86,7 +86,7 @@ {!! $errors->first('image_delete', ':message') !!}
- +
@@ -170,7 +170,7 @@ }); } } - ; + $(function () { //grab custom fields for this model whenever model changes. @@ -184,135 +184,8 @@ user_add($(".status_id").val()); }); - $("#create-form").submit(function (event) { - event.preventDefault(); - return sendForm(); - }); - - // Resize Files when chosen - //First check to see if there is a file before doing anything else - - var imageData = ""; - var $fileInput = $('#uploadFile'); - $fileInput.on('change', function (e) { - if ($fileInput != '') { - if (window.File && window.FileReader && window.FormData) { - var file = e.target.files[0]; - if (file) { - if (/^image\//i.test(file.type)) { - readFile(file); - } else { - alert('Invalid Image File :('); - } - } - } - else { - console.log("File API not supported, not resizing"); - } - } - }); - - - function readFile(file) { - var reader = new FileReader(); - - reader.onloadend = function () { - processFile(reader.result, file.type); - } - - reader.onerror = function () { - alert("Unable to read file"); - } - - reader.readAsDataURL(file); - } - - function processFile(dataURL, fileType) { - var maxWidth = 800; - var maxHeight = 800; - - var image = new Image(); - image.src = dataURL; - - image.onload = function () { - var width = image.width; - var height = image.height; - var shouldResize = (width > maxWidth) || (height > maxHeight); - - if (!shouldResize) { - imageData = dataURL; - return; - } - - var newWidth; - var newHeight; - - if (width > height) { - newHeight = height * (maxWidth / width); - newWidth = maxWidth; - } else { - newWidth = width * (maxHeight / height); - newHeight = maxHeight; - } - var canvas = document.createElement('canvas'); - - canvas.width = newWidth; - canvas.height = newHeight; - - var context = canvas.getContext('2d'); - - context.drawImage(this, 0, 0, newWidth, newHeight); - - dataURL = canvas.toDataURL(fileType); - - imageData = dataURL; - - }; - - image.onerror = function () { - alert('Unable to process file :('); - } - } - - function sendForm() { - var form = $("#create-form").get(0); - var formData = $('#create-form').serializeArray(); - formData.push({name: 'image', value: imageData}); - $.ajax({ - type: 'POST', - url: form.action, - headers: { - "X-Requested-With": 'XMLHttpRequest', - "X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr('content') - }, - data: formData, - dataType: 'json', - success: function (data) { - // console.dir(data); - // AssetController flashes success to session, redirect to hardware page. - if (data.redirect_url) { - window.location.href = data.redirect_url; - return true; - } - window.location.reload(true); - return false; - - }, - error: function (data) { - // AssetRequest Validator will flash all errors to session, this just refreshes to see them. - window.location.reload(true); - // console.log(JSON.stringify(data)); - // console.log('error submitting'); - } - }); - - return false; - } - }); - - @stop diff --git a/resources/views/hardware/view.blade.php b/resources/views/hardware/view.blade.php index dd8ea1b6e3..f6b5ffc69e 100755 --- a/resources/views/hardware/view.blade.php +++ b/resources/views/hardware/view.blade.php @@ -497,9 +497,9 @@
diff --git a/resources/views/partials/forms/edit/image-upload.blade.php b/resources/views/partials/forms/edit/image-upload.blade.php index 32b1b3ce5b..b0c7819b6e 100644 --- a/resources/views/partials/forms/edit/image-upload.blade.php +++ b/resources/views/partials/forms/edit/image-upload.blade.php @@ -3,14 +3,14 @@

{{ trans('general.image_filetypes_help', ['size' => \App\Helpers\Helper::file_upload_max_size_readable()]) }}

{!! $errors->first('image', ':message') !!}
-
+
diff --git a/resources/views/settings/backups.blade.php b/resources/views/settings/backups.blade.php index 534a291005..148c81967b 100644 --- a/resources/views/settings/backups.blade.php +++ b/resources/views/settings/backups.blade.php @@ -29,7 +29,7 @@ @foreach ($files as $file) - {{ $file['filename'] }} + {{ $file['filename'] }} {{ date("M d, Y g:i A", $file['modified']) }} {{ $file['filesize'] }} diff --git a/resources/views/settings/branding.blade.php b/resources/views/settings/branding.blade.php index 6756570461..4a7170459a 100644 --- a/resources/views/settings/branding.blade.php +++ b/resources/views/settings/branding.blade.php @@ -37,7 +37,7 @@
-
+
@@ -60,23 +60,31 @@
- + +
- @if (config('app.lock_passwords')) -

{{ trans('general.lock_passwords') }}

- @else + -

{{ trans('general.image_filetypes_help', ['size' => \App\Helpers\Helper::file_upload_max_size_readable()]) }}

- +

{{ trans('general.image_filetypes_help', ['size' => \App\Helpers\Helper::file_upload_max_size_readable()]) }} {{ trans('general.logo_size') }}

{!! $errors->first('image', ':message') !!} - {{ Form::checkbox('clear_logo', '1', Input::old('clear_logo'),array('class' => 'minimal')) }} Remove - @endif +
+
+ +
+ + @if ($setting->logo!='') +
+ + {{ Form::checkbox('clear_logo', '1', Input::old('clear_logo'),array('class' => 'minimal')) }} Remove current image + +
+ @endif
@@ -157,7 +165,7 @@ {{ Form::textarea('custom_css', Input::old('custom_css', $setting->custom_css), array('class' => 'form-control','placeholder' => 'Add your custom CSS')) }} {!! $errors->first('custom_css', ':message') !!} @endif -

{{ trans('admin/settings/general.custom_css_help') }}

+

{!! trans('admin/settings/general.custom_css_help') !!}

diff --git a/resources/views/users/view.blade.php b/resources/views/users/view.blade.php index 20b9b7fd4d..09a572c055 100755 --- a/resources/views/users/view.blade.php +++ b/resources/views/users/view.blade.php @@ -115,11 +115,7 @@
@endif
- @if ($user->avatar) - - @else - - @endif +
diff --git a/resources/views/vendor/mail/html/header.blade.php b/resources/views/vendor/mail/html/header.blade.php index 686ee632f5..fe93f44a99 100644 --- a/resources/views/vendor/mail/html/header.blade.php +++ b/resources/views/vendor/mail/html/header.blade.php @@ -4,13 +4,13 @@ @if ($snipeSettings->brand == '3') @if ($snipeSettings->logo!='') - + @endif {{ $snipeSettings->site_name }} @elseif ($snipeSettings->brand == '2') @if ($snipeSettings->logo!='') - + @endif @else {{ $snipeSettings->site_name }} diff --git a/upgrade.php b/upgrade.php index 030d262072..08eafd6b26 100644 --- a/upgrade.php +++ b/upgrade.php @@ -174,16 +174,71 @@ echo "\n"; echo "--------------------------------------------------------\n"; -echo "Step 9: Taking application out of maintenance mode:\n"; +echo "Step 10: Taking application out of maintenance mode:\n"; echo "--------------------------------------------------------\n\n"; $up = shell_exec('php artisan up'); echo '-- '.$up."\n\n"; + +echo "--------------------------------------------------------\n"; +echo "Step 11: Checking for v5 public storage directories: \n"; +echo "--------------------------------------------------------\n\n"; + + +if ((!file_exists('storage/app/public')) && (!is_dir('storage/app/public'))) { + echo "- No public directory found in storage/app - creating one.\n\n"; + if (!mkdir('storage/app/public', 0777, true)) { + echo "ERROR: Failed to create directory at storage/app/public. You should do this manually.\n\n"; + } + $storage_simlink = shell_exec('php artisan storage:link'); + echo $storage_simlink; + +} else { + echo "- Public storage directory already exists. Skipping...\n\n"; +} + +echo "- Copying files into storage/app/public.\n\n"; +if (rmove('public/uploads','storage/app/public')) { + echo "- Copy successful.\n\n"; +} else { + echo "- Copy failed - you should do this manually by copying the files from public/uploads into the storage/app/public directory.\n\n"; +} + echo "--------------------------------------------------------\n"; echo "FINISHED! Clear your browser cookies and re-login to use :\n"; echo "your upgraded Snipe-IT.\n"; echo "--------------------------------------------------------\n\n"; +/** + * Recursively move files from one directory to another + * + * @param String $src - Source of files being moved + * @param String $dest - Destination of files being moved + */ +function rmove($src, $dest){ + // If source is not a directory stop processing + if(!is_dir($src)) return false; + + // If the destination directory does not exist create it + if(!is_dir($dest)) { + if(!mkdir($dest)) { + // If the destination directory could not be created stop processing + return false; + } + } + + // Open the source directory to read in files + $i = new DirectoryIterator($src); + foreach($i as $f) { + if($f->isFile()) { + rename($f->getRealPath(), "$dest/" . $f->getFilename()); + } else if(!$f->isDot() && $f->isDir()) { + rmove($f->getRealPath(), "$dest/$f"); + unlink($f->getRealPath()); + } + } + unlink($src); +}
@if ($asset->image) - + @elseif (($asset->model) && ($asset->model->image!='')) - + @endif @if ($snipeSettings->qr_code=='1') diff --git a/resources/views/layouts/basic.blade.php b/resources/views/layouts/basic.blade.php index 1e9b3334b5..4942c24041 100644 --- a/resources/views/layouts/basic.blade.php +++ b/resources/views/layouts/basic.blade.php @@ -45,7 +45,7 @@ @if (($snipeSettings) && ($snipeSettings->logo!=''))
- +
@endif diff --git a/resources/views/layouts/default.blade.php b/resources/views/layouts/default.blade.php index f74fc9ce67..ca06e2e6f0 100644 --- a/resources/views/layouts/default.blade.php +++ b/resources/views/layouts/default.blade.php @@ -96,14 +96,14 @@ @if ($snipeSettings->brand == '3')
@elseif ($snipeSettings->brand == '2') @else diff --git a/resources/views/locations/edit.blade.php b/resources/views/locations/edit.blade.php index 253a069ce0..3990c5b8fb 100755 --- a/resources/views/locations/edit.blade.php +++ b/resources/views/locations/edit.blade.php @@ -54,9 +54,9 @@ @if ($item->image)
-
+
{{ Form::checkbox('image_delete') }} - + {!! $errors->first('image_delete', ':message') !!}
diff --git a/resources/views/manufacturers/edit.blade.php b/resources/views/manufacturers/edit.blade.php index af212be8fc..eb8fa88b41 100755 --- a/resources/views/manufacturers/edit.blade.php +++ b/resources/views/manufacturers/edit.blade.php @@ -56,7 +56,7 @@
{{ Form::checkbox('image_delete') }} - + {!! $errors->first('image_delete', ':message') !!}
diff --git a/resources/views/models/edit.blade.php b/resources/views/models/edit.blade.php index ae271c5835..ccf8728c8b 100755 --- a/resources/views/models/edit.blade.php +++ b/resources/views/models/edit.blade.php @@ -62,7 +62,7 @@
{{ Form::checkbox('image_delete') }} - + {!! $errors->first('image_delete', '
:message
') !!}