From 7321c5937fcb41206e712fc21723d7306bf3ffc4 Mon Sep 17 00:00:00 2001 From: snipe Date: Thu, 16 Nov 2017 16:49:16 -0800 Subject: [PATCH 1/6] Fixed #4440 - allow username search in asset dropdown --- app/Http/Controllers/Api/AssetsController.php | 21 ++++-- app/Models/Asset.php | 72 ++++++++++++++++--- 2 files changed, 78 insertions(+), 15 deletions(-) diff --git a/app/Http/Controllers/Api/AssetsController.php b/app/Http/Controllers/Api/AssetsController.php index 2f44ac7965..2980057ea6 100644 --- a/app/Http/Controllers/Api/AssetsController.php +++ b/app/Http/Controllers/Api/AssetsController.php @@ -281,27 +281,34 @@ class AssetsController extends Controller 'assets.name', 'assets.asset_tag', 'assets.model_id', + 'assets.assigned_to', + 'assets.assigned_type', 'assets.status_id' - ])->with('model', 'assetstatus')->NotArchived()); + ])->with('model', 'assetstatus', 'assignedTo')->NotArchived()); if ($request->has('search')) { - $assets = $assets->where('assets.name', 'LIKE', '%'.$request->get('search').'%') - ->orWhere('assets.asset_tag', 'LIKE', '%'.$request->get('search').'%') - ->join('models AS assets_models',function ($join) use ($request) { - $join->on('assets_models.id', "=", "assets.model_id"); - })->orWhere('assets_models.name','LIKE','%'.$request->get('search').'%'); + $assets = $assets->AssignedSearch($request->input('search')); } + $assets = $assets->paginate(50); // Loop through and set some custom properties for the transformer to use. // 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 ($assets as $asset) { + + $asset->use_text = $asset->present()->fullName; + + if ($asset->checkedOutToUser()) { + $asset->use_text .= ' β†’ '.$asset->assigned->getFullNameAttribute(); + } + + if ($asset->assetstatus->getStatuslabelType()=='pending') { - $asset->use_text = $asset->present()->fullName.' ('.$asset->assetstatus->getStatuslabelType().')'; + $asset->use_text .= '('.$asset->assetstatus->getStatuslabelType().')'; } $asset->use_image = ($asset->getImageUrl()) ? $asset->getImageUrl() : null; diff --git a/app/Models/Asset.php b/app/Models/Asset.php index a8d0035b7a..e71ae82b6a 100644 --- a/app/Models/Asset.php +++ b/app/Models/Asset.php @@ -765,11 +765,11 @@ class Asset extends Depreciable { $search = explode(' OR ', $search); - return $query->leftJoin('users',function ($leftJoin) { - $leftJoin->on("users.id", "=", "assets.assigned_to") + return $query->leftJoin('users as assets_users',function ($leftJoin) { + $leftJoin->on("assets_users.id", "=", "assets.assigned_to") ->where("assets.assigned_type", "=", User::class); - })->leftJoin('locations',function ($leftJoin) { - $leftJoin->on("locations.id","=","assets.assigned_to") + })->leftJoin('locations as assets_locations',function ($leftJoin) { + $leftJoin->on("assets_locations.id","=","assets.assigned_to") ->where("assets.assigned_type","=",Location::class); })->leftJoin('assets as assigned_assets',function ($leftJoin) { $leftJoin->on('assigned_assets.id', '=', 'assets.assigned_to') @@ -808,10 +808,10 @@ class Asset extends Depreciable $query->where('locations.name', 'LIKE', '%'.$search.'%'); }); })->orWhere(function ($query) use ($search) { - $query->where('users.first_name', 'LIKE', '%'.$search.'%') - ->orWhere('users.last_name', 'LIKE', '%'.$search.'%') - ->orWhere('users.username', 'LIKE', '%'.$search.'%') - ->orWhere('locations.name', 'LIKE', '%'.$search.'%') + $query->where('assets_users.first_name', 'LIKE', '%'.$search.'%') + ->orWhere('assets_users.last_name', 'LIKE', '%'.$search.'%') + ->orWhere('assets_users.username', 'LIKE', '%'.$search.'%') + ->orWhere('assets_locations.name', 'LIKE', '%'.$search.'%') ->orWhere('assigned_assets.name', 'LIKE', '%'.$search.'%'); })->orWhere('assets.name', 'LIKE', '%'.$search.'%') ->orWhere('assets.asset_tag', 'LIKE', '%'.$search.'%') @@ -826,6 +826,62 @@ class Asset extends Depreciable } + /** + * Query builder scope to search on text for complex Bootstrap Tables API. + * + * @param \Illuminate\Database\Query\Builder $query Query builder instance + * @param text $search Search term + * + * @return \Illuminate\Database\Query\Builder Modified query builder + */ + public function scopeAssignedSearch($query, $search) + { + $search = explode(' OR ', $search); + + return $query->leftJoin('users as assets_users',function ($leftJoin) { + $leftJoin->on("assets_users.id", "=", "assets.assigned_to") + ->where("assets.assigned_type", "=", User::class); + })->leftJoin('locations as assets_locations',function ($leftJoin) { + $leftJoin->on("assets_locations.id","=","assets.assigned_to") + ->where("assets.assigned_type","=",Location::class); + })->leftJoin('assets as assigned_assets',function ($leftJoin) { + $leftJoin->on('assigned_assets.id', '=', 'assets.assigned_to') + ->where('assets.assigned_type', '=', Asset::class); + })->where(function ($query) use ($search) { + foreach ($search as $search) { + $query->whereHas('model', function ($query) use ($search) { + $query->whereHas('category', function ($query) use ($search) { + $query->where(function ($query) use ($search) { + $query->where('categories.name', 'LIKE', '%'.$search.'%') + ->orWhere('models.name', 'LIKE', '%'.$search.'%') + ->orWhere('models.model_number', 'LIKE', '%'.$search.'%'); + }); + }); + })->orWhereHas('model', function ($query) use ($search) { + $query->whereHas('manufacturer', function ($query) use ($search) { + $query->where(function ($query) use ($search) { + $query->where('manufacturers.name', 'LIKE', '%'.$search.'%'); + }); + }); + })->orWhere(function ($query) use ($search) { + $query->where('assets_users.first_name', 'LIKE', '%'.$search.'%') + ->orWhere('assets_users.last_name', 'LIKE', '%'.$search.'%') + ->orWhere('assets_users.username', 'LIKE', '%'.$search.'%') + ->orWhere('assets_locations.name', 'LIKE', '%'.$search.'%') + ->orWhere('assigned_assets.name', 'LIKE', '%'.$search.'%'); + })->orWhere('assets.name', 'LIKE', '%'.$search.'%') + ->orWhere('assets.asset_tag', 'LIKE', '%'.$search.'%') + ->orWhere('assets.serial', 'LIKE', '%'.$search.'%') + ->orWhere('assets.order_number', 'LIKE', '%'.$search.'%') + ->orWhere('assets.notes', 'LIKE', '%'.$search.'%'); + } + foreach (CustomField::all() as $field) { + $query->orWhere('assets.'.$field->db_column_name(), 'LIKE', "%$search%"); + } + })->withTrashed()->whereNull("assets.deleted_at"); //workaround for laravel bug + } + + /** * Query builder scope to search on text filters for complex Bootstrap Tables API From 897bd2c56e75b870823e47e457122e48c4c0f593 Mon Sep 17 00:00:00 2001 From: snipe Date: Thu, 16 Nov 2017 16:49:48 -0800 Subject: [PATCH 2/6] Fixed location sorting location instead of rtd --- app/Models/Asset.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/Models/Asset.php b/app/Models/Asset.php index e71ae82b6a..148b97c010 100644 --- a/app/Models/Asset.php +++ b/app/Models/Asset.php @@ -1147,7 +1147,7 @@ class Asset extends Depreciable */ public function scopeOrderLocation($query, $order) { - return $query->leftJoin('locations as asset_locations', 'asset_locations.id', '=', 'assets.rtd_location_id')->orderBy('asset_locations.name', $order); + return $query->leftJoin('locations as asset_locations', 'asset_locations.id', '=', 'assets.location_id')->orderBy('asset_locations.name', $order); } @@ -1175,7 +1175,7 @@ class Asset extends Depreciable public function scopeByLocationId($query, $search) { return $query->where(function ($query) use ($search) { - $query->whereHas('defaultLoc', function ($query) use ($search) { + $query->whereHas('location', function ($query) use ($search) { $query->where('locations.id', '=', $search); }); }); From 55a140045bebff0aef2701c4100dd4dacd8d1c00 Mon Sep 17 00:00:00 2001 From: snipe Date: Thu, 16 Nov 2017 16:50:16 -0800 Subject: [PATCH 3/6] Fixed upgrade language --- upgrade.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/upgrade.php b/upgrade.php index f96036cd77..1370ae4f99 100644 --- a/upgrade.php +++ b/upgrade.php @@ -19,10 +19,10 @@ echo "Welcome to the Snipe-IT upgrader.\n\n"; echo "Please note that this script will not download the latest Snipe-IT \n"; echo "files for you unless you have git installed. \n"; echo "It simply runs the standard composer and artisan \n"; -echo "commands needed to finalize the upgrade after \n\n"; +echo "commands needed to finalize the upgrade after. \n\n"; echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"; -echo "!! If you have any encrypted custom fields, BE SURE TO run the recrypter. \n"; +echo "!! If you have any encrypted custom fields, BE SURE TO run the recrypter if upgrading from v3 to v4. \n"; echo "!! See the Snipe-IT documentation for help: \n"; echo "!! https://snipe-it.readme.io/docs/upgrading-to-v4\n"; echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"; From bfefa104625ee15e6527eb7a4b7bbc2006aee43e Mon Sep 17 00:00:00 2001 From: snipe Date: Mon, 20 Nov 2017 18:54:43 -0800 Subject: [PATCH 4/6] Add @TheVakman as a contributor --- .all-contributorsrc | 10 ++++++++++ README.md | 4 ++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index b7a9b304a3..7192dc8ba6 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -809,6 +809,16 @@ "contributions": [ "doc" ] + }, + { + "login": "TheVakman", + "name": "Lawrence", + "avatar_url": "https://avatars1.githubusercontent.com/u/18545156?v=4", + "profile": "https://github.com/TheVakman", + "contributions": [ + "test", + "bug" + ] } ] } diff --git a/README.md b/README.md index 51b913d31f..6dd4dfd484 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ [![Build Status](https://travis-ci.org/snipe/snipe-it.svg?branch=develop)](https://travis-ci.org/snipe/snipe-it) [![Stories in Ready](https://badge.waffle.io/snipe/snipe-it.png?label=ready+for+dev&title=Ready+for+development)](http://waffle.io/snipe/snipe-it) [![Maintenance](https://img.shields.io/maintenance/yes/2017.svg)]() [![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) [![Zenhub](https://img.shields.io/badge/Shipping_faster_with-ZenHub-5e60ba.svg)](https://zenhub.io) [![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-87-orange.svg?style=flat-square)](#contributors) +[![All Contributors](https://img.shields.io/badge/all_contributors-88-orange.svg?style=flat-square)](#contributors) ## Snipe-IT - Open Source Asset Management System @@ -68,7 +68,7 @@ Thanks goes to all of these wonderful people ([emoji key](https://github.com/ken | [
Gil Rutkowski](http://FlashingCursor.com)
[πŸ’»](https://github.com/snipe/snipe-it/commits?author=flashingcursor "Code") | [
Desmond Morris](http://www.desmondmorris.com)
[πŸ’»](https://github.com/snipe/snipe-it/commits?author=desmondmorris "Code") | [
Nick Peelman](http://peelman.us)
[πŸ’»](https://github.com/snipe/snipe-it/commits?author=peelman "Code") | [
Abraham Vegh](https://abrahamvegh.com)
[πŸ’»](https://github.com/snipe/snipe-it/commits?author=abrahamvegh "Code") | [
Mohamed Rashid](https://github.com/rashivkp)
[πŸ“–](https://github.com/snipe/snipe-it/commits?author=rashivkp "Documentation") | [
Kasey](http://hinchk.github.io)
[πŸ’»](https://github.com/snipe/snipe-it/commits?author=HinchK "Code") | [
Brett](https://github.com/BrettFagerlund)
[⚠️](https://github.com/snipe/snipe-it/commits?author=BrettFagerlund "Tests") | | [
Jason Spriggs](http://jasonspriggs.com)
[πŸ’»](https://github.com/snipe/snipe-it/commits?author=jasonspriggs "Code") | [
Nate Felton](http://n8felton.wordpress.com)
[πŸ’»](https://github.com/snipe/snipe-it/commits?author=n8felton "Code") | [
Manasses Ferreira](http://homepages.dcc.ufmg.br/~manassesferreira)
[πŸ’»](https://github.com/snipe/snipe-it/commits?author=manassesferreira "Code") | [
Steve](https://github.com/steveelwood)
[⚠️](https://github.com/snipe/snipe-it/commits?author=steveelwood "Tests") | [
matc](http://twitter.com/matc)
[⚠️](https://github.com/snipe/snipe-it/commits?author=matc "Tests") | [
Cole R. Davis](http://www.davisracingteam.com)
[⚠️](https://github.com/snipe/snipe-it/commits?author=VanillaNinjaD "Tests") | [
gibsonjoshua55](https://github.com/gibsonjoshua55)
[πŸ’»](https://github.com/snipe/snipe-it/commits?author=gibsonjoshua55 "Code") | | [
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") | +| [
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") | This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome! From 17405f5de1fd903a1d9381c0c37388d801599e64 Mon Sep 17 00:00:00 2001 From: snipe Date: Mon, 20 Nov 2017 19:21:05 -0800 Subject: [PATCH 5/6] Fixed #4413 - Next license seat not bering assigned correctly --- app/Http/Controllers/LicensesController.php | 21 +++++++++++++++------ app/Models/License.php | 9 ++++++--- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/app/Http/Controllers/LicensesController.php b/app/Http/Controllers/LicensesController.php index 94aa4add57..cd3308edbd 100755 --- a/app/Http/Controllers/LicensesController.php +++ b/app/Http/Controllers/LicensesController.php @@ -275,10 +275,19 @@ class LicensesController extends Controller if ($license->getAvailSeatsCountAttribute() < 1) { return redirect()->route('licenses.index')->with('error', 'There are no available seats for this license'); } + + // Get the next available seat for this license $next = $license->freeSeat(); + if (!$next) { + return redirect()->route('licenses.index')->with('error', 'There are no available seats for this license'); + } + + if (!$licenseSeat = LicenseSeat::where('id', '=', $next->id)->first()) { + return redirect()->route('licenses.index')->with('error', 'There are no available seats for this license'); + } + - $licenseSeat = LicenseSeat::where('license_id',$license->id)->find($next)->first(); $assigned_to = $request->input('assigned_to'); $asset_id = $request->input('asset_id'); @@ -299,6 +308,8 @@ class LicensesController extends Controller return redirect()->back()->withInput()->withErrors($validator); } $target = null; + + // If assigned to a user if ($assigned_to!='') { // Check if the user exists if (is_null($target = User::find($assigned_to))) { @@ -307,6 +318,7 @@ class LicensesController extends Controller } } + // If assigned to an asset if ($asset_id!='') { if (is_null($target = Asset::find($asset_id))) { // Redirect to the asset management page with error @@ -318,11 +330,6 @@ class LicensesController extends Controller } } - // Check if the asset exists - if (is_null($licenseSeat)) { - // Redirect to the asset management page with error - return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.not_found')); - } if ($request->input('asset_id') == '') { $licenseSeat->asset_id = null; @@ -337,6 +344,8 @@ class LicensesController extends Controller $licenseSeat->assigned_to = $request->input('assigned_to'); } + $licenseSeat->user_id = Auth::user()->id; + // Was the asset updated? if ($licenseSeat->save()) { $licenseSeat->logCheckout($request->input('note'), $target); diff --git a/app/Models/License.php b/app/Models/License.php index 049675d42a..7ccae0799a 100755 --- a/app/Models/License.php +++ b/app/Models/License.php @@ -347,10 +347,13 @@ class License extends Depreciable */ public function freeSeat() { - return $this->licenseseats() + return $this->licenseseats() ->whereNull('deleted_at') - ->whereNull('assigned_to') - ->whereNull('asset_id') + ->where(function ($query) { + $query->whereNull('assigned_to') + ->whereNull('asset_id'); + }) + ->orderBy('id', 'asc') ->first(); } From c0293a7c1cb726f9fb460631b5d9965ba0ab5f5c Mon Sep 17 00:00:00 2001 From: snipe Date: Mon, 20 Nov 2017 19:39:04 -0800 Subject: [PATCH 6/6] Add @uknzaeinozpas as a contributor --- .all-contributorsrc | 10 ++++++++++ README.md | 4 ++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index 7192dc8ba6..4b205114c0 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -819,6 +819,16 @@ "test", "bug" ] + }, + { + "login": "uknzaeinozpas", + "name": "uknzaeinozpas", + "avatar_url": "https://avatars1.githubusercontent.com/u/22473767?v=4", + "profile": "https://github.com/uknzaeinozpas", + "contributions": [ + "test", + "code" + ] } ] } diff --git a/README.md b/README.md index 6dd4dfd484..0e6326a454 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ [![Build Status](https://travis-ci.org/snipe/snipe-it.svg?branch=develop)](https://travis-ci.org/snipe/snipe-it) [![Stories in Ready](https://badge.waffle.io/snipe/snipe-it.png?label=ready+for+dev&title=Ready+for+development)](http://waffle.io/snipe/snipe-it) [![Maintenance](https://img.shields.io/maintenance/yes/2017.svg)]() [![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) [![Zenhub](https://img.shields.io/badge/Shipping_faster_with-ZenHub-5e60ba.svg)](https://zenhub.io) [![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-88-orange.svg?style=flat-square)](#contributors) +[![All Contributors](https://img.shields.io/badge/all_contributors-89-orange.svg?style=flat-square)](#contributors) ## Snipe-IT - Open Source Asset Management System @@ -68,7 +68,7 @@ Thanks goes to all of these wonderful people ([emoji key](https://github.com/ken | [
Gil Rutkowski](http://FlashingCursor.com)
[πŸ’»](https://github.com/snipe/snipe-it/commits?author=flashingcursor "Code") | [
Desmond Morris](http://www.desmondmorris.com)
[πŸ’»](https://github.com/snipe/snipe-it/commits?author=desmondmorris "Code") | [
Nick Peelman](http://peelman.us)
[πŸ’»](https://github.com/snipe/snipe-it/commits?author=peelman "Code") | [
Abraham Vegh](https://abrahamvegh.com)
[πŸ’»](https://github.com/snipe/snipe-it/commits?author=abrahamvegh "Code") | [
Mohamed Rashid](https://github.com/rashivkp)
[πŸ“–](https://github.com/snipe/snipe-it/commits?author=rashivkp "Documentation") | [
Kasey](http://hinchk.github.io)
[πŸ’»](https://github.com/snipe/snipe-it/commits?author=HinchK "Code") | [
Brett](https://github.com/BrettFagerlund)
[⚠️](https://github.com/snipe/snipe-it/commits?author=BrettFagerlund "Tests") | | [
Jason Spriggs](http://jasonspriggs.com)
[πŸ’»](https://github.com/snipe/snipe-it/commits?author=jasonspriggs "Code") | [
Nate Felton](http://n8felton.wordpress.com)
[πŸ’»](https://github.com/snipe/snipe-it/commits?author=n8felton "Code") | [
Manasses Ferreira](http://homepages.dcc.ufmg.br/~manassesferreira)
[πŸ’»](https://github.com/snipe/snipe-it/commits?author=manassesferreira "Code") | [
Steve](https://github.com/steveelwood)
[⚠️](https://github.com/snipe/snipe-it/commits?author=steveelwood "Tests") | [
matc](http://twitter.com/matc)
[⚠️](https://github.com/snipe/snipe-it/commits?author=matc "Tests") | [
Cole R. Davis](http://www.davisracingteam.com)
[⚠️](https://github.com/snipe/snipe-it/commits?author=VanillaNinjaD "Tests") | [
gibsonjoshua55](https://github.com/gibsonjoshua55)
[πŸ’»](https://github.com/snipe/snipe-it/commits?author=gibsonjoshua55 "Code") | | [
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") | +| [
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") | This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome!