Merge branch 'develop'

# Conflicts:
#	app/Importer/Importer.php
#	config/version.php
This commit is contained in:
snipe
2018-04-23 13:33:34 -07:00
62 changed files with 1176 additions and 467 deletions
+18
View File
@@ -893,6 +893,24 @@
"bug",
"doc"
]
},
{
"login": "lea-mink",
"name": "lea-mink",
"avatar_url": "https://avatars2.githubusercontent.com/u/37537300?v=4",
"profile": "https://github.com/lea-mink",
"contributions": [
"code"
]
},
{
"login": "hannahtinkler",
"name": "Hannah Tinkler",
"avatar_url": "https://avatars0.githubusercontent.com/u/7140719?v=4",
"profile": "https://github.com/hannahtinkler",
"contributions": [
"code"
]
}
]
}
+4 -1
View File
@@ -64,7 +64,10 @@ RUN chown -R docker /var/www/html
RUN \
rm -r "/var/www/html/storage/private_uploads" && ln -fs "/var/lib/snipeit/data/private_uploads" "/var/www/html/storage/private_uploads" \
&& rm -rf "/var/www/html/public/uploads" && ln -fs "/var/lib/snipeit/data/uploads" "/var/www/html/public/uploads" \
&& rm -r "/var/www/html/storage/app/backups" && ln -fs "/var/lib/snipeit/dumps" "/var/www/html/storage/app/backups"
&& rm -r "/var/www/html/storage/app/backups" && ln -fs "/var/lib/snipeit/dumps" "/var/www/html/storage/app/backups" \
&& mkdir "/var/lib/snipeit/keys" && ln -fs "/var/lib/snipeit/keys/oauth-private.key" "/var/www/html/storage/oauth-private.key" \
&& ln -fs "/var/lib/snipeit/keys/oauth-public.key" "/var/www/html/storage/oauth-public.key" \
&& chown docker "/var/lib/snipeit/keys/"
############## DEPENDENCIES via COMPOSER ###################
+2 -2
View File
@@ -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-96-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)
[![All Contributors](https://img.shields.io/badge/all_contributors-98-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
@@ -81,7 +81,7 @@ Thanks goes to all of these wonderful people ([emoji key](https://github.com/ken
| [<img src="https://avatars2.githubusercontent.com/u/16108587?v=3" width="110px;"/><br /><sub>Jason Spriggs</sub>](http://jasonspriggs.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=jasonspriggs "Code") | [<img src="https://avatars2.githubusercontent.com/u/1134568?v=3" width="110px;"/><br /><sub>Nate Felton</sub>](http://n8felton.wordpress.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=n8felton "Code") | [<img src="https://avatars2.githubusercontent.com/u/14036694?v=3" width="110px;"/><br /><sub>Manasses Ferreira</sub>](http://homepages.dcc.ufmg.br/~manassesferreira)<br />[💻](https://github.com/snipe/snipe-it/commits?author=manassesferreira "Code") | [<img src="https://avatars0.githubusercontent.com/u/15913949?v=3" width="110px;"/><br /><sub>Steve</sub>](https://github.com/steveelwood)<br />[⚠️](https://github.com/snipe/snipe-it/commits?author=steveelwood "Tests") | [<img src="https://avatars1.githubusercontent.com/u/3361683?v=3" width="110px;"/><br /><sub>matc</sub>](http://twitter.com/matc)<br />[⚠️](https://github.com/snipe/snipe-it/commits?author=matc "Tests") | [<img src="https://avatars3.githubusercontent.com/u/7405702?v=3" width="110px;"/><br /><sub>Cole R. Davis</sub>](http://www.davisracingteam.com)<br />[⚠️](https://github.com/snipe/snipe-it/commits?author=VanillaNinjaD "Tests") | [<img src="https://avatars2.githubusercontent.com/u/10167681?v=3" width="110px;"/><br /><sub>gibsonjoshua55</sub>](https://github.com/gibsonjoshua55)<br />[💻](https://github.com/snipe/snipe-it/commits?author=gibsonjoshua55 "Code") |
| [<img src="https://avatars2.githubusercontent.com/u/2809241?v=4" width="110px;"/><br /><sub>Robin Temme</sub>](https://github.com/zwerch)<br />[💻](https://github.com/snipe/snipe-it/commits?author=zwerch "Code") | [<img src="https://avatars0.githubusercontent.com/u/6961695?v=4" width="110px;"/><br /><sub>Iman</sub>](https://github.com/imanghafoori1)<br />[💻](https://github.com/snipe/snipe-it/commits?author=imanghafoori1 "Code") | [<img src="https://avatars1.githubusercontent.com/u/6551003?v=4" width="110px;"/><br /><sub>Richard Hofman</sub>](https://github.com/richardhofman6)<br />[💻](https://github.com/snipe/snipe-it/commits?author=richardhofman6 "Code") | [<img src="https://avatars0.githubusercontent.com/u/3697569?v=4" width="110px;"/><br /><sub>gizzmojr</sub>](https://github.com/gizzmojr)<br />[💻](https://github.com/snipe/snipe-it/commits?author=gizzmojr "Code") | [<img src="https://avatars3.githubusercontent.com/u/404729?v=4" width="110px;"/><br /><sub>Jenny Li</sub>](https://github.com/imjennyli)<br />[📖](https://github.com/snipe/snipe-it/commits?author=imjennyli "Documentation") | [<img src="https://avatars0.githubusercontent.com/u/869227?v=4" width="110px;"/><br /><sub>Geoff Young</sub>](https://github.com/GeoffYoung)<br />[💻](https://github.com/snipe/snipe-it/commits?author=GeoffYoung "Code") | [<img src="https://avatars3.githubusercontent.com/u/1068477?v=4" width="110px;"/><br /><sub>Elliot Blackburn</sub>](http://www.elliotblackburn.com)<br />[📖](https://github.com/snipe/snipe-it/commits?author=BlueHatbRit "Documentation") |
| [<img src="https://avatars1.githubusercontent.com/u/6357451?v=4" width="110px;"/><br /><sub>Tõnis Ormisson</sub>](http://andmemasin.eu)<br />[💻](https://github.com/snipe/snipe-it/commits?author=TonisOrmisson "Code") | [<img src="https://avatars0.githubusercontent.com/u/449411?v=4" width="110px;"/><br /><sub>Nicolai Essig</sub>](http://www.nicolai-essig.de)<br />[💻](https://github.com/snipe/snipe-it/commits?author=thakilla "Code") | [<img src="https://avatars1.githubusercontent.com/u/14809698?v=4" width="110px;"/><br /><sub>Danielle</sub>](https://github.com/techincolor)<br />[📖](https://github.com/snipe/snipe-it/commits?author=techincolor "Documentation") | [<img src="https://avatars1.githubusercontent.com/u/18545156?v=4" width="110px;"/><br /><sub>Lawrence</sub>](https://github.com/TheVakman)<br />[⚠️](https://github.com/snipe/snipe-it/commits?author=TheVakman "Tests") [🐛](https://github.com/snipe/snipe-it/issues?q=author%3ATheVakman "Bug reports") | [<img src="https://avatars1.githubusercontent.com/u/22473767?v=4" width="110px;"/><br /><sub>uknzaeinozpas</sub>](https://github.com/uknzaeinozpas)<br />[⚠️](https://github.com/snipe/snipe-it/commits?author=uknzaeinozpas "Tests") [💻](https://github.com/snipe/snipe-it/commits?author=uknzaeinozpas "Code") | [<img src="https://avatars3.githubusercontent.com/u/422752?v=4" width="110px;"/><br /><sub>Ryan</sub>](https://github.com/Gelob)<br />[📖](https://github.com/snipe/snipe-it/commits?author=Gelob "Documentation") | [<img src="https://avatars1.githubusercontent.com/u/10672546?v=4" width="110px;"/><br /><sub>vcordes79</sub>](https://github.com/vcordes79)<br />[💻](https://github.com/snipe/snipe-it/commits?author=vcordes79 "Code") |
| [<img src="https://avatars3.githubusercontent.com/u/27958330?v=4" width="110px;"/><br /><sub>fordster78</sub>](https://github.com/fordster78)<br />[💻](https://github.com/snipe/snipe-it/commits?author=fordster78 "Code") | [<img src="https://avatars0.githubusercontent.com/u/34064225?v=4" width="110px;"/><br /><sub>CronKz</sub>](https://github.com/CronKz)<br />[💻](https://github.com/snipe/snipe-it/commits?author=CronKz "Code") | [<img src="https://avatars1.githubusercontent.com/u/585486?v=4" width="110px;"/><br /><sub>Tim Bishop</sub>](https://github.com/tdb)<br />[💻](https://github.com/snipe/snipe-it/commits?author=tdb "Code") | [<img src="https://avatars2.githubusercontent.com/u/5384694?v=4" width="110px;"/><br /><sub>Sean McIlvenna</sub>](https://www.seanmcilvenna.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=seanmcilvenna "Code") | [<img src="https://avatars3.githubusercontent.com/u/36515590?v=4" width="110px;"/><br /><sub>cepacs</sub>](https://github.com/cepacs)<br />[🐛](https://github.com/snipe/snipe-it/issues?q=author%3Acepacs "Bug reports") [📖](https://github.com/snipe/snipe-it/commits?author=cepacs "Documentation") |
| [<img src="https://avatars3.githubusercontent.com/u/27958330?v=4" width="110px;"/><br /><sub>fordster78</sub>](https://github.com/fordster78)<br />[💻](https://github.com/snipe/snipe-it/commits?author=fordster78 "Code") | [<img src="https://avatars0.githubusercontent.com/u/34064225?v=4" width="110px;"/><br /><sub>CronKz</sub>](https://github.com/CronKz)<br />[💻](https://github.com/snipe/snipe-it/commits?author=CronKz "Code") | [<img src="https://avatars1.githubusercontent.com/u/585486?v=4" width="110px;"/><br /><sub>Tim Bishop</sub>](https://github.com/tdb)<br />[💻](https://github.com/snipe/snipe-it/commits?author=tdb "Code") | [<img src="https://avatars2.githubusercontent.com/u/5384694?v=4" width="110px;"/><br /><sub>Sean McIlvenna</sub>](https://www.seanmcilvenna.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=seanmcilvenna "Code") | [<img src="https://avatars3.githubusercontent.com/u/36515590?v=4" width="110px;"/><br /><sub>cepacs</sub>](https://github.com/cepacs)<br />[🐛](https://github.com/snipe/snipe-it/issues?q=author%3Acepacs "Bug reports") [📖](https://github.com/snipe/snipe-it/commits?author=cepacs "Documentation") | [<img src="https://avatars2.githubusercontent.com/u/37537300?v=4" width="110px;"/><br /><sub>lea-mink</sub>](https://github.com/lea-mink)<br />[💻](https://github.com/snipe/snipe-it/commits?author=lea-mink "Code") | [<img src="https://avatars0.githubusercontent.com/u/7140719?v=4" width="110px;"/><br /><sub>Hannah Tinkler</sub>](https://github.com/hannahtinkler)<br />[💻](https://github.com/snipe/snipe-it/commits?author=hannahtinkler "Code") |
<!-- ALL-CONTRIBUTORS-LIST:END -->
This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome!
+54 -7
View File
@@ -77,6 +77,9 @@ class AssetsController extends Controller
'last_audit_date',
'next_audit_date',
'warranty_months',
'checkouts_count',
'checkins_count',
'user_requests_count',
];
$filter = array();
@@ -92,11 +95,7 @@ class AssetsController extends Controller
$assets = Company::scopeCompanyables(Asset::select('assets.*'),"company_id","assets")
->with('location', 'assetstatus', 'assetlog', 'company', 'defaultLoc','assignedTo',
'model.category', 'model.manufacturer', 'model.fieldset','supplier');
'model.category', 'model.manufacturer', 'model.fieldset','supplier')->withCount('checkins', 'checkouts', 'userRequests');
// These are used by the API to query against specific ID numbers.
@@ -106,6 +105,10 @@ class AssetsController extends Controller
$assets->where('assets.status_id', '=', $request->input('status_id'));
}
if ($request->input('requestable')=='true') {
$assets->where('assets.requestable', '=', '1');
}
if ($request->has('model_id')) {
$assets->InModelList([$request->input('model_id')]);
}
@@ -116,7 +119,6 @@ class AssetsController extends Controller
if ($request->has('location_id')) {
$assets->where('assets.location_id', '=', $request->input('location_id'));
// dd($assets->toSql());
}
if ($request->has('supplier_id')) {
@@ -322,7 +324,7 @@ class AssetsController extends Controller
*/
public function show($id)
{
if ($asset = Asset::with('assetstatus')->with('assignedTo')->withTrashed()->findOrFail($id)) {
if ($asset = Asset::with('assetstatus')->with('assignedTo')->withTrashed()->withCount('checkins', 'checkouts', 'userRequests')->findOrFail($id)) {
$this->authorize('view', $asset);
return (new AssetsTransformer)->transformAsset($asset);
}
@@ -736,5 +738,50 @@ class AssetsController extends Controller
}
/**
* Returns JSON listing of all requestable assets
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v4.0]
* @return JsonResponse
*/
public function requestable(Request $request)
{
$assets = Company::scopeCompanyables(Asset::select('assets.*'),"company_id","assets")
->with('location', 'assetstatus', 'assetlog', 'company', 'defaultLoc','assignedTo',
'model.category', 'model.manufacturer', 'model.fieldset','supplier')->where('assets.requestable', '=', '1');
$offset = request('offset', 0);
$limit = $request->input('limit', 50);
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
$assets->TextSearch($request->input('search'));
switch ($request->input('sort')) {
case 'model':
$assets->OrderModels($order);
break;
case 'model_number':
$assets->OrderModelNumber($order);
break;
case 'category':
$assets->OrderCategory($order);
break;
case 'manufacturer':
$assets->OrderManufacturer($order);
break;
default:
$assets->orderBy('assets.created_at', $order);
break;
}
$total = $assets->count();
$assets = $assets->skip($offset)->take($limit)->get();
return (new AssetsTransformer)->transformRequestedAssets($assets, $total);
}
}
@@ -35,6 +35,10 @@ class ComponentsController extends Controller
$components->where('company_id','=',$request->input('company_id'));
}
if ($request->has('category_id')) {
$components->where('category_id','=',$request->input('category_id'));
}
$offset = request('offset', 0);
$limit = request('limit', 50);
@@ -0,0 +1,44 @@
<?php
namespace App\Http\Controllers\Api;
use App\Models\CheckoutRequest;
use App\Http\Controllers\Controller;
use Auth;
use App\Helpers\Helper;
class ProfileController extends Controller
{
/**
* Display a listing of requested assets.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v4.3.0]
*
* @return Array
*/
public function requestedAssets()
{
$checkoutRequests = CheckoutRequest::where('user_id', '=', Auth::user()->id)->get();
$results = [];
$results['total'] = $checkoutRequests->count();
foreach ($checkoutRequests as $checkoutRequest) {
$results['rows'][] = [
'image' => $checkoutRequest->itemRequested()->present()->getImageUrl(),
'name' => $checkoutRequest->itemRequested()->present()->name(),
'type' => $checkoutRequest->itemType(),
'qty' => $checkoutRequest->quantity,
'location' => ($checkoutRequest->location()) ? $checkoutRequest->location()->name : null,
'expected_checkin' => Helper::getFormattedDateObject($checkoutRequest->itemRequested()->expected_checkin, 'datetime'),
'request_date' => Helper::getFormattedDateObject($checkoutRequest->created_at, 'datetime'),
];
}
return $results;
}
}
@@ -134,12 +134,6 @@ class SettingsController extends Controller
if (!config('app.lock_passwords')) {
try {
Notification::send(Setting::first(), new MailTest());
/*Mail::send('emails.test', [], function ($m) {
$m->to(config('mail.reply_to.address'), config('mail.reply_to.name'));
$m->replyTo(config('mail.reply_to.address'), config('mail.reply_to.name'));
$m->subject(trans('mail.test_email'));
});*/
return response()->json(['message' => 'Mail sent to '.config('mail.reply_to.address')], 200);
} catch (Exception $e) {
return response()->json(['message' => $e->getMessage()], 500);
@@ -25,7 +25,7 @@ class SuppliersController extends Controller
$allowed_columns = ['id','name','address','phone','contact','fax','email','image','assets_count','licenses_count', 'accessories_count'];
$suppliers = Supplier::select(
array('id','name','address','address2','city','state','country','fax', 'phone','email','contact','created_at','updated_at','deleted_at','image')
array('id','name','address','address2','city','state','country','fax', 'phone','email','contact','created_at','updated_at','deleted_at','image','notes')
)->withCount('assets')->withCount('licenses')->withCount('accessories')->whereNull('deleted_at');
+3 -1
View File
@@ -194,7 +194,9 @@ class UsersController extends Controller
$this->authorize('view', User::class);
$user = new User;
$user->fill($request->all());
$user->password = bcrypt($request->input('password'));
$tmp_pass = substr(str_shuffle("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), 0, 20);
$user->password = bcrypt($request->get('password', $tmp_pass));
if ($user->save()) {
return response()->json(Helper::formatStandardApiResponse('success', (new UsersTransformer)->transformUser($user), trans('admin/users/message.success.create')));
+8 -4
View File
@@ -1305,12 +1305,16 @@ class AssetsController extends Controller
}
}
public function getRequestedIndex($id = null)
public function getRequestedIndex($user_id = null)
{
if ($id) {
$requestedItems = CheckoutRequest::where('user_id', $id)->with('user', 'requestedItem')->get();
$requestedItems = CheckoutRequest::with('user', 'requestedItem')->whereNull('canceled_at')->with('user', 'requestedItem');
if ($user_id) {
$requestedItems->where('user_id', $user_id)->get();
}
$requestedItems = CheckoutRequest::with('user', 'requestedItem')->get();
$requestedItems = $requestedItems->orderBy('created_at', 'desc')->get();
return view('hardware/requested', compact('requestedItems'));
}
+45 -6
View File
@@ -503,6 +503,19 @@ class ReportsController extends Controller
$header[] = trans('general.zip');
}
if ($request->has('rtd_location')) {
$header[] = trans('admin/hardware/form.default_location');
}
if ($request->has('rtd_location_address')) {
$header[] = trans('general.address');
$header[] = trans('general.address');
$header[] = trans('general.city');
$header[] = trans('general.state');
$header[] = trans('general.country');
$header[] = trans('general.zip');
}
if ($request->has('assigned_to')) {
$header[] = trans('admin/hardware/table.checkoutto');
$header[] = trans('general.type');
@@ -516,6 +529,10 @@ class ReportsController extends Controller
$header[] = 'Employee No.';
}
if ($request->has('department')) {
$header[] = trans('general.department');
}
if ($request->has('status')) {
$header[] = trans('general.status');
}
@@ -671,12 +688,25 @@ class ReportsController extends Controller
}
if ($request->has('location_address')) {
$row[] = ($asset->location) ? $asset->location->address : '';
$row[] = ($asset->location) ? $asset->location->address2 : '';
$row[] = ($asset->location) ? $asset->location->city : '';
$row[] = ($asset->location) ? $asset->location->state : '';
$row[] = ($asset->location) ? $asset->location->country : '';
$row[] = ($asset->location) ? $asset->location->zip : '';
$row[] = ($asset->defaultLoc) ? $asset->defaultLoc->address : '';
$row[] = ($asset->defaultLoc) ? $asset->defaultLoc->address2 : '';
$row[] = ($asset->defaultLoc) ? $asset->defaultLoc->city : '';
$row[] = ($asset->defaultLoc) ? $asset->defaultLoc->state : '';
$row[] = ($asset->defaultLoc) ? $asset->defaultLoc->country : '';
$row[] = ($asset->defaultLoc) ? $asset->defaultLoc->zip : '';
}
if ($request->has('rtd_location')) {
$row[] = ($asset->location) ? $asset->defaultLoc->present()->name() : '';
}
if ($request->has('rtd_location_address')) {
$row[] = ($asset->defaultLoc) ? $asset->defaultLoc->address : '';
$row[] = ($asset->defaultLoc) ? $asset->defaultLoc->address2 : '';
$row[] = ($asset->defaultLoc) ? $asset->defaultLoc->city : '';
$row[] = ($asset->defaultLoc) ? $asset->defaultLoc->state : '';
$row[] = ($asset->defaultLoc) ? $asset->defaultLoc->country : '';
$row[] = ($asset->defaultLoc) ? $asset->defaultLoc->zip : '';
}
@@ -703,6 +733,15 @@ class ReportsController extends Controller
}
}
if ($request->has('department')) {
if ($asset->checkedOutToUser()) {
$row[] = (($asset->assignedto) && ($asset->assignedto->department)) ? $asset->assignedto->department->name : '';
} else {
$row[] = ''; // Empty string if unassigned
}
}
if ($request->has('status')) {
$row[] = ($asset->assetstatus) ? $asset->assetstatus->name.' ('.$asset->present()->statusMeta.')' : '';
}
+54 -129
View File
@@ -12,6 +12,8 @@ use App\Models\Consumable;
use App\Models\License;
use App\Models\Setting;
use App\Models\User;
use App\Notifications\RequestAssetNotification;
use App\Notifications\RequestAssetCancelationNotification;
use Auth;
use Config;
use DB;
@@ -80,116 +82,71 @@ class ViewAssetsController extends Controller
{
$item = null;
$fullItemType = 'App\\Models\\' . studly_case($itemType);
if ($itemType == "asset_model") {
$itemType = "model";
}
$item = call_user_func(array($fullItemType, 'find'), $itemId);
$user = Auth::user();
$quantity = $data['item_quantity'] = Input::has('request-quantity') ? e(Input::get('request-quantity')) : 1;
$logaction = new Actionlog();
$logaction->item_id = $data['asset_id'] = $item->id;
$logaction->item_type = $fullItemType;
$logaction->created_at = $data['requested_date'] = date("Y-m-d H:i:s");
if ($user->location_id) {
$logaction->location_id = $user->location_id;
}
$logaction->target_id = $data['user_id'] = Auth::user()->id;
$logaction->target_type = User::class;
$data['item_quantity'] = Input::has('request-quantity') ? e(Input::get('request-quantity')) : 1;
$data['requested_by'] = $user->present()->fullName();
$data['item_name'] = $item->name;
$data['item'] = $item;
$data['item_type'] = $itemType;
$data['target'] = Auth::user();
if ($fullItemType == Asset::class) {
$data['item_url'] = route('hardware.show', $item->id);
$slackMessage = ' Asset <'.url('/').'/hardware/'.$item->id.'/view'.'|'.$item->present()->name().'> requested by <'.url('/').'/users/'.$item->user_id.'/view'.'|'.$user->present()->fullName().'>.';
} else {
$data['item_url'] = route("view/${itemType}", $item->id);
$slackMessage = $quantity. ' ' . class_basename(strtoupper($logaction->item_type)).' <'.$data['item_url'].'|'.$item->name.'> requested by <'.url('/').'/user/'.$item->id.'/view'.'|'.$user->present()->fullName().'>.';
}
$settings = Setting::getSettings();
if ($settings->slack_endpoint) {
$slack_settings = [
'username' => $settings->botname,
'channel' => $settings->slack_channel,
'link_names' => true
];
$slackClient = new \Maknz\Slack\Client($settings->slack_endpoint, $slack_settings);
}
if ($item->isRequestedBy($user)) {
$item->cancelRequest();
$log = $logaction->logaction('request_canceled');
if ($item_request = $item->isRequestedBy($user)) {
$item->cancelRequest();
$data['item_quantity'] = $item_request->qty;
$logaction->logaction('request_canceled');
if (($settings->alert_email!='') && ($settings->alerts_enabled=='1') && (!config('app.lock_passwords'))) {
Mail::send('emails.asset-canceled', $data, function ($m) use ($user, $settings) {
$m->to(explode(',', $settings->alert_email), $settings->site_name);
$m->replyTo(config('mail.reply_to.address'), config('mail.reply_to.name'));
$m->subject(trans('mail.Item_Request_Canceled'));
});
}
if ($settings->slack_endpoint) {
try {
$slackClient->attach([
'color' => 'good',
'fields' => [
[
'title' => 'CANCELED:',
'value' => $slackMessage
]
]
])->send('Item Request Canceled');
} catch (Exception $e) {
}
$settings->notify(new RequestAssetCancelationNotification($data));
}
return redirect()->route('requestable-assets')->with('success')->with('success', trans('admin/hardware/message.requests.canceled'));
} else {
$item->request();
$log = $logaction->logaction('requested');
if (($settings->alert_email!='') && ($settings->alerts_enabled=='1') && (!config('app.lock_passwords'))) {
Mail::send('emails.asset-requested', $data, function ($m) use ($user, $settings) {
$m->to(explode(',', $settings->alert_email), $settings->site_name);
$m->replyTo(config('mail.reply_to.address'), config('mail.reply_to.name'));
$m->subject(trans('mail.Item_Requested'));
});
$logaction->logaction('requested');
$settings->notify(new RequestAssetNotification($data));
}
if ($settings->slack_endpoint) {
try {
$slackClient->attach([
'color' => 'good',
'fields' => [
[
'title' => 'REQUESTED:',
'value' => $slackMessage
]
]
])->send('Item Requested');
} catch (Exception $e) {
}
}
return redirect()->route('requestable-assets')->with('success')->with('success', trans('admin/hardware/message.requests.success'));
}
}
public function getRequestAsset($assetId = null)
{
@@ -197,74 +154,45 @@ class ViewAssetsController extends Controller
// Check if the asset exists and is requestable
if (is_null($asset = Asset::RequestableAssets()->find($assetId))) {
// Redirect to the asset management page
return redirect()->route('requestable-assets')->with('error', trans('admin/hardware/message.does_not_exist_or_not_requestable'));
return redirect()->route('requestable-assets')
->with('error', trans('admin/hardware/message.does_not_exist_or_not_requestable'));
} elseif (!Company::isCurrentUserHasAccess($asset)) {
return redirect()->route('requestable-assets')->with('error', trans('general.insufficient_permissions'));
return redirect()->route('requestable-assets')
->with('error', trans('general.insufficient_permissions'));
}
// If it's requested, cancel the request.
$data['item'] = $asset;
$data['target'] = Auth::user();
$data['item_quantity'] = 1;
$settings = Setting::getSettings();
$logaction = new Actionlog();
$logaction->item_id = $data['asset_id'] = $asset->id;
$logaction->item_type = $data['item_type'] = Asset::class;
$logaction->created_at = $data['requested_date'] = date("Y-m-d H:i:s");
if ($user->location_id) {
$logaction->location_id = $user->location_id;
}
$logaction->target_id = $data['user_id'] = Auth::user()->id;
$logaction->target_type = User::class;
// If it's already requested, cancel the request.
if ($asset->isRequestedBy(Auth::user())) {
$asset->cancelRequest();
return redirect()->route('requestable-assets')->with('success')->with('success', trans('admin/hardware/message.requests.success'));
$logaction->logaction('request canceled');
$settings->notify(new RequestAssetCancelationNotification($data));
return redirect()->route('requestable-assets')
->with('success')->with('success', trans('admin/hardware/message.requests.cancel-success'));
} else {
$logaction = new Actionlog();
$logaction->item_id = $data['asset_id'] = $asset->id;
$logaction->item_type = Asset::class;
$logaction->created_at = $data['requested_date'] = date("Y-m-d H:i:s");
$data['asset_type'] = 'hardware';
if ($user->location_id) {
$logaction->location_id = $user->location_id;
}
$logaction->target_id = $data['user_id'] = Auth::user()->id;
$logaction->target_type = User::class;
$log = $logaction->logaction('requested');
$data['requested_by'] = $user->present()->fullName();
$data['asset_name'] = $asset->present()->name();
$settings = Setting::getSettings();
if (($settings->alert_email!='') && ($settings->alerts_enabled=='1') && (!config('app.lock_passwords'))) {
Mail::send('emails.asset-requested', $data, function ($m) use ($user, $settings) {
$m->to(explode(',', $settings->alert_email), $settings->site_name);
$m->replyTo(config('mail.reply_to.address'), config('mail.reply_to.name'));
$m->subject(trans('mail.asset_requested'));
});
}
$logaction->logaction('requested');
$asset->request();
$settings->notify(new RequestAssetNotification($data));
if ($settings->slack_endpoint) {
$slack_settings = [
'username' => $settings->botname,
'channel' => $settings->slack_channel,
'link_names' => true
];
$client = new \Maknz\Slack\Client($settings->slack_endpoint, $slack_settings);
try {
$client->attach([
'color' => 'good',
'fields' => [
[
'title' => 'REQUESTED:',
'value' => class_basename(strtoupper($logaction->item_type)).' asset <'.url('/').'/hardware/'.$asset->id.'/view'.'|'.$asset->present()->name().'> requested by <'.url('/').'/hardware/'.$asset->id.'/view'.'|'.Auth::user()->present()->fullName().'>.'
]
]
])->send('Asset Requested');
} catch (Exception $e) {
}
}
return redirect()->route('requestable-assets')->with('success')->with('success', trans('admin/hardware/message.requests.success'));
}
@@ -273,13 +201,10 @@ class ViewAssetsController extends Controller
public function getRequestedAssets()
{
$checkoutrequests = CheckoutRequest::all();
return view('account/requested-items', compact($checkoutrequests));
return view('account/requested');
}
// Get the acceptance screen
public function getAcceptAsset($logID = null)
{
+4 -1
View File
@@ -35,7 +35,10 @@ class SaveUserRequest extends Request
{
$rules['first_name'] = 'required|string|min:1';
$rules['username'] = 'required_unless:ldap_import,1|string|min:1';
$rules['password'] = Setting::passwordComplexityRulesSaving('store');
if ($this->request->get('ldap_import') == false)
{
$rules['password'] = Setting::passwordComplexityRulesSaving('store');
}
break;
}
@@ -77,6 +77,9 @@ class AssetsTransformer
'last_checkout' => Helper::getFormattedDateObject($asset->last_checkout, 'datetime'),
'expected_checkin' => Helper::getFormattedDateObject($asset->expected_checkin, 'date'),
'purchase_cost' => Helper::formatCurrencyOutput($asset->purchase_cost),
'checkins_count' => (int) $asset->checkins_count,
'checkouts_count' => (int) $asset->checkouts_count,
'user_requests_count' => (int) $asset->user_requests_count,
'user_can_checkout' => (bool) $asset->availableForCheckout(),
];
@@ -160,4 +163,39 @@ class AssetsTransformer
'type' => $asset->assignedType()
] : null;
}
public function transformRequestedAssets(Collection $assets, $total)
{
$array = array();
foreach ($assets as $asset) {
$array[] = self::transformRequestedAsset($asset);
}
return (new DatatablesTransformer)->transformDatatables($array, $total);
}
public function transformRequestedAsset(Asset $asset) {
$array = [
'id' => (int) $asset->id,
'name' => e($asset->name),
'asset_tag' => e($asset->asset_tag),
'serial' => e($asset->serial),
'image' => ($asset->getImageUrl()) ? $asset->getImageUrl() : null,
'model' => ($asset->model) ? e($asset->model->name) : null,
'model_number' => (($asset->model) && ($asset->model->model_number)) ? e($asset->model->model_number) : null,
'expected_checkin' => Helper::getFormattedDateObject($asset->expected_checkin, 'date'),
'location' => ($asset->location) ? e($asset->location->name) : null,
'status'=> ($asset->assetstatus) ? $asset->present()->statusMeta : null,
];
$permissions_array['available_actions'] = [
'cancel' => ($asset->isRequestedBy(\Auth::user())) ? true : false,
'request' => ($asset->isRequestedBy(\Auth::user())) ? false : true,
];
$array += $permissions_array;
return $array;
}
}
+34 -23
View File
@@ -119,10 +119,13 @@ abstract class Importer
// Remove any custom fields that do not exist in the header row. This prevents nulling out values that shouldn't exist.
// In detail, we compare the lower case name of custom fields (indexed by name) to the keys in the header row. This
// results in an array with only custom fields that are in the file.
$this->customFields = array_intersect_key(
array_change_key_case($this->customFields),
array_change_key_case(array_flip($headerRow))
);
if ($this->customFields) {
$this->customFields = array_intersect_key(
array_change_key_case($this->customFields),
array_change_key_case(array_flip($headerRow))
);
}
DB::transaction(function () use (&$results) {
@@ -244,6 +247,18 @@ abstract class Importer
$user_username = $this->findCsvMatch($row, "username");
$first_name = '';
$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)) {
$user = User::where('username', $user_username)->first();
if($user) {
return $user;
}
}
// A number was given instead of a name
if (is_numeric($user_name)) {
$this->log('User '.$user_name.' is not a name - assume this user already exists');
@@ -252,28 +267,24 @@ abstract class Importer
return $user;
}
$this->log('User with id'.$user_name.' does not exist. Continuing through our processes');
} elseif (empty($user_name)) {
$this->log('No user data provided - skipping user creation, just adding asset');
//$user_username = '';
return false;
} else {
$user_email_array = User::generateFormattedNameFromFullName(Setting::getSettings()->email_format, $user_name);
$first_name = $user_email_array['first_name'];
$last_name = $user_email_array['last_name'];
}
// Generate data based on user name.
$user_email_array = User::generateFormattedNameFromFullName(Setting::getSettings()->email_format, $user_name);
$first_name = $user_email_array['first_name'];
$last_name = $user_email_array['last_name'];
if ($user_email=='') {
if (Setting::getSettings()->email_domain) {
$user_email = str_slug($user_email_array['username']).'@'.Setting::getSettings()->email_domain;
}
if (empty($user_email)) {
if (Setting::getSettings()->email_domain) {
$user_email = str_slug($user_email_array['username']).'@'.Setting::getSettings()->email_domain;
}
}
if ($user_username=='') {
if ($this->usernameFormat =='email') {
$user_username = $user_email;
} else {
$user_name_array = User::generateFormattedNameFromFullName(Setting::getSettings()->username_format, $user_name);
$user_username = $user_name_array['username'];
}
if (empty($user_username)) {
if ($this->usernameFormat =='email') {
$user_username = $user_email;
} else {
$user_name_array = User::generateFormattedNameFromFullName(Setting::getSettings()->username_format, $user_name);
$user_username = $user_name_array['username'];
}
}
$user = new User;
+33 -1
View File
@@ -11,7 +11,6 @@ use Config;
use Illuminate\Database\Eloquent\SoftDeletes;
use Log;
use Watson\Validating\ValidatingTrait;
use Illuminate\Notifications\Notifiable;
use DB;
use App\Notifications\CheckinAssetNotification;
use App\Notifications\CheckoutAssetNotification;
@@ -95,6 +94,7 @@ class Asset extends Depreciable
'assigned_type',
'company_id',
'image',
'location_id',
'model_id',
'name',
'notes',
@@ -350,6 +350,38 @@ class Asset extends Depreciable
->withTrashed();
}
/**
* Get checkouts
*/
public function checkouts()
{
return $this->assetlog()->where('action_type', '=', 'checkout')
->orderBy('created_at', 'desc')
->withTrashed();
}
/**
* Get checkins
*/
public function checkins()
{
return $this->assetlog()
->where('action_type', '=', 'checkin from')
->orderBy('created_at', 'desc')
->withTrashed();
}
/**
* Get user requests
*/
public function userRequests()
{
return $this->assetlog()
->where('action_type', '=', 'requested')
->orderBy('created_at', 'desc')
->withTrashed();
}
/**
* assetmaintenances
+2 -1
View File
@@ -52,7 +52,8 @@ class AssetMaintenance extends Model implements ICompanyableChild
return [
trans('admin/asset_maintenances/general.maintenance') => trans('admin/asset_maintenances/general.maintenance'),
trans('admin/asset_maintenances/general.repair') => trans('admin/asset_maintenances/general.repair'),
trans('admin/asset_maintenances/general.upgrade') => trans('admin/asset_maintenances/general.upgrade')
trans('admin/asset_maintenances/general.upgrade') => trans('admin/asset_maintenances/general.upgrade'),
'PAT test' => 'PAT test',
];
}
+8
View File
@@ -98,6 +98,14 @@ class AssetModel extends SnipeModel
return $this->belongsTo('\App\Models\CustomFieldset', 'fieldset_id');
}
public function getImageUrl() {
if ($this->image) {
return url('/').'/uploads/models/'.$this->image;
}
return false;
}
/**
* -----------------------------------------------
* BEGIN QUERY SCOPES
+2 -1
View File
@@ -1,12 +1,13 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Model;
class CheckoutRequest extends Model
{
//
use SoftDeletes;
protected $fillable = ['user_id'];
protected $table = 'checkout_requests';
+1 -1
View File
@@ -20,7 +20,7 @@ class Location extends SnipeModel
protected $table = 'locations';
protected $rules = array(
'name' => 'required|min:2|max:255|unique_undeleted',
'city' => 'min:3|max:255|nullable',
'city' => 'min:2|max:255|nullable',
'country' => 'min:2|max:2|nullable',
'address' => 'max:80|nullable',
'address2' => 'max:80|nullable',
+9 -6
View File
@@ -19,9 +19,7 @@ trait Requestable
public function isRequestedBy(User $user)
{
$requests = $this->requests->where('user_id', $user->id);
return $requests->count() > 0;
return $this->requests->where('canceled_at', NULL)->where('user_id', $user->id)->first();
}
public function scopeRequestedBy($query, User $user)
@@ -31,15 +29,20 @@ trait Requestable
});
}
public function request()
public function request($qty = 1)
{
$this->requests()->save(
new CheckoutRequest(['user_id' => Auth::id()])
new CheckoutRequest(['user_id' => Auth::id(), 'qty' => $qty])
);
}
public function deleteRequest()
{
$this->requests()->where('user_id', Auth::id())->delete();
}
public function cancelRequest()
{
$this->requests()->where('user_id', Auth::id())->delete();
$this->requests()->where('user_id', Auth::id())->update(['canceled_at' => \Carbon\Carbon::now()]);
}
}
+2 -1
View File
@@ -39,6 +39,7 @@ class User extends SnipeModel implements AuthenticatableContract, CanResetPasswo
'first_name',
'jobtitle',
'last_name',
'ldap_import',
'locale',
'location_id',
'manager_id',
@@ -292,7 +293,7 @@ class User extends SnipeModel implements AuthenticatableContract, CanResetPasswo
*/
public function checkoutRequests()
{
return $this->belongsToMany(Asset::class, 'checkout_requests');
return $this->belongsToMany(Asset::class, 'checkout_requests', 'user_id', 'requestable_id')->whereNull('canceled_at');
}
public function throttle()
@@ -0,0 +1,137 @@
<?php
namespace App\Notifications;
use App\Models\Setting;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Messages\SlackMessage;
use Illuminate\Notifications\Notification;
class RequestAssetCancelationNotification extends Notification
{
/**
* @var
*/
private $params;
/**
* Create a new notification instance.
*
* @param $params
*/
public function __construct($params)
{
$this->target = $params['target'];
$this->item = $params['item'];
$this->note = '';
$this->last_checkout = '';
$this->item_quantity = $params['item_quantity'];
$this->expected_checkin = '';
$this->requested_date = \App\Helpers\Helper::getFormattedDateObject($params['requested_date'], 'datetime',
false);
$this->settings = Setting::getSettings();
if (array_key_exists('note', $params)) {
$this->note = $params['note'];
}
if ($this->item->last_checkout) {
$this->last_checkout = \App\Helpers\Helper::getFormattedDateObject($this->item->last_checkout, 'date',
false);
}
if ($this->item->expected_checkin) {
$this->expected_checkin = \App\Helpers\Helper::getFormattedDateObject($this->item->expected_checkin, 'date',
false);
}
}
/**
* Get the notification's delivery channels.
*
* @param mixed $notifiable
* @return array
*/
public function via()
{
$notifyBy = [];
if (Setting::getSettings()->slack_endpoint!='') {
\Log::debug('use slack');
$notifyBy[] = 'slack';
}
$notifyBy[] = 'mail';
return $notifyBy;
}
public function toSlack()
{
$target = $this->target;
$item = $this->item;
$note = $this->note;
$qty = $this->item_quantity;
$botname = ($this->settings->slack_botname) ? $this->settings->slack_botname : 'Snipe-Bot' ;
$fields = [
'QTY' => $qty,
'Canceled By' => '<'.$target->present()->viewUrl().'|'.$target->present()->fullName().'>',
];
if (($this->expected_checkin) && ($this->expected_checkin!='')) {
$fields['Expected Checkin'] = $this->expected_checkin;
}
return (new SlackMessage)
->content( trans('mail.a_user_canceled'))
->from($botname)
->attachment(function ($attachment) use ($item, $note, $fields) {
$attachment->title(htmlspecialchars_decode($item->present()->name), $item->present()->viewUrl())
->fields($fields)
->content($note);
});
}
/**
* Get the mail representation of the notification.
*
* @param mixed $notifiable
* @return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail()
{
$fields = [];
// Check if the item has custom fields associated with it
if (($this->item->model) && ($this->item->model->fieldset)) {
$fields = $this->item->model->fieldset->fields;
}
$message = (new MailMessage)->markdown('notifications.markdown.asset-requested',
[
'item' => $this->item,
'note' => $this->note,
'requested_by' => $this->target,
'requested_date' => $this->requested_date,
'fields' => $fields,
'qty' => $this->item_quantity,
'last_checkout' => $this->last_checkout,
'expected_checkin' => $this->expected_checkin,
'intro_text' => trans('mail.a_user_canceled'),
])
->subject(trans('Item Request Canceled'));
return $message;
}
}
@@ -0,0 +1,134 @@
<?php
namespace App\Notifications;
use App\Models\Setting;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Messages\SlackMessage;
use Illuminate\Notifications\Notification;
class RequestAssetNotification extends Notification
{
/**
* @var
*/
private $params;
/**
* Create a new notification instance.
*
* @param $params
*/
public function __construct($params)
{
$this->target = $params['target'];
$this->item = $params['item'];
$this->item_type = $params['item_type'];
$this->item_quantity = $params['item_quantity'];
$this->note = '';
$this->last_checkout = '';
$this->expected_checkin = '';
$this->requested_date = \App\Helpers\Helper::getFormattedDateObject($params['requested_date'], 'datetime',
false);
$this->settings = Setting::getSettings();
if (array_key_exists('note', $params)) {
$this->note = $params['note'];
}
if ($this->item->last_checkout) {
$this->last_checkout = \App\Helpers\Helper::getFormattedDateObject($this->item->last_checkout, 'date',
false);
}
if ($this->item->expected_checkin) {
$this->expected_checkin = \App\Helpers\Helper::getFormattedDateObject($this->item->expected_checkin, 'date',
false);
}
}
/**
* Get the notification's delivery channels.
*
* @param mixed $notifiable
* @return array
*/
public function via()
{
$notifyBy = [];
if (Setting::getSettings()->slack_endpoint!='') {
\Log::debug('use slack');
$notifyBy[] = 'slack';
}
$notifyBy[] = 'mail';
return $notifyBy;
}
public function toSlack()
{
$target = $this->target;
$qty = $this->item_quantity;
$item = $this->item;
$note = $this->note;
$botname = ($this->settings->slack_botname) ? $this->settings->slack_botname : 'Snipe-Bot' ;
$fields = [
'QTY' => $qty,
'Requested By' => '<'.$target->present()->viewUrl().'|'.$target->present()->fullName().'>',
];
return (new SlackMessage)
->content(trans('mail.Item_Requested'))
->from($botname)
->attachment(function ($attachment) use ($item, $note, $fields) {
$attachment->title(htmlspecialchars_decode($item->present()->name), $item->present()->viewUrl())
->fields($fields)
->content($note);
});
}
/**
* Get the mail representation of the notification.
*
* @param mixed $notifiable
* @return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail()
{
$fields = [];
// Check if the item has custom fields associated with it
if (($this->item->model) && ($this->item->model->fieldset)) {
$fields = $this->item->model->fieldset->fields;
}
$message = (new MailMessage)->markdown('notifications.markdown.asset-requested',
[
'item' => $this->item,
'note' => $this->note,
'requested_by' => $this->target,
'requested_date' => $this->requested_date,
'fields' => $fields,
'last_checkout' => $this->last_checkout,
'expected_checkin' => $this->expected_checkin,
'intro_text' => trans('mail.a_user_requested'),
'qty' => $this->item_quantity,
])
->subject(trans('mail.Item_Requested'));
return $message;
}
}
@@ -70,6 +70,11 @@ class AssetMaintenancesPresenter extends Presenter
"searchable" => true,
"sortable" => true,
"title" => trans('admin/asset_maintenances/form.asset_maintenance_type'),
], [
"field" => "title",
"searchable" => true,
"sortable" => true,
"title" => trans('admin/asset_maintenances/form.title'),
], [
"field" => "created_at",
"searchable" => true,
+21
View File
@@ -181,6 +181,27 @@ class AssetPresenter extends Presenter
"visible" => false,
"title" => trans('general.notes'),
], [
"field" => "checkouts_count",
"searchable" => false,
"sortable" => true,
"visible" => false,
"title" => trans('general.checkouts_count')
],[
"field" => "checkins_count",
"searchable" => false,
"sortable" => true,
"visible" => false,
"title" => trans('general.checkins_count')
], [
"field" => "user_requests_count",
"searchable" => false,
"sortable" => true,
"visible" => false,
"title" => trans('general.user_requests_count')
], [
"field" => "created_at",
"searchable" => false,
+2 -2
View File
@@ -1,8 +1,8 @@
<?php
return array (
'app_version' => 'v4.2.0',
'full_app_version' => 'v4.2.0 - build 3497-g590938f',
'build_version' => '3497',
'full_app_version' => 'v4.2.0 - build 3508-g086711e46',
'build_version' => '3508',
'prerelease_version' => '',
'hash_version' => 'g590938f',
'full_hash' => 'v4.2.0-4-g590938f',
@@ -0,0 +1,36 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class AddCanceledAtAndFulfilledAtInRequests extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('checkout_requests', function (Blueprint $table) {
$table->dateTime('canceled_at')->nullable()->default(null);
$table->dateTime('fulfilled_at')->nullable()->default(null);
$table->dateTime('deleted_at')->nullable()->default(null);
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('checkout_requests', function (Blueprint $table) {
$table->dropColumn('canceled_at');
$table->dropColumn('fulfilled_at');
$table->dropColumn('deleted_at');
});
}
}
@@ -0,0 +1,32 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class AddDropUniqueRequests extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('checkout_requests', function (Blueprint $table) {
$table->dropUnique('checkout_requests_user_id_requestable_id_requestable_type_unique');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('checkout_requests', function (Blueprint $table) {
$table->index(['user_id','requestable_id','requestable_type'], 'checkout_requests_user_id_requestable_id_requestable_type_unique')->unique();
});
}
}
@@ -0,0 +1,32 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class AddNewIndexRequestable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('checkout_requests', function (Blueprint $table) {
$table->index(['user_id','requestable_id','requestable_type'], 'checkout_requests_user_id_requestable_id_requestable_type');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('checkout_requests', function (Blueprint $table) {
$table->dropIndex('checkout_requests_user_id_requestable_id_requestable_type');
});
}
}
-28
View File
@@ -1,28 +0,0 @@
# Docker Environment File
#Database Variables
MYSQL_ROOT_PASSWORD=supersecuresecretthing
MYSQL_DATABASE=snipeit
MYSQL_USER=snipeit
MYSQL_PASSWORD=tinglewingler
#Email Variables
MAIL_PORT_587_TCP_ADDR=smtp.mandrillapp.com
MAIL_PORT_587_TCP_PORT=587
MAIL_ENV_FROM_ADDR=you@example.com
MAIL_ENV_FROM_NAME=Snipe-IT
MAIL_ENV_ENCRYPTION=tcp
MAIL_ENV_USERNAME=you@example.com
MAIL_ENV_PASSWORD=N7AqLufTZMULWHWYwJ0ZCw
MAIL_ENV_REPLYTO_ADDR=you@example.com
MAIL_ENV_REPLYTO_NAME='Snipe-IT'
#SNIPE-IT Variables
APP_ENV=develop
APP_DEBUG=true
APP_KEY=Y5hJeC7x1i7OxhDrvrQPlB9KvCorvRdO
APP_URL=http://127.0.0.1:32782
APP_TIMEZONE=US/Pacific
APP_LOCALE=en
ALLOW_IFRAMING=false
+2 -2
View File
@@ -50,7 +50,7 @@
.fixed-table-body {
overflow-x: auto;
overflow-y: auto;
height: 100%;
height: auto;
}
.fixed-table-container table {
@@ -294,4 +294,4 @@ div.fixed-table-scroll-outer {
width: 200px;
height: 150px;
overflow: hidden;
}
}
+1 -2
View File
@@ -44,11 +44,10 @@
.m-signature-pad--body {
position: absolute;
left: 20px;
right: 20px;
top: 20px;
bottom: 60px;
border: 1px solid #f4f4f4;
background-color: white;
}
.m-signature-pad--body
+10 -7
View File
@@ -7,13 +7,6 @@
--text-sub: #BBB;
}
.main-header .navbar, .main-header .logo {
background-color: #18A452;
background: -webkit-linear-gradient(top, #18A452 0%,#18A452 100%);
background: linear-gradient(to bottom, #18A452 0%,#18A452 100%);
border-color: #18A452;
}
a, a:link, a:visited, .btn-primary.hover {
color: var(--header);
}
@@ -108,6 +101,16 @@ input[type=text], input[type=search] {
background-color: var(--back-main);
color: var(--text-main);
}
.main-header .navbar, .main-header .logo {
background-color: var(--header);
background: -webkit-linear-gradient(top, var(--header) 0%,var(--header) 100%);
background: linear-gradient(to bottom, var(--header) 0%,var(--header) 100%);
border-color: var(--header);
}
.modal-content {
background-color: var(--back-main);
color: var(--text-main);
}
.nav-tabs-custom>.nav-tabs>li>a, .nav-tabs-custom>.nav-tabs>li.active>a {
color: var(--text-main);
}
+8 -4
View File
@@ -8,10 +8,14 @@
}
.main-header .navbar, .main-header .logo {
background-color: #FF8C00;
background: -webkit-linear-gradient(top, #FF8C00 0%,#FF8C00 100%);
background: linear-gradient(to bottom, #FF8C00 0%,#FF8C00 100%);
border-color: #FF8C00;
background-color: var(--header);
background: -webkit-linear-gradient(top, var(--header) 0%,var(--header) 100%);
background: linear-gradient(to bottom, var(--header) 0%,var(--header) 100%);
border-color: var(--header);
}
.modal-content {
background-color: var(--back-main);
color: var(--text-main);
}
a, a:link, a:visited, .btn-primary.hover {
+9 -4
View File
@@ -8,10 +8,15 @@
}
.main-header .navbar, .main-header .logo {
background-color: #ad0c0c;
background: -webkit-linear-gradient(top, #ad0c0c 0%,#ad0c0c 100%);
background: linear-gradient(to bottom, #ad0c0c 0%,#ad0c0c 100%);
border-color: #ad0c0c;
background-color: var(--header);
background: -webkit-linear-gradient(top, var(--header) 0%,var(--header) 100%);
background: linear-gradient(to bottom, var(--header) 0%,var(--header) 100%);
border-color: var(--header);
}
.modal-content {
background-color: var(--back-main);
color: var(--text-main);
}
a, a:link, a:visited, .btn-primary.hover {
+26 -26
View File
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 one or more lines are too long
+26 -26
View File
File diff suppressed because one or more lines are too long
+4 -4
View File
@@ -1,14 +1,14 @@
{
"/js/build/vue.js": "/js/build/vue.js?id=1de38b37fbbd0382cab3",
"/js/build/vue.js": "/js/build/vue.js?id=cd8def41b04c6707fc9e",
"/css/AdminLTE.css": "/css/AdminLTE.css?id=b8be19a285eaf44eec37",
"/css/app.css": "/css/app.css?id=407edb63cc6b6dc62405",
"/css/overrides.css": "/css/overrides.css?id=c289c71c08df753ebc45",
"/js/build/vue.js.map": "/js/build/vue.js.map?id=cc8a76b6d73986f89391",
"/js/build/vue.js.map": "/js/build/vue.js.map?id=ae61f2fa91bc184b92a9",
"/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=5fdad90c2d445e4a1a2c",
"/js/dist/all.js": "/js/dist/all.js?id=6769a7c5085ca8147451",
"/js/dist/all.js": "/js/dist/all.js?id=dc00b6ea982000d41b0e",
"/css/build/all.css": "/css/build/all.css?id=5fdad90c2d445e4a1a2c",
"/js/build/all.js": "/js/build/all.js?id=6769a7c5085ca8147451"
"/js/build/all.js": "/js/build/all.js?id=dc00b6ea982000d41b0e"
}
@@ -100,9 +100,7 @@ tr {
{id: 'company', text: 'Company' },
{id: 'checkout_to', text: 'Checked out to' },
{id: 'email', text: 'Email' },
{id: 'first_name', text: 'First Name' },
{id: 'item_name', text: 'Item Name' },
{id: 'last_name', text: 'Last Name' },
{id: 'location', text: 'Location' },
{id: 'maintained', text: 'Maintained' },
{id: 'manufacturer', text: 'Manufacturer' },
@@ -135,8 +133,11 @@ tr {
],
users: [
{id: 'employee_num', text: 'Employee Number' },
{id: 'first_name', text: 'First Name' },
{id: 'jobtitle', text: 'Job Title' },
{id: 'last_name', text: 'Last Name' },
{id: 'phone_number', text: 'Phone Number' },
],
customFields: this.customFields,
},
@@ -150,13 +151,24 @@ tr {
},
computed: {
columns() {
// function to sort objects by their display text.
function sorter(a,b) {
if (a.text < b.text)
return -1;
if (a.text > b.text)
return 1;
return 0;
}
switch(this.options.importType) {
case 'asset':
return this.columnOptions.general.concat(this.columnOptions.assets).concat(this.columnOptions.customFields);
return this.columnOptions.general
.concat(this.columnOptions.assets)
.concat(this.columnOptions.customFields)
.sort(sorter);
case 'license':
return this.columnOptions.general.concat(this.columnOptions.licenses);
return this.columnOptions.general.concat(this.columnOptions.licenses).sort(sorter);
case 'user':
return this.columnOptions.general.concat(this.columnOptions.users);
return this.columnOptions.general.concat(this.columnOptions.users).sort(sorter);
}
return this.columnOptions.general;
},
+3
View File
@@ -39,6 +39,9 @@
'checkin' => 'Checkin',
'checkin_from' => 'Checkin from',
'checkout' => 'Checkout',
'checkouts_count' => 'Checkouts',
'checkins_count' => 'Checkins',
'user_requests_count' => 'Requests',
'city' => 'City',
'click_here' => 'Click here',
'clear_selection' => 'Clear Selection',
+1
View File
@@ -23,6 +23,7 @@ return array(
'Confirm_Asset_Checkin' => 'Confirm Asset Checkin.',
'Confirm_Accessory_Checkin' => 'Confirm Accessory Checkin.',
'Confirm_accessory_delivery' => 'Confirm accessory delivery.',
'Confirm_license_delivery' => 'Confirm license delivery.',
'Confirm_asset_delivery' => 'Confirm asset delivery.',
'Confirm_consumable_delivery' => 'Confirm consumable delivery.',
'current_QTY' => 'Current QTY',
@@ -21,7 +21,7 @@
#eula_div {
width: 100%;
height: 200px;
height: auto;
overflow: scroll;
}
@@ -66,13 +66,13 @@
<h3>Sign below to indicate that you agree to the terms of service:</h3>
<div id="signature-pad" class="m-signature-pad col-md-12 col-sm-12">
<div class="m-signature-pad--body col-md-12 col-sm-12">
<div id="signature-pad" class="m-signature-pad">
<div class="m-signature-pad--body col-md-12 col-sm-12 col-lg-12 col-xs-12">
<canvas></canvas>
<input type="hidden" name="signature_output" id="signature_output">
</div>
<div class="col-md-12 col-sm-12 text-center">
<button type="button" class="btn btn-sm btn-default clear" data-action="clear" id="clear_button">Clear</button>
<div class="col-md-12 col-sm-12 col-lg-12 col-xs-12 text-center">
<button type="button" class="btn btn-sm btn-default clear" data-action="clear" id="clear_button">Clear Signature</button>
</div>
</div>
</div> <!-- .col-md-12.text-center-->
@@ -29,97 +29,40 @@
<div class="tab-pane fade in active" id="assets">
<div class="row">
<div class="col-md-12">
@if ($assets->count() > 0)
<div class="table-responsive">
<table
name="requested-assets"
data-toolbar="#toolbar"
class="table table-striped snipe-table"
id="table"
data-advanced-search="true"
data-id-table="advancedTable"
data-cookie-id-table="requestableAssets">
data-click-to-select="true"
data-cookie-id-table="requestableAssetsListingTable"
data-pagination="true"
data-id-table="requestableAssetsListingTable"
data-search="true"
data-side-pagination="server"
data-show-columns="true"
data-show-export="false"
data-show-footer="false"
data-show-refresh="true"
data-sort-order="asc"
data-sort-name="name"
data-toolbar="#toolbar"
id="assetsListingTable"
class="table table-striped snipe-table"
data-url="{{ route('api.assets.requestable', ['requestable' => true]) }}">
<thead>
<tr role="row">
<th class="col-md-1" data-sortable="true">{{ trans('general.image') }}</th>
<th class="col-md-2" data-sortable="true">{{ trans('admin/hardware/table.asset_model') }}</th>
<th class="col-md-2" data-sortable="true">{{ trans('admin/models/table.modelnumber') }}</th>
@if ($snipeSettings->display_asset_name)
<th class="col-md-2" data-sortable="true">{{ trans('admin/hardware/form.name') }}</th>
@endif
<th class="col-md-3" data-sortable="true">{{ trans('admin/hardware/table.serial') }}</th>
<th class="col-md-2" data-sortable="true">{{ trans('admin/hardware/table.location') }}</th>
<th class="col-md-2" data-sortable="true">{{ trans('admin/hardware/table.status') }}</th>
<th class="col-md-2" data-sortable="true">{{ trans('admin/hardware/form.expected_checkin') }}</th>
<th class="col-md-1 actions" data-sortable="false">{{ trans('table.actions') }}</th>
<tr>
<th class="col-md-1" data-field="image" data-formatter="imageFormatter" data-sortable="true">{{ trans('general.image') }}</th>
<th class="col-md-2" data-field="model" data-sortable="true">{{ trans('admin/hardware/table.asset_model') }}</th>
<th class="col-md-2" data-field="model_number" data-sortable="true">{{ trans('admin/models/table.modelnumber') }}</th>
<th class="col-md-2" data-field="name" data-sortable="true">{{ trans('admin/hardware/form.name') }}</th>
<th class="col-md-3" data-field="serial" data-sortable="true">{{ trans('admin/hardware/table.serial') }}</th>
<th class="col-md-2" data-field="location" data-sortable="true">{{ trans('admin/hardware/table.location') }}</th>
<th class="col-md-2" data-field="status" data-sortable="true">{{ trans('admin/hardware/table.status') }}</th>
<th class="col-md-2" data-field="expected_checkin" data-formatter="dateDisplayFormatter" data-sortable="true">{{ trans('admin/hardware/form.expected_checkin') }}</th>
<th class="col-md-1" data-formatter="assetRequestActionsFormatter" data-field="actions" data-sortable="false">{{ trans('table.actions') }}</th>
</tr>
</thead>
<tbody>
@foreach ($assets as $asset)
<tr>
<td>
@if ($asset->getImageUrl())
<a href="{{ $asset->getImageUrl() }}" data-toggle="lightbox" data-type="image">
<img src="{{ $asset->getImageUrl() }}" style="max-height: {{ $snipeSettings->thumbnail_max_h }}px; width: auto;" class="img-responsive">
</a>
@endif
</td>
<td>{{ $asset->model->name }}
</td>
<td>
{{ $asset->model->model_number }}
</td>
@if ($snipeSettings->display_asset_name)
<td>{{ $asset->name }}</td>
@endif
<td>{{ $asset->serial }}</td>
<td>
@if ($asset->location)
{{ $asset->location->name }}
@endif
</td>
@if ($asset->assigned_to != '' && $asset->assigned_to > 0)
<td>Checked out</td>
@else
<td>{{ trans('admin/hardware/general.requestable') }}</td>
@endif
<td>{{ $asset->expected_checkin }}</td>
<td>
<form action="{{route('account/request-item', ['itemType' => 'asset', 'itemId' => $asset->id])}}" method="POST" accept-charset="utf-8">
{{ csrf_field() }}
@if ($asset->isRequestedBy(Auth::user()))
{{Form::submit(trans('button.cancel'), ['class' => 'btn btn-danger btn-sm'])}}
@else
{{Form::submit(trans('button.request'), ['class' => 'btn btn-primary btn-sm'])}}
@endif
</form>
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
@else
<div class="alert alert-info alert-block">
<i class="fa fa-info-circle"></i>
{{ trans('general.no_results') }}
</div>
@endif
</div>
</div>
</div>
@@ -0,0 +1,54 @@
@extends('layouts/default')
{{-- Page title --}}
@section('title')
Requested Assets
@stop
{{-- Account page content --}}
@section('content')
<div class="row">
<div class="col-md-12">
<div class="box box-default">
<div class="box-body">
<table
data-cookie-id-table="userRequests"
data-pagination="true"
data-id-table="userRequests"
data-side-pagination="server"
data-show-columns="true"
data-show-export="true"
data-show-refresh="true"
data-sort-order="desc"
id="userRequests"
class="table table-striped snipe-table"
data-url="{{ route('api.assets.requested') }}"
data-export-options='{
"fileName": "my-requested-assets-{{ date('Y-m-d') }}",
"ignoreColumn": ["actions","image","change","checkbox","checkincheckout","icon"]
}'>
<thead>
<tr>
<th class="col-md-1" data-field="image" data-formatter="imageFormatter">Image</th>
<th class="col-md-2" data-field="name">Item Name</th>
<th class="col-md-2" data-field="type">Type</th>
<th class="col-md-2" data-field="qty">{{ trans('general.qty') }}</th>
<th class="col-md-2" data-field="location">{{ trans('admin/hardware/table.location') }}</th>
<th class="col-md-2" data-field="expected_checkin" data-formatter="dateDisplayFormatter"> {{ trans('admin/hardware/form.expected_checkin') }}</th>
<th class="col-md-2" data-field="request_date" data-formatter="dateDisplayFormatter">Requested Date</th>
</tr>
</thead>
</table>
</div> <!-- .box-body -->
</div> <!-- .box-default -->
</div> <!-- .col-md-9 -->
</div> <!-- .row-->
@stop
@section('moar_scripts')
@include ('partials.bootstrap-table')
@stop
@@ -266,7 +266,7 @@ View Assets for {{ $user->present()->fullName() }}
data-show-columns="true"
data-show-export="true"
data-show-refresh="true"
data-sort-order="asc"
data-sort-order="desc"
id="userActivityReport"
class="table table-striped snipe-table"
data-url="{{route('api.activity.index', ['target_id' => $user->id, 'target_type' => 'User', 'order' => 'desc']) }}"
@@ -100,7 +100,13 @@
<label for="cost" class="col-md-3 control-label">{{ trans('admin/asset_maintenances/form.cost') }}</label>
<div class="col-md-2">
<div class="input-group">
<span class="input-group-addon">{{ $snipeSettings->default_currency }}</span>
<span class="input-group-addon">
@if (($item->asset) && ($item->asset->location) && ($item->asset->location->currency!=''))
{{ $item->asset->location->currency }}
@else
{{ $snipeSettings->default_currency }}
@endif
</span>
<input class="col-md-2 form-control" type="text" name="cost" id="cost" value="{{ Input::old('cost', \App\Helpers\Helper::formatCurrencyOutput($item->cost)) }}" />
{!! $errors->first('cost', '<span class="alert-msg"><i class="fa fa-times"></i> :message</span>') !!}
</div>
@@ -120,8 +126,9 @@
<div class="box-footer text-right">
<button type="submit" class="btn btn-success"><i class="fa fa-check icon-white"></i> {{ trans('general.save') }}</button>
</div>
</div> <!-- .box-default -->
</form>
</div>
</div>
</div>
@stop
@@ -1,17 +0,0 @@
@extends('emails/layouts/default')
@section('content')
<p>{{ trans('mail.a_user_canceled') }} <a href="{{ url('/') }}"> {{ $snipeSettings->site_name }}</a>. </p>
<p>{{ trans('mail.user') }} <a href="{{ route('users.show', $user_id) }}">{{ $requested_by }}</a><br>
{{ trans('mail.item') }} <a href="{{ $item_url }}">{{ $item_name }}</a> ({{ $item_type }}) <br>
{{ trans('mail.canceled') }} {{ $requested_date }}
</p>
@if ($snipeSettings->show_url_in_emails=='1')
<p><a href="{{ url('/') }}">{{ $snipeSettings->site_name }}</a></p>
@else
<p>{{ $snipeSettings->site_name }}</p>
@endif
@stop
@@ -1,20 +0,0 @@
@extends('emails/layouts/default')
@section('content')
<p>{{ trans('mail.a_user_requested') }} <a href="{{ url('/') }}"> {{ $snipeSettings->site_name }}</a>. </p>
<p>{{ trans('mail.user') }} <a href="{{ route('users.show', $user_id) }}">{{ $requested_by }}</a><br>
{{ trans('mail.item') }} <a href="{{ $item_url }}">{{ $item_name }}</a> ({{ $item_type }}) <br>
{{ trans('general.requested') }} {{ $requested_date }}
@if ($item_quantity > 1)
<br> {{ trans('general.qty') }} {{ $item_quantity}}
@endif
@if ($snipeSettings->show_url_in_emails=='1')
<p><a href="{{ url('/') }}">{{ $snipeSettings->site_name }}</a></p>
@else
<p>{{ $snipeSettings->site_name }}</p>
@endif
@stop
+14 -4
View File
@@ -28,13 +28,22 @@
@if ($requestedItems->count() > 0)
<div class="table-responsive">
<table
name="requested-assets"
name="requestedAssets"
data-toolbar="#toolbar"
class="table table-striped snipe-table"
id="table"
id="requestedAssets"
data-advanced-search="true"
data-id-table="advancedTable"
data-cookie-id-table="requestedAssets">
data-search="true"
data-show-columns="true"
data-show-export="true"
data-pagination="true"
data-id-table="requestedAssets"
data-cookie-id-table="requestedAssets"
data-url="{{ route('api.consumables.index') }}"
data-export-options='{
"fileName": "export-assetrequests-{{ date('Y-m-d') }}",
"ignoreColumn": ["actions","image","change","checkbox","checkincheckout","icon"]
}'>
<thead>
<tr role="row">
<th class="col-md-1">Image</th>
@@ -44,6 +53,7 @@
<th class="col-md-3" data-sortable="true">Requesting User</th>
<th class="col-md-2">Requested Date</th>
<th class="col-md-1"></th>
<th class="col-md-1"></th>
</tr>
</thead>
<tbody>
+23 -1
View File
@@ -25,7 +25,7 @@
@endcan
@endif
@endif
@can('edit', \App\Models\Asset::class)
@can('update', \App\Models\Asset::class)
<li role="presentation"><a href="{{ route('hardware.edit', $asset->id) }}">{{ trans('admin/hardware/general.edit') }}</a></li>
@endcan
@can('create', \App\Models\Asset::class)
@@ -465,6 +465,28 @@
</td>
</tr>
@endif
<tr>
<td>{{ trans('general.checkouts_count') }}</td>
<td>
{{ ($asset->checkouts) ? (int) $asset->checkouts->count() : '0' }}
</td>
</tr>
<tr>
<td>{{ trans('general.checkins_count') }}</td>
<td>
{{ ($asset->checkins) ? (int) $asset->checkins->count() : '0' }}
</td>
</tr>
<tr>
<td>{{ trans('general.user_requests_count') }}</td>
<td>
{{ ($asset->userRequests) ? (int) $asset->userRequests->count() : '0' }}
</td>
</tr>
</tbody>
</table>
</div> <!-- /table-responsive -->
+10
View File
@@ -307,6 +307,16 @@
<i class="fa fa-check fa-fw"></i>
{{ trans('general.viewassets') }}
</a></li>
<li {!! (Request::is('account/requested') ? ' class="active"' : '') !!}>
<a href="{{ route('account.requested') }}">
<i class="fa fa-check fa-disk"></i>
Requested Assets
</a></li>
<li>
<a href="{{ route('profile') }}">
<i class="fa fa-user fa-fw"></i>
@@ -0,0 +1,62 @@
@component('mail::message')
# {{ trans('mail.hello') }},
{{ $intro_text }}.
@if (($snipeSettings->show_images_in_email =='1') && $item->getImageUrl())
<center><img src="{{ $item->getImageUrl() }}" alt="Asset" style="max-width: 570px;"></center>
@endif
@component('mail::table')
| | |
| ------------- | ------------- |
@if (isset($qty))
| **{{ trans('general.qty') }}** | {{ $qty }}
@endif
| **{{ trans('mail.user') }}** | [{{ $requested_by->present()->fullName() }}]({{ route('users.show', $requested_by->id) }}) |
| **{{ trans('general.requested') }}** | {{ $requested_date }} |
@if ((isset($item->asset_tag)) && ($item->asset_tag!=''))
| **{{ trans('mail.asset_tag') }}** | {{ $item->asset_tag }} |
@endif
@if ((isset($item->name)) && ($item->name!=''))
| **{{ trans('mail.asset_name') }}** | {{ $item->name }} |
@endif
@if (isset($item->assetstatus))
| **{{ trans('general.status') }}** | {{ $item->assetstatus->name }}
@endif
@if ($item->assignedTo)
| **Checked out to** | {!! $item->assignedTo->present()->nameUrl() !!} ({{ $item->present()->statusMeta }})
@endif
@if (isset($item->manufacturer))
| **{{ trans('general.manufacturer') }}** | {{ $item->manufacturer->name }} |
@endif
@if (isset($item->model))
| **{{ trans('general.asset_model') }}** | {{ $item->model->name }} |
@endif
@if (isset($item->model_no))
| **{{ trans('general.model_no') }}** | {{ $item->model_no }} |
@endif
@if (isset($item->serial))
| **{{ trans('mail.serial') }}** | {{ $item->serial }} |
@endif
@if ((isset($last_checkout)) && ($last_checkout!=''))
| **Last Checkout** | {{ $last_checkout }} |
@endif
@if ((isset($expected_checkin)) && ($expected_checkin!=''))
| **{{ trans('mail.expecting_checkin_date') }}** | {{ $expected_checkin }} |
@endif
@foreach($fields as $field)
@if (($item->{ $field->db_column_name() }!='') && ($field->show_in_email) && ($field->field_encrypted=='0'))
| **{{ $field->name }}** | {{ $item->{ $field->db_column_name() } }} |
@endif
@endforeach
@if ($note)
| **{{ trans('mail.additional_notes') }}** | {{ $note }} |
@endif
@endcomponent
Thanks,
{{ $snipeSettings->site_name }}
@endcomponent
@@ -10,7 +10,9 @@
@component('mail::table')
| | |
| ------------- | ------------- |
@if ((isset($item->name)) && ($item->name!=''))
| **{{ trans('mail.asset_name') }}** | {{ $item->name }} |
@endif
| **{{ trans('mail.asset_tag') }}** | {{ $item->asset_tag }} |
@if (isset($item->manufacturer))
| **{{ trans('general.manufacturer') }}** | {{ $item->manufacturer->name }} |
@@ -10,7 +10,9 @@
@component('mail::table')
| | |
| ------------- | ------------- |
@if ((isset($item->name)) && ($item->name!=''))
| **{{ trans('mail.asset_name') }}** | {{ $item->name }} |
@endif
| **{{ trans('mail.asset_tag') }}** | {{ $item->asset_tag }} |
@if (isset($item->manufacturer))
| **{{ trans('general.manufacturer') }}** | {{ $item->manufacturer->name }} |
@@ -301,6 +301,17 @@
}
// This is only used by the requestable assets section
function assetRequestActionsFormatter (row, value) {
if (value.available_actions.cancel == true) {
return '<form action="{{ url('/') }}/account/request-asset/'+ value.id + '" method="GET"><button class="btn btn-danger btn-sm" data-tooltip="true" title="Cancel this item request">{{ trans('button.cancel') }}</button></form>';
} else if (value.available_actions.request == true) {
return '<form action="{{ url('/') }}/account/request-asset/'+ value.id + '" method="GET"><button class="btn btn-primary btn-sm" data-tooltip="true" title="Request this item">{{ trans('button.request') }}</button></form>';
}
}
var formatters = [
'hardware',
+45 -15
View File
@@ -118,28 +118,24 @@
<div class="checkbox col-md-12">
<label>
{{ Form::checkbox('location_address', '1', '1', ['class' => 'minimal']) }}
{{ trans('general.address') }}
</label>
</div>
<div class="checkbox col-md-12">
<label>
{{ Form::checkbox('assigned_to', '1', '1', ['class' => 'minimal']) }}
{{ trans('admin/licenses/table.assigned_to') }}
</label>
</div>
<div class="checkbox col-md-12">
<label>
{{ Form::checkbox('username', '1', '1', ['class' => 'minimal']) }}
{{ trans('admin/users/table.username') }}
- {{ trans('general.address') }}
</label>
</div>
<div class="checkbox col-md-12">
<label>
{{ Form::checkbox('employee_num', '1', '1', ['class' => 'minimal']) }}
{{ trans('admin/users/table.employee_num') }}
{{ Form::checkbox('rtd_location', '1', '1', ['class' => 'minimal']) }}
{{ trans('admin/hardware/form.default_location') }}
</label>
</div>
<div class="checkbox col-md-12">
<label>
{{ Form::checkbox('rtd_location_address', '1', '1', ['class' => 'minimal']) }}
- {{ trans('general.address') }}
</label>
</div>
<div class="checkbox col-md-12">
<label>
{{ Form::checkbox('status', '1', '1', ['class' => 'minimal']) }}
@@ -201,6 +197,40 @@
</label>
</div>
<!-- User fields -->
<div class="checkbox col-md-12">
<h4>Checked Out To Fields:</h4>
</div>
<div class="checkbox col-md-12">
<label>
{{ Form::checkbox('assigned_to', '1', '1', ['class' => 'minimal']) }}
{{ trans('admin/licenses/table.assigned_to') }}
</label>
</div>
<div class="checkbox col-md-12">
<label>
{{ Form::checkbox('username', '1', '1', ['class' => 'minimal']) }}
{{ trans('admin/users/table.username') }}
</label>
</div>
<div class="checkbox col-md-12">
<label>
{{ Form::checkbox('employee_num', '1', '1', ['class' => 'minimal']) }}
{{ trans('admin/users/table.employee_num') }}
</label>
</div>
<div class="checkbox col-md-12">
<label>
{{ Form::checkbox('department', '1', '1', ['class' => 'minimal']) }}
{{ trans('general.department') }}
</label>
</div>
@if ($customfields->count() > 0)
<div class="checkbox col-md-12">
<h4>Custom Fields:</h4>
+13 -13
View File
@@ -18,7 +18,7 @@ Create a User ::
<!-- Site Name -->
<div class="row">
<div class="form-group col-lg-12 {{ $errors->has('site_name') ? 'error' : '' }}">
<div class="form-group col-lg-12 required {{ $errors->has('site_name') ? 'error' : '' }}">
{{ Form::label('site_name', trans('general.site_name')) }}
{{ Form::text('site_name', Input::old('site_name'), array('class' => 'form-control','placeholder' => 'Snipe-IT Asset Management')) }}
@@ -29,7 +29,7 @@ Create a User ::
<div class="row">
<!-- Language -->
<div class="form-group col-lg-6 {{$errors->has('default_language') ? 'error' : ''}}">
<div class="form-group col-lg-6{{ (\App\Helpers\Helper::checkIfRequired(\App\Models\User::class, 'default_language')) ? ' required' : '' }} {{$errors->has('default_language') ? 'error' : ''}}">
{{ Form::label('locale', trans('admin/settings/general.default_language')) }}
{!! Form::locales('locale', Input::old('locale', "en"), 'select2') !!}
@@ -37,7 +37,7 @@ Create a User ::
</div>
<!-- Currency -->
<div class="form-group col-lg-6 {{$errors->has('default_currency') ? 'error' : ''}}">
<div class="form-group col-lg-6{{ (\App\Helpers\Helper::checkIfRequired(\App\Models\User::class, 'default_currency')) ? ' required' : '' }} {{$errors->has('default_currency') ? 'error' : ''}}">
{{ Form::label('default_currency', trans('admin/settings/general.default_currency')) }}
{{ Form::text('default_currency', Input::old('default_currency'), array('class' => 'form-control','placeholder' => 'USD', 'maxlength'=>'3', 'style'=>'width: 60px;')) }}
@@ -72,14 +72,14 @@ Create a User ::
<div class="row">
<div class="form-group col-lg-6 {{ $errors->has('auto_increment_prefix') ? 'error' : '' }}">
<div class="form-group col-lg-6{{ (\App\Helpers\Helper::checkIfRequired(\App\Models\User::class, 'auto_increment_prefix')) ? ' required' : '' }} {{ $errors->has('auto_increment_prefix') ? 'error' : '' }}">
{{ Form::label('auto_increment_prefix', trans('admin/settings/general.auto_increment_prefix')) }}
{{ Form::text('auto_increment_prefix', Input::old('auto_increment_prefix'), array('class' => 'form-control')) }}
{!! $errors->first('auto_increment_prefix', '<span class="alert-msg">:message</span>') !!}
</div>
<div class="form-group col-lg-6 {{ $errors->has('zerofill_count') ? 'error' : '' }}">
<div class="form-group col-lg-6{{ (\App\Helpers\Helper::checkIfRequired(\App\Models\User::class, 'zerofill_count')) ? ' required' : '' }} {{ $errors->has('zerofill_count') ? 'error' : '' }}">
{{ Form::label('zerofill_count', trans('admin/settings/general.zerofill_count')) }}
{{ Form::text('zerofill_count', Input::old('zerofill_count', 5), array('class' => 'form-control')) }}
@@ -90,7 +90,7 @@ Create a User ::
<!-- email domain -->
<div class="row">
<div class="form-group col-lg-6 {{ $errors->has('email_domain') ? 'error' : '' }}">
<div class="form-group col-lg-6 required {{ $errors->has('email_domain') ? 'error' : '' }}">
{{ Form::label('email_domain', trans('general.email_domain')) }}
{{ Form::text('email_domain', Input::old('email_domain'), array('class' => 'form-control','placeholder' => 'example.com')) }}
<span class="help-block">{{ trans('general.email_domain_help') }}</span>
@@ -99,7 +99,7 @@ Create a User ::
</div>
<!-- email format -->
<div class="form-group col-lg-6 {{ $errors->has('email_format') ? 'error' : '' }}">
<div class="form-group col-lg-6{{ (\App\Helpers\Helper::checkIfRequired(\App\Models\User::class, 'email_format')) ? ' required' : '' }} {{ $errors->has('email_format') ? 'error' : '' }}">
{{ Form::label('email_format', trans('general.email_format')) }}
{!! Form::username_format('email_format', Input::old('email_format', 'filastname'), 'select2') !!}
{!! $errors->first('email_format', '<span class="alert-msg">:message</span>') !!}
@@ -109,14 +109,14 @@ Create a User ::
<!-- Name -->
<div class="row">
<!-- first name -->
<div class="form-group col-lg-6 {{ $errors->has('first_name') ? 'error' : '' }}">
<div class="form-group col-lg-6{{ (\App\Helpers\Helper::checkIfRequired(\App\Models\User::class, 'first_name')) ? ' required' : '' }} {{ $errors->has('first_name') ? 'error' : '' }}">
{{ Form::label('first_name', trans('general.first_name')) }}
{{ Form::text('first_name', Input::old('first_name'), array('class' => 'form-control','placeholder' => 'Jane')) }}
{!! $errors->first('first_name', '<span class="alert-msg">:message</span>') !!}
</div>
<!-- last name -->
<div class="form-group col-lg-6 {{ $errors->has('last_name') ? 'error' : '' }}">
<div class="form-group col-lg-6 required {{ $errors->has('last_name') ? 'error' : '' }}">
{{ Form::label('last_name', trans('general.last_name')) }}
{{ Form::text('last_name', Input::old('last_name'), array('class' => 'form-control','placeholder' => 'Smith')) }}
{!! $errors->first('last_name', '<span class="alert-msg">:message</span>') !!}
@@ -125,14 +125,14 @@ Create a User ::
<div class="row">
<!-- email-->
<div class="form-group col-lg-6 {{ $errors->has('email') ? 'error' : '' }}">
<div class="form-group col-lg-6{{ (\App\Helpers\Helper::checkIfRequired(\App\Models\User::class, 'email')) ? ' required' : '' }} {{ $errors->has('email') ? 'error' : '' }}">
{{ Form::label('email', trans('admin/users/table.email')) }}
{{ Form::email('email', config('mail.from.address'), array('class' => 'form-control','placeholder' => 'you@example.com')) }}
{!! $errors->first('email', '<span class="alert-msg">:message</span>') !!}
</div>
<!-- username -->
<div class="form-group col-lg-6 {{ $errors->has('username') ? 'error' : '' }}">
<div class="form-group col-lg-6{{ (\App\Helpers\Helper::checkIfRequired(\App\Models\User::class, 'username')) ? ' required' : '' }} {{ $errors->has('username') ? 'error' : '' }}">
{{ Form::label('username', trans('admin/users/table.username')) }}
{{ Form::text('username', Input::old('username'), array('class' => 'form-control','placeholder' => 'jsmith')) }}
{!! $errors->first('username', '<span class="alert-msg">:message</span>') !!}
@@ -141,14 +141,14 @@ Create a User ::
<div class="row">
<!-- password -->
<div class="form-group col-lg-6 {{ $errors->has('password') ? 'error' : '' }}">
<div class="form-group col-lg-6{{ (\App\Helpers\Helper::checkIfRequired(\App\Models\User::class, 'password')) ? ' required' : '' }} {{ $errors->has('password') ? 'error' : '' }}">
{{ Form::label('password', trans('admin/users/table.password')) }}
{{ Form::password('password', array('class' => 'form-control')) }}
{!! $errors->first('password', '<span class="alert-msg">:message</span>') !!}
</div>
<!-- password confirm -->
<div class="form-group col-lg-6 {{ $errors->has('password_confirm') ? 'error' : '' }}">
<div class="form-group col-lg-6{{ (\App\Helpers\Helper::checkIfRequired(\App\Models\User::class, 'password')) ? ' required' : '' }} {{ $errors->has('password_confirm') ? 'error' : '' }}">
{{ Form::label('password_confirmation', trans('admin/users/table.password_confirm')) }}
{{ Form::password('password_confirm', array('class' => 'form-control')) }}
{!! $errors->first('password_confirmation', '<span class="alert-msg">:message</span>') !!}
+18 -1
View File
@@ -16,8 +16,24 @@ use Illuminate\Http\Request;
Route::group(['prefix' => 'v1','namespace' => 'Api'], function () {
/*--- Accessories API ---*/
Route::group(['prefix' => 'account'], function () {
Route::get('requestable/hardware',
[
'as' => 'api.assets.requestable',
'uses' => 'AssetsController@requestable'
]
);
Route::get('requests',
[
'as' => 'api.assets.requested',
'uses' => 'ProfileController@requestedAssets'
]
);
});
/*--- Accessories API ---*/
Route::resource('accessories', 'AccessoriesController',
['names' =>
[
@@ -716,4 +732,5 @@ Route::group(['prefix' => 'v1','namespace' => 'Api'], function () {
);
});
+2
View File
@@ -249,6 +249,8 @@ Route::group([ 'prefix' => 'account', 'middleware' => ['auth']], function () {
# View Assets
Route::get('view-assets', [ 'as' => 'view-assets', 'uses' => 'ViewAssetsController@getIndex' ]);
Route::get('requested', [ 'as' => 'account.requested', 'uses' => 'ViewAssetsController@getRequestedAssets' ]);
# Accept Asset
Route::get(
'accept-asset/{logID}',