Merge branch 'develop' of github.com:snipe/snipe-it into develop

This commit is contained in:
snipe 2017-01-25 21:33:25 -08:00
commit a688822899
37 changed files with 53685 additions and 1180 deletions

View file

@ -68,15 +68,17 @@ class Handler extends ExceptionHandler
switch ($e->getStatusCode()) { switch ($e->getStatusCode()) {
case '404': case '404':
return response()->json(Helper::formatStandardApiResponse('error', null, $statusCode . ' endpoint not found'), 404); return response()->json(Helper::formatStandardApiResponse('error', null, $statusCode . ' endpoint not found'), 404);
break;
case '405': case '405':
return response()->json(Helper::formatStandardApiResponse('error', null, 'Method not allowed'), 405); return response()->json(Helper::formatStandardApiResponse('error', null, 'Method not allowed'), 405);
break;
default: default:
return response()->json(Helper::formatStandardApiResponse('error', null, $e->getStatusCode()), 405); return response()->json(Helper::formatStandardApiResponse('error', null, $statusCode), 405);
} }
} }
// Try to parse 500 Errors ina bit nicer way when debug is enabled.
if (config('app.debug')) {
return response()->json(Helper::formatStandardApiResponse('error', null, "An Error has occured! " . $e->getMessage()), 500);
}
} }

View file

@ -2,16 +2,34 @@
namespace App\Http\Controllers\Api; namespace App\Http\Controllers\Api;
use App\Helpers\Helper; use App\Helpers\Helper;
use App\Http\Controllers\Controller;
use App\Http\Requests\AssetRequest; use App\Http\Requests\AssetRequest;
use App\Http\Transformers\AssetsTransformer;
use App\Models\Asset; use App\Models\Asset;
use App\Models\AssetModel; use App\Models\AssetModel;
use App\Models\Company; use App\Models\Company;
use App\Models\CustomField; use App\Models\CustomField;
use App\Models\Location; use App\Models\Location;
use App\Models\Setting;
use App\Models\User; use App\Models\User;
use Artisan;
use Auth;
use Carbon\Carbon;
use Config;
use DB;
use Gate;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use App\Http\Controllers\Controller; use Input;
use App\Http\Transformers\AssetsTransformer; use Lang;
use Log;
use Mail;
use Paginator;
use Response;
use Slack;
use Str;
use TCPDF;
use Validator;
use View;
/** /**
* This class controls all actions related to assets for * This class controls all actions related to assets for
@ -332,6 +350,4 @@ class AssetsController extends Controller
} }
} }

View file

@ -0,0 +1,141 @@
<?php
namespace App\Http\Controllers\Api;
use App\Helpers\Helper;
use App\Http\Controllers\Controller;
use App\Http\Requests\ItemImportRequest;
use App\Http\Transformers\ImportsTransformer;
use App\Models\Company;
use App\Models\Import;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Input;
use Illuminate\Support\Facades\Session;
use Symfony\Component\HttpFoundation\File\Exception\FileException;
class ImportController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
//
$imports = Import::latest()->get();
return (new ImportsTransformer)->transformImports($imports);
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store()
{
//
if (!Company::isCurrentUserAuthorized()) {
return redirect()->route('hardware.index')->with('error', trans('general.insufficient_permissions'));
} elseif (!config('app.lock_passwords')) {
$files = Input::file('files');
$path = config('app.private_uploads').'/imports';
$results = [];
$import = new Import;
foreach ($files as $file) {
if (!in_array($file->getMimeType(), array(
'application/vnd.ms-excel',
'text/csv',
'text/plain',
'text/comma-separated-values',
'text/tsv'))) {
$results['error']='File type must be CSV';
return $results;
}
$date = date('Y-m-d-his');
$fixed_filename = str_replace(' ', '-', $file->getClientOriginalName());
try {
$file->move($path, $date.'-'.$fixed_filename);
} catch (FileException $exception) {
$results['error']=trans('admin/hardware/message.upload.error');
if (config('app.debug')) {
$results['error'].= ' ' . $exception->getMessage();
}
return response()->json(Helper::formatStandardApiResponse('error', null, $results['error']), 500);
}
$file_name = date('Y-m-d-his').'-'.$fixed_filename;
$import->file_path = $file_name;
$import->filesize = filesize($path.'/'.$file_name);
$import->save();
$results[] = $import;
}
$results = (new ImportsTransformer)->transformImports($results);
return [
'files' => $results
];
}
$results['error']=trans('general.feature_disabled');
return $results;
}
/**
* Processes the specified Import.
*
* @param \App\Import $import
* @return \Illuminate\Http\Response
*/
public function process(ItemImportRequest $request, $import_id)
{
$this->authorize('create', Asset::class);
$errors = $request->import(Import::find($import_id));
$redirectTo = "hardware";
switch ($request->get('import-type')) {
case "asset":
$redirectTo = "hardware.index";
break;
case "accessory":
$redirectTo = "accessories.index";
break;
case "consumable":
$redirectTo = "consumables.index";
break;
case "component":
$redirectTo = "components.index";
break;
case "license":
$redirectTo = "licenses.index";
break;
}
if ($errors) { //Failure
return response()->json(Helper::formatStandardApiResponse('import-errors', null, $errors), 500);
}
//Flash message before the redirect
Session::flash('success', trans('admin/hardware/message.import.success'));
return response()->json(Helper::formatStandardApiResponse('success', null, ['redirect_url' => route($redirectTo)]));
}
/**
* Remove the specified resource from storage.
*
* @param \App\Import $import
* @return \Illuminate\Http\Response
*/
public function destroy($import_id)
{
$this->authorize('create', Asset::class);
$import = Import::find($import_id);
try {
unlink(config('app.private_uploads').'/imports/'.$import->file_path);
$import->delete();
return response()->json(Helper::formatStandardApiResponse('success', null, trans('message.import.file_delete_success')));
} catch (\Exception $e) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/hardware/message.import.file_delete_error')), 500);
}
}
}

View file

@ -681,103 +681,9 @@ class AssetsController extends Controller
public function getImportUpload() public function getImportUpload()
{ {
$this->authorize('create', Asset::class); $this->authorize('create', Asset::class);
$path = config('app.private_uploads').'/imports/assets'; return View::make('hardware/import');
$files = array();
if (!Company::isCurrentUserAuthorized()) {
return redirect()->route('hardware.index')->with('error', trans('general.insufficient_permissions'));
} }
// Check if the uploads directory exists. If not, try to create it.
if (!file_exists($path)) {
mkdir($path, 0755, true);
}
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)=='csv') {
$files[] = array(
'filename' => $entry,
'filesize' => Setting::fileSizeConvert(filesize($path.'/'.$entry)),
'modified' => filemtime($path.'/'.$entry)
);
}
}
closedir($handle);
$files = array_reverse($files);
}
return View::make('hardware/import')->with('files', $files);
}
/**
* Upload the import file via AJAX
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v2.0]
* @param AssetFileRequest $request
* @return array
*/
public function postAPIImportUpload(AssetFileRequest $request)
{
if (!Company::isCurrentUserAuthorized()) {
return redirect()->route('hardware.index')->with('error', trans('general.insufficient_permissions'));
} elseif (!config('app.lock_passwords')) {
$files = Input::file('files');
$path = config('app.private_uploads').'/imports/assets';
$results = array();
foreach ($files as $file) {
if (!in_array($file->getMimeType(), array(
'application/vnd.ms-excel',
'text/csv',
'text/plain',
'text/comma-separated-values',
'text/tsv'))) {
$results['error']='File type must be CSV';
return $results;
}
$date = date('Y-m-d-his');
$fixed_filename = str_replace(' ', '-', $file->getClientOriginalName());
try {
$file->move($path, $date.'-'.$fixed_filename);
} catch (FileException $exception) {
$results['error']=trans('admin/hardware/message.upload.error');
if (config('app.debug')) {
$results['error'].= ' ' . $exception->getMessage();
}
return $results;
}
$name = date('Y-m-d-his').'-'.$fixed_filename;
$filesize = Setting::fileSizeConvert(filesize($path.'/'.$name));
$results[] = compact('name', 'filesize');
}
return [
'files' => $results
];
}
$results['error']=trans('general.feature_disabled');
return $results;
}
public function getDeleteImportFile($filename)
{
$this->authorize('create', Asset::class);
if (unlink(config('app.private_uploads').'/imports/assets/'.$filename)) {
return redirect()->back()->with('success', trans('admin/hardware/message.import.file_delete_success'));
}
return redirect()->back()->with('error', trans('admin/hardware/message.import.file_delete_error'));
}
/** /**
* Process the uploaded file * Process the uploaded file
* *

View file

@ -2,6 +2,7 @@
namespace App\Http\Requests; namespace App\Http\Requests;
use App\Models\Import;
use Illuminate\Foundation\Http\FormRequest; use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
@ -29,10 +30,9 @@ class ItemImportRequest extends FormRequest
]; ];
} }
public function import() public function import(Import $import)
{ {
$filename = config('app.private_uploads') . '/imports/' . $import->file_path;
$filename = config('app.private_uploads') . '/imports/assets/' . $this->get('filename');
$class = title_case($this->input('import-type')); $class = title_case($this->input('import-type'));
$classString = "App\\Importer\\{$class}Importer"; $classString = "App\\Importer\\{$class}Importer";
$importer = new $classString($filename); $importer = new $classString($filename);
@ -58,6 +58,7 @@ class ItemImportRequest extends FormRequest
public function errorCallback($item, $field, $errorString) public function errorCallback($item, $field, $errorString)
{ {
$this->errors[$item->name][$field] = $errorString; $this->errors[$item->name][$field] = $errorString;
// $this->errors[$item->name] = $errorString;
} }
private $errors; private $errors;

View file

@ -0,0 +1,39 @@
<?php
namespace App\Http\Transformers;
use App\Models\Import;
use App\Models\Setting;
use Illuminate\Database\Eloquent\Collection;
class ImportsTransformer
{
public function transformImports($imports)
{
$array = array();
foreach ($imports as $import) {
$array[] = self::transformImport($import);
}
return $array;
}
public function transformImport(Import $import)
{
$array = [
'id' => $import->id,
'file_path' => $import->file_path,
'filesize' => Setting::fileSizeConvert($import->filesize),
'name' => $import->name,
'import_type' => $import->import_type,
'created_at' => $import->created_at->diffForHumans(),
];
return $array;
}
public function transformImportsDatatable($imports)
{
return (new DatatablesTransformer)->transformDatatables($imports);
}
}

View file

@ -6,14 +6,16 @@ use App\Helpers\Helper;
use App\Models\Asset; use App\Models\Asset;
use App\Models\Category; use App\Models\Category;
use App\Models\Manufacturer; use App\Models\Manufacturer;
use App\Models\Statuslabel;
class AssetImporter extends ItemImporter class AssetImporter extends ItemImporter
{ {
protected $assets; protected $defaultStatusLabelId;
public function __construct($filename) public function __construct($filename)
{ {
parent::__construct($filename); parent::__construct($filename);
$this->assets = Asset::all(); $this->defaultStatusLabelId = Statuslabel::first()->id;
} }
protected function handle($row) protected function handle($row)
@ -41,11 +43,8 @@ class AssetImporter extends ItemImporter
public function createAssetIfNotExists(array $row) public function createAssetIfNotExists(array $row)
{ {
$editingAsset = false; $editingAsset = false;
$asset = new Asset; $asset = Asset::where(['asset_tag'=> $this->item['asset_tag']])->first();
$asset_id = $this->assets->search(function ($key) { if ($asset) {
return strcasecmp($key->asset_tag, $this->item['asset_tag']) == 0;
});
if ($asset_id !== false) {
if (!$this->updating) { if (!$this->updating) {
$this->log('A matching Asset ' . $this->item['asset_tag'] . ' already exists'); $this->log('A matching Asset ' . $this->item['asset_tag'] . ' already exists');
return; return;
@ -53,9 +52,9 @@ class AssetImporter extends ItemImporter
$this->log("Updating Asset"); $this->log("Updating Asset");
$editingAsset = true; $editingAsset = true;
$asset = $this->assets[$asset_id];
} else { } else {
$this->log("No Matching Asset, Creating a new one"); $this->log("No Matching Asset, Creating a new one");
$asset = new Asset;
} }
$this->item['serial'] = $this->array_smart_fetch($row, "serial number"); $this->item['serial'] = $this->array_smart_fetch($row, "serial number");
$this->item['image'] = $this->array_smart_fetch($row, "image"); $this->item['image'] = $this->array_smart_fetch($row, "image");
@ -65,13 +64,11 @@ class AssetImporter extends ItemImporter
} }
if (isset($this->item["status_label"])) { if (isset($this->item["status_label"])) {
$this->item['status_id'] = $this->item["status_label"]->id; $this->item['status_id'] = $this->item["status_label"]->id;
} elseif (!$editingAsset) {
// Assume if we are editing, we already have a status and can ignore.
$this->log("No status field found, defaulting to first status.");
$this->item['status_id'] = $this->defaultStatusLabelId;
} }
// We should require a status or come up with a better way of doing this..
// elseif (!$editingAsset) {
// // Assume if we are editing, we already have a status and can ignore.
// $this->log("No status field found, defaulting to first status.");
// $status_id = $this->status_labels->first()->id;
// }
// By default we're set this to location_id in the item. // By default we're set this to location_id in the item.
@ -90,9 +87,7 @@ class AssetImporter extends ItemImporter
$asset->{$custom_field} = $val; $asset->{$custom_field} = $val;
} }
} }
if (!$editingAsset) {
$this->assets->add($asset);
}
if (!$this->testRun) { if (!$this->testRun) {
if ($asset->save()) { if ($asset->save()) {
$asset->logCreate('Imported using csv importer'); $asset->logCreate('Imported using csv importer');

View file

@ -1,15 +1,9 @@
<?php <?php
namespace App\Importer; namespace App\Importer;
use App\Models\AssetModel;
use App\Models\Category;
use App\Models\Company;
use App\Models\CustomField; use App\Models\CustomField;
use App\Models\Location;
use App\Models\Manufacturer;
use App\Models\Setting; use App\Models\Setting;
use App\Models\Statuslabel;
use App\Models\Supplier;
use App\Models\User; use App\Models\User;
use ForceUTF8\Encoding; use ForceUTF8\Encoding;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
@ -60,15 +54,9 @@ abstract class Importer
/** /**
* ObjectImporter constructor. * ObjectImporter constructor.
* @param string $filename * @param string $filename
* @param callable $logCallback
* @param callable $progressCallback
* @param callable $errorCallback
* @param bool $testRun
* @param int $user_id
* @param bool $updating
* @param null $usernameFormat
*/ */
function __construct(string $filename) { public function __construct(string $filename)
{
$this->filename = $filename; $this->filename = $filename;
$this->csv = Reader::createFromPath($filename); $this->csv = Reader::createFromPath($filename);
@ -79,22 +67,12 @@ abstract class Importer
$this->tempPassword = substr(str_shuffle("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), 0, 20); $this->tempPassword = substr(str_shuffle("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), 0, 20);
} }
// Cached Values for import lookups // Cached Values for import lookups
protected $locations;
protected $categories;
protected $manufacturers;
protected $asset_models;
protected $companies;
protected $status_labels;
protected $suppliers;
protected $assets;
protected $accessories;
protected $consumables;
protected $customFields; protected $customFields;
public function import() public function import()
{ {
$results = $this->normalizeInputArray($this->csv->fetchAssoc()); $results = $this->normalizeInputArray($this->csv->fetchAssoc());
$this->initializeLookupArrays(); $this->customFields = CustomField::All(['name']);
DB::transaction(function () use (&$results) { DB::transaction(function () use (&$results) {
Model::unguard(); Model::unguard();
$resultsCount = sizeof($results); $resultsCount = sizeof($results);
@ -123,22 +101,6 @@ abstract class Importer
return $newArray; return $newArray;
} }
/**
* Load Cached versions of all used methods.
*/
public function initializeLookupArrays()
{
$this->locations = Location::All(['name', 'id']);
$this->categories = Category::All(['name', 'category_type', 'id']);
$this->manufacturers = Manufacturer::All(['name', 'id']);
$this->asset_models = AssetModel::All(['name', 'model_number', 'category_id', 'manufacturer_id', 'id']);
$this->companies = Company::All(['name', 'id']);
$this->status_labels = Statuslabel::All(['name', 'id']);
$this->suppliers = Supplier::All(['name', 'id']);
$this->customFields = CustomField::All(['name']);
}
/** /**
* Check to see if the given key exists in the array, and trim excess white space before returning it * Check to see if the given key exists in the array, and trim excess white space before returning it
* *
@ -156,7 +118,7 @@ abstract class Importer
$val = e(Encoding::toUTF8(trim($array[ $key ]))); $val = e(Encoding::toUTF8(trim($array[ $key ])));
} }
$key = title_case($key); $key = title_case($key);
$this->log("${key}: ${val}"); // $this->log("${key}: ${val}");
return $val; return $val;
} }

View file

@ -129,6 +129,9 @@ class ItemImporter extends Importer
*/ */
private function shouldUpdateField($field) private function shouldUpdateField($field)
{ {
if (empty($field)) {
return false;
}
return !($this->updating && empty($field)); return !($this->updating && empty($field));
} }
/** /**
@ -156,23 +159,18 @@ class ItemImporter extends Importer
$asset_model_name ='Unknown'; $asset_model_name ='Unknown';
} }
$editingModel = $this->updating; $editingModel = $this->updating;
$asset_model_id = $this->asset_models->search(function ($key) use ($asset_model_name, $asset_modelNumber) { $asset_model = AssetModel::where(['name' => $asset_model_name, 'model_number' => $asset_modelNumber])->first();
return strcasecmp($key->name, $asset_model_name) ==0
&& $key->model_number == $asset_modelNumber; if ($asset_model) {
});
// We need strict compare here because the index returned above can be 0.
// This casts to false and causes false positives
$asset_model = new AssetModel;
$item = $this->sanitizeItemForStoring($asset_model, $editingModel);
$item['name'] = $asset_model_name;
$item['model_number'] = $asset_modelNumber;
if ($asset_model_id !== false) {
$asset_model = $this->asset_models[$asset_model_id];
if (!$this->updating) { if (!$this->updating) {
$this->log("A matching model already exists, returning it."); $this->log("A matching model already exists, returning it.");
return $asset_model; return $asset_model;
} }
$this->log("Matching Model found, updating it."); $this->log("Matching Model found, updating it.");
$item = $this->sanitizeItemForStoring($asset_model, $editingModel);
$item['name'] = $asset_model_name;
$item['model_number'] = $asset_modelNumber;
$asset_model->update($item); $asset_model->update($item);
if (!$this->testRun) { if (!$this->testRun) {
$asset_model->save(); $asset_model->save();
@ -180,9 +178,13 @@ class ItemImporter extends Importer
return $asset_model; return $asset_model;
} }
$this->log("No Matching Model, Creating a new one"); $this->log("No Matching Model, Creating a new one");
$asset_model = new AssetModel(); $asset_model = new AssetModel();
$item = $this->sanitizeItemForStoring($asset_model, $editingModel);
$item['name'] = $asset_model_name;
$item['model_number'] = $asset_modelNumber;
$asset_model->fill($item); $asset_model->fill($item);
$this->asset_models->add($asset_model);
if ($this->testRun) { if ($this->testRun) {
$this->log('TEST RUN - asset_model ' . $asset_model->name . ' not created'); $this->log('TEST RUN - asset_model ' . $asset_model->name . ' not created');
@ -214,15 +216,11 @@ class ItemImporter extends Importer
if (empty($asset_category)) { if (empty($asset_category)) {
$asset_category = 'Unnamed Category'; $asset_category = 'Unnamed Category';
} }
$category = $this->categories->search(function ($key) use ($asset_category, $item_type) { $category = Category::where(['name' => $asset_category, 'category_type' => $item_type])->first();
return (strcasecmp($key->name, $asset_category) == 0)
&& $key->category_type === $item_type; if ($category) {
});
// We need strict compare here because the index returned above can be 0.
// This casts to false and causes false positives
if ($category !== false) {
$this->log("A matching category: " . $asset_category . " already exists"); $this->log("A matching category: " . $asset_category . " already exists");
return $this->categories[$category]; return $category;
} }
$category = new Category(); $category = new Category();
@ -231,11 +229,9 @@ class ItemImporter extends Importer
$category->user_id = $this->user_id; $category->user_id = $this->user_id;
if ($this->testRun) { if ($this->testRun) {
$this->categories->add($category);
return $category; return $category;
} }
if ($category->save()) { if ($category->save()) {
$this->categories->add($category);
$this->log('Category ' . $asset_category . ' was created'); $this->log('Category ' . $asset_category . ' was created');
return $category; return $category;
} }
@ -253,24 +249,19 @@ class ItemImporter extends Importer
*/ */
public function createOrFetchCompany($asset_company_name) public function createOrFetchCompany($asset_company_name)
{ {
$company = $this->companies->search(function ($key) use ($asset_company_name) { $company = Company::where(['name' => $asset_company_name])->first();
return strcasecmp($key->name, $asset_company_name) == 0; if ($company) {
});
// We need strict compare here because the index returned above can be 0.
// This casts to false and causes false positives
if ($company !== false) {
$this->log('A matching Company ' . $asset_company_name . ' already exists'); $this->log('A matching Company ' . $asset_company_name . ' already exists');
return $this->companies[$company]; return $company;
} }
$company = new Company(); $company = new Company();
$company->name = $asset_company_name; $company->name = $asset_company_name;
if ($this->testRun) { if ($this->testRun) {
$this->companies->add($company);
return $company; return $company;
} }
if ($company->save()) { if ($company->save()) {
$this->companies->add($company);
$this->log('Company ' . $asset_company_name . ' was created'); $this->log('Company ' . $asset_company_name . ' was created');
return $company; return $company;
} }
@ -291,14 +282,11 @@ class ItemImporter extends Importer
if (empty($asset_statuslabel_name)) { if (empty($asset_statuslabel_name)) {
return null; return null;
} }
$status = $this->status_labels->search(function ($key) use ($asset_statuslabel_name) { $status = Statuslabel::where(['name' => $asset_statuslabel_name])->first();
return strcasecmp($key->name, $asset_statuslabel_name) == 0;
}); if ($status) {
// We need strict compare here because the index returned above can be 0.
// This casts to false and causes false positives
if ($status !== false) {
$this->log('A matching Status ' . $asset_statuslabel_name . ' already exists'); $this->log('A matching Status ' . $asset_statuslabel_name . ' already exists');
return $this->status_labels[$status]; return $status;
} }
$this->log("Creating a new status"); $this->log("Creating a new status");
$status = new Statuslabel(); $status = new Statuslabel();
@ -309,12 +297,10 @@ class ItemImporter extends Importer
$status->archived = 0; $status->archived = 0;
if ($this->testRun) { if ($this->testRun) {
$this->status_labels->add($status);
return $status; return $status;
} }
if ($status->save()) { if ($status->save()) {
$this->status_labels->add($status);
$this->log('Status ' . $asset_statuslabel_name . ' was created'); $this->log('Status ' . $asset_statuslabel_name . ' was created');
return $status; return $status;
} }
@ -338,14 +324,11 @@ class ItemImporter extends Importer
if (empty($item_manufacturer)) { if (empty($item_manufacturer)) {
$item_manufacturer='Unknown'; $item_manufacturer='Unknown';
} }
$manufacturer = $this->manufacturers->search(function ($key) use ($item_manufacturer) { $manufacturer = Manufacturer::where(['name'=> $item_manufacturer])->first();
return strcasecmp($key->name, $item_manufacturer) == 0;
}); if ($manufacturer) {
// We need strict compare here because the index returned above can be 0.
// This casts to false and causes false positives
if ($manufacturer !== false) {
$this->log('Manufacturer ' . $item_manufacturer . ' already exists') ; $this->log('Manufacturer ' . $item_manufacturer . ' already exists') ;
return $this->manufacturers[$manufacturer]; return $manufacturer;
} }
//Otherwise create a manufacturer. //Otherwise create a manufacturer.
@ -354,11 +337,9 @@ class ItemImporter extends Importer
$manufacturer->user_id = $this->user_id; $manufacturer->user_id = $this->user_id;
if ($this->testRun) { if ($this->testRun) {
$this->manufacturers->add($manufacturer);
return $manufacturer; return $manufacturer;
} }
if ($manufacturer->save()) { if ($manufacturer->save()) {
$this->manufacturers->add($manufacturer);
$this->log('Manufacturer ' . $manufacturer->name . ' was created'); $this->log('Manufacturer ' . $manufacturer->name . ' was created');
return $manufacturer; return $manufacturer;
} }
@ -380,14 +361,11 @@ class ItemImporter extends Importer
$this->log('No location given, so none created.'); $this->log('No location given, so none created.');
return null; return null;
} }
$location = $this->locations->search(function ($key) use ($asset_location) { $location = Location::where(['name' => $asset_location])->first();
return strcasecmp($key->name, $asset_location) == 0;
});
// We need strict compare here because the index returned above can be 0.
// This casts to false and causes false positives
if ($location !== false) { if ($location !== false) {
$this->log('Location ' . $asset_location . ' already exists'); $this->log('Location ' . $asset_location . ' already exists');
return $this->locations[$location]; return $location;
} }
// No matching locations in the collection, create a new one. // No matching locations in the collection, create a new one.
$location = new Location(); $location = new Location();
@ -399,11 +377,9 @@ class ItemImporter extends Importer
$location->user_id = $this->user_id; $location->user_id = $this->user_id;
if ($this->testRun) { if ($this->testRun) {
$this->locations->add($location);
return $location; return $location;
} }
if ($location->save()) { if ($location->save()) {
$this->locations->add($location);
$this->log('Location ' . $asset_location . ' was created'); $this->log('Location ' . $asset_location . ' was created');
return $location; return $location;
} }
@ -425,14 +401,11 @@ class ItemImporter extends Importer
$item_supplier='Unknown'; $item_supplier='Unknown';
} }
$supplier = $this->suppliers->search(function ($key) use ($item_supplier) { $supplier = Supplier::where(['name' => $item_supplier ])->first();
return strcasecmp($key->name, $item_supplier) == 0;
}); if ($supplier) {
// We need strict compare here because the index returned above can be 0.
// This casts to false and causes false positives
if ($supplier !== false) {
$this->log('Supplier ' . $item_supplier . ' already exists'); $this->log('Supplier ' . $item_supplier . ' already exists');
return $this->suppliers[$supplier]; return $supplier;
} }
$supplier = new Supplier(); $supplier = new Supplier();
@ -440,11 +413,9 @@ class ItemImporter extends Importer
$supplier->user_id = $this->user_id; $supplier->user_id = $this->user_id;
if ($this->testRun) { if ($this->testRun) {
$this->suppliers->add($supplier);
return $supplier; return $supplier;
} }
if ($supplier->save()) { if ($supplier->save()) {
$this->suppliers->add($supplier);
$this->log('Supplier ' . $item_supplier . ' was created'); $this->log('Supplier ' . $item_supplier . ' was created');
return $supplier; return $supplier;
} }

View file

@ -31,8 +31,8 @@ class Category extends SnipeModel
public $rules = array( public $rules = array(
'user_id' => 'numeric|nullable', 'user_id' => 'numeric|nullable',
'name' => 'required|min:1|max:255|unique_undeleted', 'name' => 'required|min:1|max:255|unique_undeleted',
'require_acceptance' => 'required|boolean', 'require_acceptance' => 'boolean',
'use_default_eula' => 'required|boolean', 'use_default_eula' => 'boolean',
'category_type' => 'required|in:asset,accessory,consumable,component', 'category_type' => 'required|in:asset,accessory,consumable,component',
); );

9
app/Models/Import.php Normal file
View file

@ -0,0 +1,9 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Import extends Model
{
}

View file

@ -0,0 +1,35 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateImportsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('imports', function (Blueprint $table) {
$table->increments('id');
$table->string('name')->nullable();
$table->string('file_path');
$table->integer('filesize');
$table->string('import_type')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('imports');
}
}

View file

@ -15,8 +15,11 @@
"laravel-elixir-vue-2": "^0.2.0", "laravel-elixir-vue-2": "^0.2.0",
"laravel-elixir-webpack-official": "^1.0.2", "laravel-elixir-webpack-official": "^1.0.2",
"lodash": "^4.16.2", "lodash": "^4.16.2",
"vue": "^2.0.1", "vue": "=2.1.6",
"vue-resource": "^1.0.3" "vue-loader": "^10.0.2",
"vue-resource": "^1.0.3",
"vue-strap": "github:wffranco/vue-strap.git",
"vue-template-compiler": "=2.1.6"
}, },
"dependencies": { "dependencies": {
"jquery": "^3.1.1", "jquery": "^3.1.1",

Binary file not shown.

File diff suppressed because it is too large Load diff

Before

Width:  |  Height:  |  Size: 357 KiB

After

Width:  |  Height:  |  Size: 434 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1,4 +1,4 @@
{ {
"assets/css/app.css": "assets/css/app-fc4d2fdcc4.css", "assets/css/app.css": "assets/css/app-fc4d2fdcc4.css",
"assets/js/all.js": "assets/js/all-93b23559b9.js" "assets/js/all.js": "assets/js/all-5e5715ba54.js"
} }

View file

@ -0,0 +1,36 @@
<style scoped>
</style>
<template>
<div class="col-md-12" :class="alertType">
<div class="alert" :class="alertClassName">
<button type="button" class="close" @click="hideEvent">&times;</button>
<i class="fa fa-check faa-pulse animated" v-show="alertType == 'success'"></i>
<strong>{{ title }} </strong>
<slot></slot>
</div>
</div>
</template>
<script>
export default {
/*
* The component's data.
*/
props: ['alertType', 'title'],
computed: {
alertClassName() {
return 'alert-' + this.alertType;
}
},
methods: {
hideEvent() {
this.$emit('hide');
}
}
}
</script>

View file

@ -0,0 +1,42 @@
<style scoped>
</style>
<template>
<div class="box" v-if="errors">
<div class="box-body">
<div class="alert alert-warning">
<strong>Warning</strong> Some Errors occured while importing
</div>
<div class="errors-table">
<table class="table table-striped table-bordered" id="errors-table">
<thead>
<th>Item</th>
<th>Errors</th>
</thead>
<tbody>
<tr v-for="(error, item) in errors">
<td>{{ item }}</td>
<td v-for="(value, field) in error">
<b>{{ field }}:</b>
<span v-for="errorString in value">{{errorString[0]}}</span>
<br />
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</template>
<script>
export default {
/*
* The component's data.
*/
props: ['errors'],
}
</script>

View file

@ -0,0 +1,227 @@
<style scoped>
</style>
<template>
<div>
<alert v-show="alert.visible" :alertType="alert.type" v-on:hide="alert.visible = false">{{ alert.message }}</alert>
<errors :errors="importErrors"></errors>
<modal v-model="displayImportModal" effect="fade">
<div slot="modal-header" class="modal-title">Import File:</div>
<div slot="modal-body" class="modal-body">
<div class="dynamic-form-row">
<div class="col-md-4 col-xs-12">
<label for="import-type">Import Type:</label>
</div>
<div class="col-md-8 col-xs-12">
<select2 :options="modal.importTypes" v-model="modal.importType">
<option disabled value="0"></option>
</select2>
</div>
</div>
<div class="dynamic-form-row">
<div class="col-md-4 col-xs-12">
<label for="import-update">Update Existing Values?:</label>
</div>
<div class="col-md-8 col-xs-12">
<input type="checkbox" name="import-update" v-model="modal.update">
</div>
</div>
</div>
<div slot="modal-footer" class="modal-footer">
<div class="row">
<div class="alert alert-success col-md-5 col-md-offset-1" style="text-align:left" v-if="modal.statusText">{{ this.modal.statusText }}</div>
<button type="button" class="btn btn-default" @click="displayImportModal = false">Cancel</button>
<button type="submit" class="btn btn-primary" @click="postSave">Save</button>
</div>
</div>
</modal>
<div class="row">
<div class="col-md-12">
<div class="box">
<div class="box-body">
<div class="col-md-3">
<!-- The fileinput-button span is used to style the file input field as button -->
<span class="btn btn-info fileinput-button">
<i class="fa fa-plus icon-white"></i>
<span>Select Import File...</span>
<!-- The file input field used as target for the file upload widget -->
<input id="fileupload" type="file" name="files[]" data-url="/api/v1/imports" accept="text/csv">
</span>
</div>
<div class="col-md-9" v-show="progress.visible" style="padding-bottom:20px">
<div class="col-md-11">
<div class="progress progress-striped-active" style="margin-top: 8px">
<div class="progress-bar" :class="progress.currentClass" role="progressbar" :style="progressWidth">
<span>{{ progress.statusText }}</span>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<table class="table table-striped" id="upload-table">
<thead>
<th>File</th>
<th>Created</th>
<th>Size</th>
<th></th>
</thead>
<tbody>
<tr v-for="file in files">
<td>{{ file.file_path }}</td>
<td>{{ file.created_at }} </td>
<td>{{ file.filesize }}</td>
<td>
<button class="btn btn-sm btn-info" @click="showModal(file)"><i class="fa fa-spinner process"></i>Process</button>
<button class="btn btn-danger btn-sm" @click="deleteFile(file)"><i class="fa fa-trash icon-white"></i></button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
require('blueimp-file-upload');
var modal = require('vue-strap').modal
export default {
/*
* The component's data.
*/
data() {
return {
files: [],
displayImportModal: false,
activeFile: null,
alert: {
type: null,
message: null,
visible: false,
},
modal: {
importType: 'asset',
update: false,
importTypes: [
{ id: 'asset', text: 'Assets' },
{ id: 'accessory', text: 'Accessories' },
{ id: 'consumable', text: 'Consumable' },
{ id: 'component', text: 'Components' },
{ id: 'license', text: 'Licenses' }
],
statusText: null,
},
importErrors: null,
progress: {
currentClass: "progress-bar-warning",
currentPercent: "0",
statusText: '',
visible: false
}
};
},
/**
* Prepare the component (Vue 2.x).
*/
mounted() {
this.fetchFiles();
let vm = this;
$('#fileupload').fileupload({
dataType: 'json',
done(e, data) {
vm.progress.currentClass="progress-bar-success";
vm.progress.statusText = "Success!";
vm.files = data.result.files.concat(vm.files);
},
add(e, data) {
data.headers = {
"X-Requested-With": 'XMLHttpRequest',
"X-CSRF-TOKEN": Laravel.csrfToken
};
data.process().done( () => {data.submit();});
vm.progress.visible=true;
},
progress(e, data) {
var progress = parseInt((data.loaded / data.total * 100, 10));
vm.progress.currentPercent = progress;
vm.progress.statusText = progress+'% Complete';
},
fail(e, data) {
vm.progress.currentClass = "progress-bar-danger";
vm.progress.statusText = data.errorThrown;
}
})
},
methods: {
fetchFiles() {
this.$http.get('/api/v1/imports')
.then( ({data}) => this.files = data, // Success
//Fail
(response) => {
this.alert.type="danger";
this.alert.visible=true;
this.alert.message="Something went wrong fetching files...";
});
},
deleteFile(file, key) {
this.$http.delete("/api/v1/imports/"+file.id)
.then((response) => this.files.splice(key, 1), // Success
(response) => {// Fail
this.alert.type="danger";
this.alert.visible=true;
this.alert.message=response.body.messages;
}
);
},
showModal(file) {
this.activeFile = file;
this.displayImportModal = true;
},
postSave() {
this.$http.post('/api/v1/imports/process/'+this.activeFile.id, {
'import-update': this.modal.update,
'import-type': this.modal.importType
}).then( (response) => {
// Success
this.modal.statusText = "Success... Redirecting.";
window.location.href = response.body.messages.redirect_url;
}, (response) => {
// Failure
if(response.body.status == 'import-errors') {
this.importErrors = response.body.messages;
} else {
this.alert.message= response.body.messages;
this.alert.type="danger";
this.alert.visible=true;
}
this.displayImportModal=false;
});
}
},
computed: {
progressWidth() {
return "width: "+this.progress.currentPercent*10+'%';
}
},
components: {
modal,
errors: require('./importer-errors.vue'),
alert: require('../alert.vue'),
select2: require('../select2.vue')
}
}
</script>

View file

@ -0,0 +1,40 @@
<style scoped>
</style>
<template>
<select style="width:100%">
<slot></slot>
</select>
</template>
<script>
require('select2');
export default {
/*
* The component's data.
*/
props: ['options', 'value'],
mounted() {
var vm = this;
$(this.$el)
.select2({
data: this.options
})
.on('change', function() { vm.$emit('input', this.value) } );
},
watch: {
value: function (value) {
$(this.$el).val(value)
},
options: function (options) {
$(this.$el).select2({data: options})
},
destroyed: function() {
$(this.$el).off().select2('destroy')
}
}
}
</script>

View file

@ -138,7 +138,13 @@ $(document).ready(function () {
var iOS = /iPhone|iPad|iPod/.test(navigator.userAgent) && !window.MSStream; var iOS = /iPhone|iPad|iPod/.test(navigator.userAgent) && !window.MSStream;
if(!iOS) if(!iOS)
{ {
$(".select2").select2(); // Vue collision: Avoid overriding a vue select2 instance
// by checking to see if the item has already been select2'd.
$('select2:not([class^="select2-container"])').each((i,obj) => {
{
$(obj).select2();
}
});
} }
$('.datepicker').datepicker(); $('.datepicker').datepicker();

File diff suppressed because one or more lines are too long

View file

@ -6,13 +6,11 @@
*/ */
require('./bootstrap'); require('./bootstrap');
/** /**
* Next, we will create a fresh Vue application instance and attach it to * Next, we will create a fresh Vue application instance and attach it to
* the page. Then, you may begin adding components to this application * the page. Then, you may begin adding components to this application
* or customize the JavaScript scaffolding to fit your unique needs. * or customize the JavaScript scaffolding to fit your unique needs.
*/ */
Vue.component( Vue.component(
'passport-clients', 'passport-clients',
require('./components/passport/Clients.vue') require('./components/passport/Clients.vue')
@ -28,7 +26,12 @@ Vue.component(
require('./components/passport/PersonalAccessTokens.vue') require('./components/passport/PersonalAccessTokens.vue')
); );
Vue.component(
'importer',
require('./components/importer/importer.vue')
);
const app = new Vue({ // Commented out currently to avoid trying to load vue everywhere.
el: '#app' // const app = new Vue({
}); // el: '#app'
// });

View file

@ -13,5 +13,12 @@
@else @else
<p class="help-block">{{ trans('general.feature_disabled') }}</p> <p class="help-block">{{ trans('general.feature_disabled') }}</p>
@endif @endif
@stop @stop
@section('moar_scripts')
<script>
new Vue({
el: "#app",
});
</script>
@endsection

View file

@ -1,5 +1,5 @@
@extends('layouts/default') @extends('layouts/default')
<link rel="stylesheet" type="text/css" href="{{ asset('assets/css/lib/jquery.fileupload.css') }}">
{{-- Page title --}} {{-- Page title --}}
@section('title') @section('title')
{{ trans('general.import') }} {{ trans('general.import') }}
@ -8,209 +8,15 @@
{{-- Page content --}} {{-- Page content --}}
@section('content') @section('content')
<div id="app">
<importer>
@if (session()->has('import_errors'))
<div class="box">
<div class="box-body">
<div class="alert alert-warning">
<strong>Warning</strong> {{trans('admin/hardware/message.import.errorDetail')}}
</div>
<div class="errors-table">
<table class="table table-striped table-bordered" id="errors-table">
<thead>
<th>Asset</th>
<th>Errors</th>
</thead>
<tbody>
@foreach (session('import_errors') as $asset => $itemErrors)
<tr>
<td> {{ $asset }}</td>
<td>
@foreach ($itemErrors as $field => $values )
<b>{{ $field }}:</b>
@foreach( $values as $errorString)
<span>{{$errorString[0]}} </span>
@endforeach
<br />
@endforeach
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
</div>
</div>
@endif
{{-- Modal import dialog --}}
<div class="modal fade" id="importModal">
<form id="import-modal-form" class="form-horizontal" method="post" action="{{ route('assets/import/process-file') }}" autocomplete="off" role="form">
{{ csrf_field()}}
<input type="hidden" id="modal-filename" name="filename" value="">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title">Import File:</h4>
</div>
<div class="modal-body">
<div class="dynamic-form-row">
<div class="col-md-4 col-xs-12">
<label for="import-type">Import Type:</label>
</div>
<div class="col-md-8 col-xs-12">
{{ Form::select('import-type', array('asset' => 'Assets', 'accessory' => "Accessories", 'consumable' => "Consumables", 'component' => "Components") , 'asset', array('class'=>'select2 parent', 'style'=>'width:100%','id' =>'import-type')) }}
</div>
</div>
<div class="dynamic-form-row">
<div class="col-md-4 col-xs-12">
<label for="import-update">Update Existing Values?:</label>
</div>
<div class="col-md-8 col-xs-12">
{{ Form::checkbox('import-update') }}
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">{{ trans('button.cancel') }}</button>
<!-- <button type="button" class="btn btn-primary" id="modal-save">{{ trans('general.save') }}</button> -->
{{Form::submit(trans('general.save'), ['class' => 'btn btn-primary'])}}
</div>
</div>
</div>
</form>
</div>
<div class="row">
<div class="col-md-12">
<div class="box">
<div class="box-body">
<div class="col-md-3">
<!-- The fileinput-button span is used to style the file input field as button -->
<span class="btn btn-info fileinput-button">
<i class="fa fa-plus icon-white"></i>
<span>Select Import File...</span>
<!-- The file input field used as target for the file upload widget -->
<input id="fileupload" type="file" name="files[]" data-url="{{ route('api.hardware.importFile') }}" accept="text/csv">
</span>
</div>
<div class="col-md-9" id="progress-container" style="visibility: hidden; padding-bottom: 20px;">
<!-- The global progress bar -->
<div class="col-md-11">
<div id="progress" class="progress progress-striped active" style="margin-top: 8px;">
<div class="progress-bar progress-bar-warning" role="progressbar" aria-valuenow="45" aria-valuemin="0" aria-valuemax="100" style="width: 45%">
<span id="progress-bar-text">0% Complete</span>
</div>
</div>
</div>
<div class="col-md-1">
<div class="pull-right progress-checkmark" style="display: none;">
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<table class="table table-striped" id="upload-table">
<thead>
<th>File</th>
<th>Created</th>
<th>Size</th>
<th></th>
</thead>
<tbody>
@foreach ($files as $file)
<tr>
<td>{{ $file['filename'] }}</td>
<td>{{ date("M d, Y g:i A", $file['modified']) }} </td>
<td>{{ $file['filesize'] }}</td>
<td>
<a href="#" data-toggle="modal" data-target="#importModal" data-filename={{$file['filename']}} class="btn btn-sm btn-info"><i class="fa fa-spinner process"></i> Process</a>
<a class="btn btn-danger btn-sm" href="import/delete/{{ $file['filename'] }}"><i class="fa fa-trash icon-white"></i></a>
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div> </div>
@stop @stop
@section('moar_scripts') @section('moar_scripts')
<link rel="stylesheet" type="text/css" href="{{ asset('assets/css/lib/jquery.fileupload.css') }}">
<link rel="stylesheet" type="text/css" href="{{ asset('assets/css/lib/jquery.fileupload-ui.css') }}">
<script> <script>
$(function () { new Vue({
//binds to onchange event of your input field el: '#app'
var uploadedFileSize = 0;
$('#fileupload').bind('change', function() {
uploadedFileSize = this.files[0].size;
$('#progress-container').css('visibility', 'visible');
});
$('.process').bind('click', function() {
$('.process').addClass('fa-spin');
});
$('#fileupload').fileupload({
//maxChunkSize: 100000,
dataType: 'json',
formData: {_token: '{{ csrf_token() }}'},
progress: function (e, data) {
//var overallProgress = $('#fileupload').fileupload('progress');
//var activeUploads = $('#fileupload').fileupload('active');
var progress = parseInt((data.loaded / uploadedFileSize) * 100, 10);
$('.progress-bar').addClass('progress-bar-warning').css('width',progress + '%');
$('#progress-bar-text').html(progress + '%');
//console.dir(overallProgress);
},
done: function (e, data) {
console.dir(data);
// We use this instead of the fail option, since our API
// returns a 200 OK status which always shows as "success"
if (data && data.jqXHR.responseJSON && data.jqXHR.responseJSON.error) {
$('#progress-bar-text').html(data.jqXHR.responseJSON.error);
$('.progress-bar').removeClass('progress-bar-warning').addClass('progress-bar-danger').css('width','100%');
$('.progress-checkmark').fadeIn('fast').html('<i class="fa fa-times fa-3x icon-white" style="color: #d9534f"></i>');
//console.log(data.jqXHR.responseJSON.error);
} else {
$('.progress-bar').removeClass('progress-bar-warning').removeClass('progress-bar-danger').addClass('progress-bar-success').css('width','100%');
$('.progress-checkmark').fadeIn('fast');
$('#progress-container').delay(950).css('visibility', 'visible');
$('.progress-bar-text').html('Finished!');
$('.progress-checkmark').fadeIn('fast').html('<i class="fa fa-check fa-3x icon-white" style="color: green"></i>');
$.each(data.result.files, function (index, file) {
$('<tr><td>' + file.name + '</td><td>Just now</td><td>' + file.filesize + '</td><td><a class="btn btn-info btn-sm" href="#" data-toggle="modal" data-target="#importModal" data-filename='+ file.name + '><i class="fa fa-spinner process"></i> Process</a> <a class="btn btn-danger btn-sm" href="import/delete/' +file.name + '"><i class="fa fa-trash icon-white"></i></a></td></tr>').prependTo("#upload-table > tbody");
});
}
$('#progress').removeClass('active');
}
});
});
// Modal Import options handling
$('#importModal').on("show.bs.modal", function(event) {
var link = $(event.relatedTarget);
var filename = link.data('filename');
$(this).find('.modal-title').text("Import File: " + filename );
$("#modal-filename").val(filename);
}); });
</script> </script>
@stop @endsection

View file

@ -16,3 +16,11 @@
@endif @endif
@stop @stop
@section('moar_scripts')
<script>
new Vue({
el: "#app",
});
</script>
@endsection

View file

@ -18,6 +18,7 @@ use App\Models\Statuslabel;
Route::group(['prefix' => 'v1','namespace' => 'Api'], function () { Route::group(['prefix' => 'v1','namespace' => 'Api'], function () {
/*---Hardware API---*/
Route::resource('users', 'UsersController', Route::resource('users', 'UsersController',
['names' => ['names' =>
@ -33,7 +34,6 @@ Route::group(['prefix' => 'v1','namespace' => 'Api'], function () {
] ]
); );
Route::resource('licenses', 'LicensesController', Route::resource('licenses', 'LicensesController',
['names' => ['names' =>
[ [
@ -47,6 +47,20 @@ Route::group(['prefix' => 'v1','namespace' => 'Api'], function () {
'parameters' => ['license' => 'license_id'] 'parameters' => ['license' => 'license_id']
] ]
); );
Route::post('imports/process/{import_id}', [ 'as' => 'api.imports.importFile', 'uses'=> 'ImportController@process']);
Route::resource('imports', 'ImportController',
['names' =>
[
'index' => 'api.imports.index',
'show' => 'api.imports.show',
'update' => 'api.imports.update',
'store' => 'api.imports.store',
'destroy' => 'api.imports.destroy'
],
'except' => ['edit']
]
);
Route::resource('models', 'AssetModelsController', Route::resource('models', 'AssetModelsController',
@ -246,7 +260,6 @@ Route::group(['prefix' => 'v1','namespace' => 'Api'], function () {
/*---Hardware API---*/ /*---Hardware API---*/
Route::post('hardware/import', [ 'as' => 'api.assets.importFile', 'uses'=> 'AssetsController@postAPIImportUpload']);
Route::match(['DELETE'], 'hardware/{id}', ['uses' => 'AssetsController@destroy','as' => 'api.assets.destroy']); Route::match(['DELETE'], 'hardware/{id}', ['uses' => 'AssetsController@destroy','as' => 'api.assets.destroy']);

View file

@ -72,10 +72,7 @@ Route::group(
'uses' => 'AssetsController@postUpload' 'uses' => 'AssetsController@postUpload'
]); ]);
Route::get('{assetId}/deletefile/{fileId}', [
'as' => 'delete/assetfile',
'uses' => 'AssetsController@getDeleteFile'
]);
Route::get('{assetId}/showfile/{fileId}', [ Route::get('{assetId}/showfile/{fileId}', [
'as' => 'show/assetfile', 'as' => 'show/assetfile',