diff --git a/.all-contributorsrc b/.all-contributorsrc index 73963a57ef..ede1bb624e 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -965,6 +965,15 @@ "contributions": [ "code" ] + }, + { + "login": "plexorama", + "name": "plexorama", + "avatar_url": "https://avatars1.githubusercontent.com/u/605167?v=4", + "profile": "https://github.com/plexorama", + "contributions": [ + "code" + ] } ] } diff --git a/README.md b/README.md index 37254d0104..0a5613db6c 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -[![Build Status](https://travis-ci.org/snipe/snipe-it.svg?branch=master)](https://travis-ci.org/snipe/snipe-it) [![Crowdin](https://d322cqt584bo4o.cloudfront.net/snipe-it/localized.svg)](https://crowdin.com/project/snipe-it) [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/snipe/snipe-it?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Docker Pulls](https://img.shields.io/docker/pulls/snipe/snipe-it.svg)](https://hub.docker.com/r/snipe/snipe-it/) [![Twitter Follow](https://img.shields.io/twitter/follow/snipeyhead.svg?style=social)](https://twitter.com/snipeyhead) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/553ce52037fc43ea99149785afcfe641)](https://www.codacy.com/app/snipe/snipe-it?utm_source=github.com&utm_medium=referral&utm_content=snipe/snipe-it&utm_campaign=Badge_Grade) -[![All Contributors](https://img.shields.io/badge/all_contributors-104-orange.svg?style=flat-square)](#contributors) [![Open Source Helpers](https://www.codetriage.com/snipe/snipe-it/badges/users.svg)](https://www.codetriage.com/snipe/snipe-it) +[![Build Status](https://travis-ci.org/snipe/snipe-it.svg?branch=master)](https://travis-ci.org/snipe/snipe-it) [![Crowdin](https://d322cqt584bo4o.cloudfront.net/snipe-it/localized.svg)](https://crowdin.com/project/snipe-it) [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/snipe/snipe-it?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Docker Pulls](https://img.shields.io/docker/pulls/snipe/snipe-it.svg)](https://hub.docker.com/r/snipe/snipe-it/) [![Twitter Follow](https://img.shields.io/twitter/follow/snipeitapp.svg?style=social)](https://twitter.com/snipeitapp) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/553ce52037fc43ea99149785afcfe641)](https://www.codacy.com/app/snipe/snipe-it?utm_source=github.com&utm_medium=referral&utm_content=snipe/snipe-it&utm_campaign=Badge_Grade) +[![All Contributors](https://img.shields.io/badge/all_contributors-105-orange.svg?style=flat-square)](#contributors) [![Open Source Helpers](https://www.codetriage.com/snipe/snipe-it/badges/users.svg)](https://www.codetriage.com/snipe/snipe-it) ## Snipe-IT - Open Source Asset Management System @@ -83,7 +83,7 @@ Thanks goes to all of these wonderful people ([emoji key](https://github.com/ken | [Robin Temme](https://github.com/zwerch)[π»](https://github.com/snipe/snipe-it/commits?author=zwerch "Code") | [Iman](https://github.com/imanghafoori1)[π»](https://github.com/snipe/snipe-it/commits?author=imanghafoori1 "Code") | [Richard Hofman](https://github.com/richardhofman6)[π»](https://github.com/snipe/snipe-it/commits?author=richardhofman6 "Code") | [gizzmojr](https://github.com/gizzmojr)[π»](https://github.com/snipe/snipe-it/commits?author=gizzmojr "Code") | [Jenny Li](https://github.com/imjennyli)[π](https://github.com/snipe/snipe-it/commits?author=imjennyli "Documentation") | [Geoff Young](https://github.com/GeoffYoung)[π»](https://github.com/snipe/snipe-it/commits?author=GeoffYoung "Code") | [Elliot Blackburn](http://www.elliotblackburn.com)[π](https://github.com/snipe/snipe-it/commits?author=BlueHatbRit "Documentation") | | [TΓ΅nis Ormisson](http://andmemasin.eu)[π»](https://github.com/snipe/snipe-it/commits?author=TonisOrmisson "Code") | [Nicolai Essig](http://www.nicolai-essig.de)[π»](https://github.com/snipe/snipe-it/commits?author=thakilla "Code") | [Danielle](https://github.com/techincolor)[π](https://github.com/snipe/snipe-it/commits?author=techincolor "Documentation") | [Lawrence](https://github.com/TheVakman)[β οΈ](https://github.com/snipe/snipe-it/commits?author=TheVakman "Tests") [π](https://github.com/snipe/snipe-it/issues?q=author%3ATheVakman "Bug reports") | [uknzaeinozpas](https://github.com/uknzaeinozpas)[β οΈ](https://github.com/snipe/snipe-it/commits?author=uknzaeinozpas "Tests") [π»](https://github.com/snipe/snipe-it/commits?author=uknzaeinozpas "Code") | [Ryan](https://github.com/Gelob)[π](https://github.com/snipe/snipe-it/commits?author=Gelob "Documentation") | [vcordes79](https://github.com/vcordes79)[π»](https://github.com/snipe/snipe-it/commits?author=vcordes79 "Code") | | [fordster78](https://github.com/fordster78)[π»](https://github.com/snipe/snipe-it/commits?author=fordster78 "Code") | [CronKz](https://github.com/CronKz)[π»](https://github.com/snipe/snipe-it/commits?author=CronKz "Code") | [Tim Bishop](https://github.com/tdb)[π»](https://github.com/snipe/snipe-it/commits?author=tdb "Code") | [Sean McIlvenna](https://www.seanmcilvenna.com)[π»](https://github.com/snipe/snipe-it/commits?author=seanmcilvenna "Code") | [cepacs](https://github.com/cepacs)[π](https://github.com/snipe/snipe-it/issues?q=author%3Acepacs "Bug reports") [π](https://github.com/snipe/snipe-it/commits?author=cepacs "Documentation") | [lea-mink](https://github.com/lea-mink)[π»](https://github.com/snipe/snipe-it/commits?author=lea-mink "Code") | [Hannah Tinkler](https://github.com/hannahtinkler)[π»](https://github.com/snipe/snipe-it/commits?author=hannahtinkler "Code") | -| [Doeke Zanstra](https://github.com/doekman)[π»](https://github.com/snipe/snipe-it/commits?author=doekman "Code") | [Djamon Staal](https://www.sdhd.nl/)[π»](https://github.com/snipe/snipe-it/commits?author=SjamonDaal "Code") | [Earl Ramirez](https://github.com/EarlRamirez)[π»](https://github.com/snipe/snipe-it/commits?author=EarlRamirez "Code") | [Richard Ray Thomas](https://github.com/RichardRay)[π»](https://github.com/snipe/snipe-it/commits?author=RichardRay "Code") | [Ryan Kuba](https://www.taisun.io/)[π»](https://github.com/snipe/snipe-it/commits?author=thelamer "Code") | [Brian Monroe](https://github.com/ParadoxGuitarist)[π»](https://github.com/snipe/snipe-it/commits?author=ParadoxGuitarist "Code") | +| [Doeke Zanstra](https://github.com/doekman)[π»](https://github.com/snipe/snipe-it/commits?author=doekman "Code") | [Djamon Staal](https://www.sdhd.nl/)[π»](https://github.com/snipe/snipe-it/commits?author=SjamonDaal "Code") | [Earl Ramirez](https://github.com/EarlRamirez)[π»](https://github.com/snipe/snipe-it/commits?author=EarlRamirez "Code") | [Richard Ray Thomas](https://github.com/RichardRay)[π»](https://github.com/snipe/snipe-it/commits?author=RichardRay "Code") | [Ryan Kuba](https://www.taisun.io/)[π»](https://github.com/snipe/snipe-it/commits?author=thelamer "Code") | [Brian Monroe](https://github.com/ParadoxGuitarist)[π»](https://github.com/snipe/snipe-it/commits?author=ParadoxGuitarist "Code") | [plexorama](https://github.com/plexorama)[π»](https://github.com/snipe/snipe-it/commits?author=plexorama "Code") | This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome! diff --git a/app/Helpers/Helper.php b/app/Helpers/Helper.php index 87c8216320..0ba7d03c01 100644 --- a/app/Helpers/Helper.php +++ b/app/Helpers/Helper.php @@ -413,7 +413,7 @@ class Helper { $keys = array_keys(CustomField::$PredefinedFormats); $stuff = array_combine($keys, $keys); - return $stuff+["" => trans('admin/custom_fields/general.custom_format')]; + return $stuff; } /** diff --git a/app/Http/Controllers/Api/UsersController.php b/app/Http/Controllers/Api/UsersController.php index 73aeb2a993..c683dbf917 100644 --- a/app/Http/Controllers/Api/UsersController.php +++ b/app/Http/Controllers/Api/UsersController.php @@ -320,4 +320,17 @@ class UsersController extends Controller return response()->json(['message' => 'No ID provided'], 500); } + + /** + * Get info on the current user. + * + * @author [Juan Font] [] + * @since [v4.4.2] + * @param \Illuminate\Http\Request $request + * @return \Illuminate\Http\Response + */ + public function getCurrentUserInfo(Request $request) + { + return response()->json($request->user()); + } } diff --git a/app/Http/Controllers/ReportsController.php b/app/Http/Controllers/ReportsController.php index 7248cc6bea..d6c01b5c89 100644 --- a/app/Http/Controllers/ReportsController.php +++ b/app/Http/Controllers/ReportsController.php @@ -400,6 +400,10 @@ class ReportsController extends Controller $header[] = 'Employee No.'; } + if ($request->has('manager')) { + $header[] = trans('admin/users/table.manager'); + } + if ($request->has('department')) { $header[] = trans('general.department'); } @@ -613,6 +617,14 @@ class ReportsController extends Controller } } + if ($request->has('manager')) { + if ($asset->checkedOutToUser()) { + $row[] = (($asset->assignedto) && ($asset->assignedto->manager)) ? $asset->assignedto->manager->present()->fullName : ''; + } else { + $row[] = ''; // Empty string if unassigned + } + } + if ($request->has('department')) { if ($asset->checkedOutToUser()) { diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index fb63238159..3bee950976 100644 --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -22,8 +22,8 @@ class Kernel extends HttpKernel \App\Http\Middleware\ReferrerPolicyHeader::class, \App\Http\Middleware\ContentSecurityPolicyHeader::class, \App\Http\Middleware\NosniffGuard::class, - \App\Http\Middleware\CheckForSetup::class, \Fideloper\Proxy\TrustProxies::class, + \App\Http\Middleware\CheckForSetup::class, \App\Http\Middleware\CheckForDebug::class, // \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class, ]; diff --git a/app/Http/Transformers/StatuslabelsTransformer.php b/app/Http/Transformers/StatuslabelsTransformer.php index f1a5460531..f76557a0bf 100644 --- a/app/Http/Transformers/StatuslabelsTransformer.php +++ b/app/Http/Transformers/StatuslabelsTransformer.php @@ -9,13 +9,13 @@ use App\Helpers\Helper; class StatuslabelsTransformer { - public function transformStatuslabels (Collection $statuslabels) + public function transformStatuslabels (Collection $statuslabels, $total) { $array = array(); foreach ($statuslabels as $statuslabel) { $array[] = self::transformStatuslabel($statuslabel); } - return (new DatatablesTransformer)->transformDatatables($array); + return (new DatatablesTransformer)->transformDatatables($array, $total); } public function transformStatuslabel (Statuslabel $statuslabel) diff --git a/app/Importer/AssetImporter.php b/app/Importer/AssetImporter.php index a8fd712536..e0977eac6c 100644 --- a/app/Importer/AssetImporter.php +++ b/app/Importer/AssetImporter.php @@ -81,8 +81,8 @@ class AssetImporter extends ItemImporter // We need to save the user if it exists so that we can checkout to user later. // Sanitizing the item will remove it. - if(array_key_exists('user', $this->item)) { - $user = $this->item['user']; + if(array_key_exists('checkout_target', $this->item)) { + $target = $this->item['checkout_target']; } $item = $this->sanitizeItemForStoring($asset, $editingAsset); // The location id fetched by the csv reader is actually the rtd_location_id. @@ -112,9 +112,9 @@ class AssetImporter extends ItemImporter $asset->logCreate('Imported using csv importer'); $this->log('Asset ' . $this->item["name"] . ' with serial number ' . $this->item['serial'] . ' was created'); - // If we have a user to checkout to, lets do so. - if(isset($user)) { - $asset->fresh()->checkOut($user); + // If we have a target to checkout to, lets do so. + if(isset($target)) { + $asset->fresh()->checkOut($target); } return; } diff --git a/app/Importer/ConsumableImporter.php b/app/Importer/ConsumableImporter.php index f81b575805..a25a8b56f7 100644 --- a/app/Importer/ConsumableImporter.php +++ b/app/Importer/ConsumableImporter.php @@ -14,17 +14,18 @@ class ConsumableImporter extends ItemImporter protected function handle($row) { - parent::handle($row); // TODO: Change the autogenerated stub - $this->createConsumableIfNotExists(); + parent::handle($row); + $this->createConsumableIfNotExists($row); } /** * Create a consumable if a duplicate does not exist * * @author Daniel Melzter + * @param array $row CSV Row Being parsed. * @since 3.0 */ - public function createConsumableIfNotExists() + public function createConsumableIfNotExists($row) { $consumable = Consumable::where('name', $this->item['name'])->first(); if ($consumable) { @@ -39,6 +40,8 @@ class ConsumableImporter extends ItemImporter } $this->log("No matching consumable, creating one"); $consumable = new Consumable(); + $this->item['model_number'] = $this->findCsvMatch($row, "model_number");; + $this->item['item_no'] = $this->findCsvMatch($row, "item_number"); $consumable->fill($this->sanitizeItemForStoring($consumable)); //FIXME: this disables model validation. Need to find a way to avoid double-logs without breaking everything. $consumable->unsetEventDispatcher(); diff --git a/app/Importer/Importer.php b/app/Importer/Importer.php index db7dc938f0..1ec04157ba 100644 --- a/app/Importer/Importer.php +++ b/app/Importer/Importer.php @@ -30,8 +30,11 @@ abstract class Importer private $defaultFieldMap = [ 'asset_tag' => 'asset tag', 'category' => 'category', + 'checkout_class' => 'checkout type', // Supports Location or User for assets. Using checkout_class instead of checkout_type because type exists on asset already. + 'checkout_location' => 'checkout location', 'company' => 'company', 'item_name' => 'item name', + 'item_number' => "item number", 'image' => 'image', 'expiration_date' => 'expiration date', 'location' => 'location', @@ -89,11 +92,12 @@ abstract class Importer public function __construct($file) { $this->fieldMap = $this->defaultFieldMap; - // By default the importer passes a url to the file. - // However, for testing we also support passing a string directly if (! ini_get("auto_detect_line_endings")) { ini_set("auto_detect_line_endings", '1'); } + + // By default the importer passes a url to the file. + // However, for testing we also support passing a string directly if (is_file($file)) { $this->csv = Reader::createFromPath($file); } else { @@ -179,9 +183,8 @@ abstract class Importer */ public function lookupCustomKey($key) { - // dd($this->fieldMap); if (array_key_exists($key, $this->fieldMap)) { - $this->log("Found a match in our custom map: {$key} is " . $this->fieldMap[$key]); + // $this->log("Found a match in our custom map: {$key} is " . $this->fieldMap[$key]); return $this->fieldMap[$key]; } // Otherwise no custom key, return original. @@ -189,6 +192,8 @@ abstract class Importer } /** + * Used to lowercase header values to ensure we're comparing values properly. + * * @param $results * @return array */ @@ -249,11 +254,11 @@ abstract class Importer $last_name = ''; if(empty($user_name) && empty($user_email) && empty($user_username)) { $this->log('No user data provided - skipping user creation, just adding asset'); - //$user_username = ''; return false; } - // A username was given. + if( !empty($user_username)) { + // A username was given. $user = User::where('username', $user_username)->first(); if($user) { return $user; diff --git a/app/Importer/ItemImporter.php b/app/Importer/ItemImporter.php index 72a618cbd1..5877ad81dd 100644 --- a/app/Importer/ItemImporter.php +++ b/app/Importer/ItemImporter.php @@ -69,11 +69,36 @@ class ItemImporter extends Importer $this->item['serial'] = $this->findCsvMatch($row, "serial"); // NO need to call this method if we're running the user import. // TODO: Merge these methods. + $this->item['checkout_class'] = $this->findCsvMatch($row, "checkout_class"); if(get_class($this) !== UserImporter::class) { - $this->item["user"] = $this->createOrFetchUser($row); + // $this->item["user"] = $this->createOrFetchUser($row); + $this->item["checkout_target"] = $this->determineCheckout($row); + } } + /** + * Parse row to determine what (if anything) we should checkout to. + * @param array $row CSV Row being parsed + * @return SnipeModel Model to be checked out to + */ + protected function determineCheckout($row) + { + // We only supporty checkout-to-location for asset, so short circuit otherw. + if(get_class($this) != AssetImporter::class) { + return $this->createOrFetchUser($row); + } + + if ($this->item['checkout_class'] === 'location') { + // dd($this->findCsvMatch($row, 'checkout_location')); + return Location::findOrFail($this->createOrFetchLocation($this->findCsvMatch($row, 'checkout_location'))); + // dd('here'); + } + + return $this->createOrFetchUser($row); + + } + /** * Cleanup the $item array before storing. * We need to remove any values that are not part of the fillable fields. diff --git a/app/Importer/LicenseImporter.php b/app/Importer/LicenseImporter.php index dd554bf61d..7be62b7b44 100644 --- a/app/Importer/LicenseImporter.php +++ b/app/Importer/LicenseImporter.php @@ -71,11 +71,11 @@ class LicenseImporter extends ItemImporter // Lets try to checkout seats if the fields exist and we have seats. if ($license->seats > 0) { - $user = $this->item['user']; + $checkout_target = $this->item['checkout_target']; $asset = Asset::where('asset_tag', $asset_tag)->first(); $targetLicense = $license->licenseSeats()->first(); - if ($user) { - $targetLicense->assigned_to = $user->id; + if ($checkout_target) { + $targetLicense->assigned_to = $checkout_target->id; if ($asset) { $targetLicense->asset_id = $asset->id; } diff --git a/app/Models/CustomField.php b/app/Models/CustomField.php index ad9a2ab36a..4ea44fef90 100644 --- a/app/Models/CustomField.php +++ b/app/Models/CustomField.php @@ -16,6 +16,7 @@ class CustomField extends Model public $guarded=["id"]; public static $PredefinedFormats=[ "ANY" => "", + "CUSTOM REGEX" => "", "ALPHA" => "alpha", "ALPHA-DASH" => "alpha_dash", "NUMERIC" => "numeric", diff --git a/public/css/build/all.css b/public/css/build/all.css index f0fefa7a8e..418fe416f0 100644 Binary files a/public/css/build/all.css and b/public/css/build/all.css differ diff --git a/public/css/dist/all.css b/public/css/dist/all.css index f0fefa7a8e..418fe416f0 100644 Binary files a/public/css/dist/all.css and b/public/css/dist/all.css differ diff --git a/public/css/overrides.css b/public/css/overrides.css index bb0bbdab96..0f11860559 100644 Binary files a/public/css/overrides.css and b/public/css/overrides.css differ diff --git a/public/js/build/all.js b/public/js/build/all.js index 3767ea093f..443defcd9b 100644 Binary files a/public/js/build/all.js and b/public/js/build/all.js differ diff --git a/public/js/build/vue.js b/public/js/build/vue.js index 79892227b7..8cbfb2baed 100644 Binary files a/public/js/build/vue.js and b/public/js/build/vue.js differ diff --git a/public/js/build/vue.js.map b/public/js/build/vue.js.map index c5105e8637..68e3c12289 100644 Binary files a/public/js/build/vue.js.map and b/public/js/build/vue.js.map differ diff --git a/public/js/dist/all.js b/public/js/dist/all.js index 3767ea093f..443defcd9b 100644 Binary files a/public/js/dist/all.js and b/public/js/dist/all.js differ diff --git a/public/mix-manifest.json b/public/mix-manifest.json index 9fe5cd6a18..ed83c4f9b0 100644 --- a/public/mix-manifest.json +++ b/public/mix-manifest.json @@ -1,14 +1,14 @@ { - "/js/build/vue.js": "/js/build/vue.js?id=992bcb968a7f2da998b5", + "/js/build/vue.js": "/js/build/vue.js?id=5eab4676dde73dbab3ca", "/css/AdminLTE.css": "/css/AdminLTE.css?id=5e72463a66acbcc740d5", "/css/app.css": "/css/app.css?id=407edb63cc6b6dc62405", - "/css/overrides.css": "/css/overrides.css?id=d85394a0b4f58e81bb78", - "/js/build/vue.js.map": "/js/build/vue.js.map?id=e0eb0edc0b761965973f", + "/css/overrides.css": "/css/overrides.css?id=2d81c3704393bac77011", + "/js/build/vue.js.map": "/js/build/vue.js.map?id=525260f84ea83d4b55cd", "/css/AdminLTE.css.map": "/css/AdminLTE.css.map?id=99f5a5a03c4155cf69f6", "/css/app.css.map": "/css/app.css.map?id=bdbe05e6ecd70ccfac72", "/css/overrides.css.map": "/css/overrides.css.map?id=898c91d4a425b01b589b", - "/css/dist/all.css": "/css/dist/all.css?id=0e3642f1b6a8a436d558", - "/js/dist/all.js": "/js/dist/all.js?id=39b95992f478d68c44a8", - "/css/build/all.css": "/css/build/all.css?id=0e3642f1b6a8a436d558", - "/js/build/all.js": "/js/build/all.js?id=39b95992f478d68c44a8" + "/css/dist/all.css": "/css/dist/all.css?id=98db4e9b7650453c8b00", + "/js/dist/all.js": "/js/dist/all.js?id=85c7dab4c75f53c45b91", + "/css/build/all.css": "/css/build/all.css?id=98db4e9b7650453c8b00", + "/js/build/all.js": "/js/build/all.js?id=85c7dab4c75f53c45b91" } \ No newline at end of file diff --git a/resources/assets/js/components/forms/asset-models/fieldset-default-values.vue b/resources/assets/js/components/forms/asset-models/fieldset-default-values.vue index 71d7ee01ed..ea45e1df74 100644 --- a/resources/assets/js/components/forms/asset-models/fieldset-default-values.vue +++ b/resources/assets/js/components/forms/asset-models/fieldset-default-values.vue @@ -44,8 +44,10 @@ + + - + {{ field_value }} diff --git a/resources/assets/js/components/importer/importer-file.vue b/resources/assets/js/components/importer/importer-file.vue index 3014a44c06..7c8dbae002 100644 --- a/resources/assets/js/components/importer/importer-file.vue +++ b/resources/assets/js/components/importer/importer-file.vue @@ -117,12 +117,18 @@ tr { assets: [ {id: 'asset_tag', text: 'Asset Tag' }, {id: 'asset_model', text: 'Model Name' }, + {id: 'checkout_class', text: 'Checkout Type' }, + {id: 'checkout_location', text: 'Checkout Location' }, {id: 'image', text: 'Image Filename' }, {id: 'model_number', text: 'Model Number' }, {id: 'full_name', text: 'Full Name' }, {id: 'status', text: 'Status' }, {id: 'warranty_months', text: 'Warranty Months' }, ], + consumables: [ + {id: 'item_no', text: "Item Number"}, + {id: 'model_number', text: "Model Number"}, + ], licenses: [ {id: 'expiration_date', text: 'Expiration Date' }, {id: 'license_email', text: 'Licensed To Email' }, @@ -165,6 +171,11 @@ tr { .concat(this.columnOptions.assets) .concat(this.columnOptions.customFields) .sort(sorter); + + case 'consumable': + return this.columnOptions.general + .concat(this.columnOptions.consumables) + .sort(sorter); case 'license': return this.columnOptions.general.concat(this.columnOptions.licenses).sort(sorter); case 'user': @@ -184,7 +195,6 @@ tr { }, watch: { columns() { - console.log("CHANGED"); this.populateSelect2ActiveItems(); } }, @@ -234,7 +244,6 @@ tr { for(var j=0; j < this.columns.length; j++) { let column = this.columns[j]; let lower = this.file.header_row.map((value) => value.toLowerCase()); - console.dir(lower); let index = lower.indexOf(column.text.toLowerCase()) if(index != -1) { this.$set(this.columnMappings, this.file.header_row[index], column.id) @@ -248,7 +257,6 @@ tr { } }, updateModel(header, value) { - console.log(header, value); this.columnMappings[header] = value; } }, diff --git a/resources/assets/less/overrides.less b/resources/assets/less/overrides.less index 0e032dfb44..7296439da8 100644 --- a/resources/assets/less/overrides.less +++ b/resources/assets/less/overrides.less @@ -341,3 +341,9 @@ img.navbar-brand-img, .navbar-brand>img { font-size: 20px; color: #889195; } + +#login-logo { + padding-top: 20px; + padding-bottom: 10px; + max-width: 200px +} diff --git a/resources/macros/macros.php b/resources/macros/macros.php index c391700b9b..34aa072af0 100644 --- a/resources/macros/macros.php +++ b/resources/macros/macros.php @@ -504,6 +504,7 @@ Form::macro('customfield_elements', function ($name = "customfield_elements", $s $formats = array( 'text' => 'Text Box', 'listbox' => 'List Box', + 'textarea' => 'Textarea (multi-line) ', // 'checkbox' => 'Checkbox', // 'radio' => 'Radio Buttons', ); diff --git a/resources/views/custom_fields/fields/edit.blade.php b/resources/views/custom_fields/fields/edit.blade.php index ea33cd2f07..1973a6991c 100644 --- a/resources/views/custom_fields/fields/edit.blade.php +++ b/resources/views/custom_fields/fields/edit.blade.php @@ -167,7 +167,7 @@ // Only display the custom format field if it's a custom format validation type $(".format").change(function(){ $(this).find("option:selected").each(function(){ - if (($(this).attr("value")=="") && $('.format').prop("selectedIndex") != 0) { + if ($('.format').prop("selectedIndex") == 1) { $("#custom_regex").show(); } else{ $("#custom_regex").hide(); @@ -178,7 +178,7 @@ // Only display the field element if the type is not text $(".field_element").change(function(){ $(this).find("option:selected").each(function(){ - if($(this).attr("value")!="text"){ + if (($(this).attr("value")!="text") && ($(this).attr("value")!="textarea")){ $("#field_values_text").show(); } else{ $("#field_values_text").hide(); diff --git a/resources/views/hardware/view.blade.php b/resources/views/hardware/view.blade.php index 96be1daa8d..db134f7160 100755 --- a/resources/views/hardware/view.blade.php +++ b/resources/views/hardware/view.blade.php @@ -281,7 +281,7 @@ @if (($field->format=='URL') && ($asset->{$field->db_column_name()}!='')) {{ $asset->{$field->db_column_name()} }} @else - {{ $asset->{$field->db_column_name()} }} + {!! nl2br(e($asset->{$field->db_column_name()})) !!} @endif @endif diff --git a/resources/views/layouts/basic.blade.php b/resources/views/layouts/basic.blade.php index 2fc35c6d0e..3ea432d3ef 100644 --- a/resources/views/layouts/basic.blade.php +++ b/resources/views/layouts/basic.blade.php @@ -46,7 +46,7 @@ @if (($snipeSettings) && ($snipeSettings->logo!='')) - + @endif diff --git a/resources/views/layouts/default.blade.php b/resources/views/layouts/default.blade.php index 884a69b139..93ff490258 100644 --- a/resources/views/layouts/default.blade.php +++ b/resources/views/layouts/default.blade.php @@ -224,7 +224,7 @@ @can('create', \App\Models\Component::class) - + {{ trans('general.component') }} @@ -310,7 +310,7 @@ - + Requested Assets diff --git a/resources/views/models/custom_fields_form.blade.php b/resources/views/models/custom_fields_form.blade.php index 3ec43cad7e..b03fbd6081 100644 --- a/resources/views/models/custom_fields_form.blade.php +++ b/resources/views/models/custom_fields_form.blade.php @@ -4,12 +4,17 @@ {{ $field->name }} + @if ($field->element!='text') @if ($field->element=='listbox') {{ Form::select($field->db_column_name(), $field->formatFieldValuesAsArray(), Input::old($field->db_column_name(),(isset($item) ? $item->{$field->db_column_name()} : $field->defaultValue($model->id))), ['class'=>'format select2 form-control']) }} + @elseif ($field->element=='textarea') + {{ Input::old($field->db_column_name(),(isset($item) ? $item->{$field->db_column_name()} : $field->defaultValue($model->id))) }} + + @elseif ($field->element=='checkbox') @foreach ($field->formatFieldValuesAsArray() as $key => $value) diff --git a/resources/views/models/edit.blade.php b/resources/views/models/edit.blade.php index 4861b5d7a1..ae271c5835 100755 --- a/resources/views/models/edit.blade.php +++ b/resources/views/models/edit.blade.php @@ -49,8 +49,7 @@ + previous-input="{{ json_encode(Input::old('default_values')) }}"> diff --git a/resources/views/reports/custom.blade.php b/resources/views/reports/custom.blade.php index 36c6d3d262..a53cbce60c 100644 --- a/resources/views/reports/custom.blade.php +++ b/resources/views/reports/custom.blade.php @@ -221,6 +221,13 @@ + + + {{ Form::checkbox('manager', '1', '1', ['class' => 'minimal']) }} + {{ trans('admin/users/table.manager') }} + + + {{ Form::checkbox('department', '1', '1', ['class' => 'minimal']) }} @@ -231,6 +238,7 @@ + @if ($customfields->count() > 0) Custom Fields: diff --git a/routes/api.php b/routes/api.php index 97c032caa6..c66c388820 100644 --- a/routes/api.php +++ b/routes/api.php @@ -674,10 +674,10 @@ Route::group(['prefix' => 'v1','namespace' => 'Api'], function () { + /*--- Users API ---*/ - - + Route::group([ 'prefix' => 'users' ], function () { Route::post('two_factor_reset', @@ -687,6 +687,13 @@ Route::group(['prefix' => 'v1','namespace' => 'Api'], function () { ] ); + Route::get('me', + [ + 'as' => 'api.users.me', + 'uses' => 'UsersController@getCurrentUserInfo' + ] + ); + Route::get('list/{status?}', [ 'as' => 'api.users.list', diff --git a/tests/unit/ImporterTest.php b/tests/unit/ImporterTest.php index 99469a8ecd..f996503962 100644 --- a/tests/unit/ImporterTest.php +++ b/tests/unit/ImporterTest.php @@ -8,6 +8,7 @@ use App\Models\Asset; use App\Models\AssetModel; use App\Models\Category; use App\Models\CustomField; +use App\Models\Location; use App\Models\User; use Illuminate\Foundation\Testing\DatabaseMigrations; use Illuminate\Foundation\Testing\DatabaseTransactions; @@ -72,12 +73,61 @@ EOT; 'asset_tag' => '970882174-8', 'notes' => "Curabitur in libero ut massa volutpat convallis. Morbi odio odio, elementum eu, interdum eu, tincidunt in, leo. Maecenas pulvinar lobortis est.", 'purchase_date' => '2016-04-05 00:00:01', - 'purchase_cost' => 133289.59, - 'warranty_months' => 14, + 'purchase_cost' => 133289.59 +, 'warranty_months' => 14, '_snipeit_weight_2' => 35 ]); } + public function testImportCheckoutToLocation() + { + $this->signIn(); + + // Testing in order: + // * Asset to user, no checkout type defined (default to user). + // * Asset to user, explicit user checkout type (Checkout to user) + // * Asset to location, location does not exist to begin with + // * Asset to preexisting location. + $csv = <<<'EOT' +Full Name,Email,Username,Checkout Location,Checkout Type,item Name,Category,Model name,Manufacturer,Model Number,Serial,Asset Tag,Location,Notes,Purchase Date,Purchase Cost,Company,Status,Warranty,Supplier,Weight +Bonnie Nelson,bnelson0@cdbaby.com,bnelson0,,,eget nunc donec quis,quam,massa id,Linkbridge,6377018600094472,27aa8378-b0f4-4289-84a4-405da95c6147,970882174-8,Daping,"Curabitur in libero ut massa volutpat convallis. Morbi odio odio, elementum eu, interdum eu, tincidunt in, leo. Maecenas pulvinar lobortis est.",2016-04-05,133289.59,Alpha,Undeployable,14,Blogspan,35 +Mildred Gibson,mgibson2@wiley.com,mgibson2,,user,morbi quis tortor id,nunc nisl duis,convallis tortor risus,Lajo,374622546776765,2837ab20-8f0d-4935-8a52-226392f2b1b0,710141467-2,Shekou,In congue. Etiam justo. Etiam pretium iaculis justo.,2015-08-09,233.57,Konklab,Lost,,, +,,,Planet Earth,location,dictumst maecenas ut,sem praesent,accumsan felis,Layo,30052522651756,4751495c-cee0-4961-b788-94a545b5643e,998233705-X,Dante Delgado,,2016-04-16,261.79,,Archived,15,Ntag, +,,,Daping,location,viverra diam vitae,semper sapien,dapibus dolor vel,Flashset,3559785746335392,e287bb64-ff4f-434c-88ab-210ad433c77b,927820758-6,Achiaman,,2016-03-05,675.3,,Archived,22,Meevee, +EOT; + + $this->import(new AssetImporter($csv)); + $user = User::where('username', 'bnelson0')->firstOrFail(); + + $this->tester->seeRecord('assets', [ + 'asset_tag' => '970882174-8', + 'assigned_type' => User::class, + 'assigned_to' => $user->id + ]); + + $user = User::where('username', 'mgibson2')->firstOrFail(); + $this->tester->seeRecord('assets', [ + 'asset_tag' => '710141467-2', + 'assigned_type' => User::class, + 'assigned_to' => $user->id + ]); + + $location = Location::where('name', 'Planet Earth')->firstOrFail(); + $this->tester->seeRecord('assets', [ + 'asset_tag' => '998233705-X', + 'assigned_type' => Location::class, + 'assigned_to' => $location->id + ]); + + $location = Location::where('name', 'Daping')->firstOrFail(); + $this->tester->seeRecord('assets', [ + 'asset_tag' => '927820758-6', + 'assigned_type' => Location::class, + 'assigned_to' => $location->id + ]); + + } + public function testUpdateAssetIncludingCustomFields() { $this->signIn(); @@ -385,18 +435,19 @@ EOT; public function testDefaultConsumableImport() { $csv = <<<'EOT' -Item Name,Purchase Date,Purchase Cost,Location,Company,Order Number,Category,Requestable,Quantity -eget,01/03/2011,$85.91,mauris blandit mattis.,Lycos,T295T06V,Triamterene/Hydrochlorothiazide,No,322 +Item Name,Purchase Date,Purchase Cost,Location,Company,Order Number,Category,Requestable,Quantity,Item Number,Model Number +eget,01/03/2011,$85.91,mauris blandit mattis.,Lycos,T295T06V,Triamterene/Hydrochlorothiazide,No,322,3305,30123 EOT; $this->import(new ConsumableImporter($csv)); - $this->tester->seeRecord('consumables', [ 'name' => 'eget', 'purchase_date' => '2011-01-03 00:00:01', 'purchase_cost' => 85.91, 'order_number' => 'T295T06V', 'requestable' => 0, - 'qty' => 322 + 'qty' => 322, + 'item_no' => 3305, + 'model_number' => 30123 ]); $this->tester->seeRecord('locations', [