diff --git a/.all-contributorsrc b/.all-contributorsrc
index b7a9b304a..4b205114c 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -809,6 +809,26 @@
"contributions": [
"doc"
]
+ },
+ {
+ "login": "TheVakman",
+ "name": "Lawrence",
+ "avatar_url": "https://avatars1.githubusercontent.com/u/18545156?v=4",
+ "profile": "https://github.com/TheVakman",
+ "contributions": [
+ "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 51b913d31..0e6326a45 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
[](https://travis-ci.org/snipe/snipe-it) [](http://waffle.io/snipe/snipe-it) []() [](https://crowdin.com/project/snipe-it) [](https://gitter.im/snipe/snipe-it?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [](https://hub.docker.com/r/snipe/snipe-it/) [](https://twitter.com/snipeyhead) [](https://zenhub.io) [](https://www.codacy.com/app/snipe/snipe-it?utm_source=github.com&utm_medium=referral&utm_content=snipe/snipe-it&utm_campaign=Badge_Grade)
-[](#contributors)
+[](#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") | [
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!
diff --git a/app/Http/Controllers/Api/AssetsController.php b/app/Http/Controllers/Api/AssetsController.php
index 2f44ac796..2980057ea 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/Http/Controllers/LicensesController.php b/app/Http/Controllers/LicensesController.php
index 94aa4add5..cd3308edb 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/Asset.php b/app/Models/Asset.php
index a8d0035b7..148b97c01 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
@@ -1091,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);
}
@@ -1119,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);
});
});
diff --git a/app/Models/License.php b/app/Models/License.php
index 049675d42..7ccae0799 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();
}
diff --git a/upgrade.php b/upgrade.php
index 07257043e..c4be286c4 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";