Merge branch 'develop'

This commit is contained in:
snipe 2018-01-24 08:25:36 -08:00
commit 7a4bf26733
36 changed files with 369 additions and 104 deletions

View file

@ -856,6 +856,24 @@
"contributions": [ "contributions": [
"code" "code"
] ]
},
{
"login": "CronKz",
"name": "CronKz",
"avatar_url": "https://avatars0.githubusercontent.com/u/34064225?v=4",
"profile": "https://github.com/CronKz",
"contributions": [
"code"
]
},
{
"login": "tdb",
"name": "Tim Bishop",
"avatar_url": "https://avatars1.githubusercontent.com/u/585486?v=4",
"profile": "https://github.com/tdb",
"contributions": [
"code"
]
} }
] ]
} }

View file

@ -1,5 +1,5 @@
[![Build Status](https://travis-ci.org/snipe/snipe-it.svg?branch=develop)](https://travis-ci.org/snipe/snipe-it) [![Stories in Ready](https://badge.waffle.io/snipe/snipe-it.png?label=ready+for+dev&title=Ready+for+development)](http://waffle.io/snipe/snipe-it) [![Maintenance](https://img.shields.io/maintenance/yes/2017.svg)]() [![Crowdin](https://d322cqt584bo4o.cloudfront.net/snipe-it/localized.svg)](https://crowdin.com/project/snipe-it) [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/snipe/snipe-it?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Docker Pulls](https://img.shields.io/docker/pulls/snipe/snipe-it.svg)](https://hub.docker.com/r/snipe/snipe-it/) [![Twitter Follow](https://img.shields.io/twitter/follow/snipeyhead.svg?style=social)](https://twitter.com/snipeyhead) [![Zenhub](https://img.shields.io/badge/Shipping_faster_with-ZenHub-5e60ba.svg)](https://zenhub.io) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/553ce52037fc43ea99149785afcfe641)](https://www.codacy.com/app/snipe/snipe-it?utm_source=github.com&utm_medium=referral&utm_content=snipe/snipe-it&utm_campaign=Badge_Grade) [![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-92-orange.svg?style=flat-square)](#contributors) [![All Contributors](https://img.shields.io/badge/all_contributors-94-orange.svg?style=flat-square)](#contributors)
## Snipe-IT - Open Source Asset Management System ## Snipe-IT - Open Source Asset Management System
@ -69,7 +69,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/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://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://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://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") |
<!-- ALL-CONTRIBUTORS-LIST:END --> <!-- ALL-CONTRIBUTORS-LIST:END -->
This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome! This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome!

View file

@ -16,7 +16,7 @@ class LdapSync extends Command
* *
* @var string * @var string
*/ */
protected $signature = 'snipeit:ldap-sync {--location=} {--location_id=} {--summary} {--json_summary}'; protected $signature = 'snipeit:ldap-sync {--location=} {--location_id=} {--base_dn=} {--summary} {--json_summary}';
/** /**
* The console command description. * The console command description.
@ -67,37 +67,24 @@ class LdapSync extends Command
$summary = array(); $summary = array();
try { try {
$results = Ldap::findLdapUsers(); if ($this->option('base_dn') != '') {
} catch (\Exception $e) { $search_base = $this->option('base_dn');
if ($this->option('json_summary')) { LOG::debug('Importing users from specified base DN: \"'.$search_base.'\".');
} else {
$search_base = null;
}
$results = Ldap::findLdapUsers($search_base);
} catch (\Exception $e) {
if ($this->option('json_summary')) {
$json_summary = [ "error" => true, "error_message" => $e->getMessage(), "summary" => [] ]; $json_summary = [ "error" => true, "error_message" => $e->getMessage(), "summary" => [] ];
$this->info(json_encode($json_summary)); $this->info(json_encode($json_summary));
} }
LOG::error($e); LOG::error($e);
return []; return [];
} }
// Retrieve locations with a mapped OU, and sort them from the shallowest to deepest OU (see #3993)
$ldap_ou_locations = Location::where('ldap_ou', '!=', '')->get()->toArray();
$ldap_ou_lengths = array();
foreach ($ldap_ou_locations as $location) {
$ldap_ou_lengths[] = strlen($location["ldap_ou"]);
}
array_multisort($ldap_ou_lengths, SORT_ASC, $ldap_ou_locations);
if (sizeof($ldap_ou_locations) > 0) {
LOG::debug('Some locations have special OUs set. Locations will be automatically set for users in those OUs.');
}
// Inject location information fields
for ($i = 0; $i < $results["count"]; $i++) {
$results[$i]["ldap_location_override"] = false;
$results[$i]["location_id"] = 0;
}
/* Determine which location to assign users to by default. */
if ($this->option('location')!='') { if ($this->option('location')!='') {
$location = Location::where('name', '=', $this->option('location'))->first(); $location = Location::where('name', '=', $this->option('location'))->first();
LOG::debug('Location name '.$this->option('location').' passed'); LOG::debug('Location name '.$this->option('location').' passed');
@ -107,39 +94,61 @@ class LdapSync extends Command
LOG::debug('Location ID '.$this->option('location_id').' passed'); LOG::debug('Location ID '.$this->option('location_id').' passed');
LOG::debug('Importing to '.$location->name.' ('.$location->id.')'); LOG::debug('Importing to '.$location->name.' ('.$location->id.')');
} else { } else {
$location = NULL; $location = NULL;
} }
if (!isset($location)) { if (!isset($location)) {
LOG::debug('That location is invalid or a location was not provided, so no location will be assigned by default.'); LOG::debug('That location is invalid or a location was not provided, so no location will be assigned by default.');
} }
// Grab subsets based on location-specific DNs, and overwrite location for these users. /* Process locations with explicitly defined OUs, if doing a full import. */
foreach ($ldap_ou_locations as $ldap_loc) { if ($this->option('base_dn')=='') {
$location_users = Ldap::findLdapUsers($ldap_loc["ldap_ou"]); // Retrieve locations with a mapped OU, and sort them from the shallowest to deepest OU (see #3993)
$usernames = array(); $ldap_ou_locations = Location::where('ldap_ou', '!=', '')->get()->toArray();
for ($i = 0; $i < $location_users["count"]; $i++) { $ldap_ou_lengths = array();
$location_users[$i]["ldap_location_override"] = true;
$location_users[$i]["location_id"] = $ldap_loc["id"]; foreach ($ldap_ou_locations as $location) {
$usernames[] = $location_users[$i][$ldap_result_username][0]; $ldap_ou_lengths[] = strlen($location["ldap_ou"]);
} }
// Delete located users from the general group. array_multisort($ldap_ou_lengths, SORT_ASC, $ldap_ou_locations);
foreach ($results as $key => $generic_entry) {
if (in_array($generic_entry[$ldap_result_username][0], $usernames)) { if (sizeof($ldap_ou_locations) > 0) {
unset($results[$key]); LOG::debug('Some locations have special OUs set. Locations will be automatically set for users in those OUs.');
}
// Inject location information fields
for ($i = 0; $i < $results["count"]; $i++) {
$results[$i]["ldap_location_override"] = false;
$results[$i]["location_id"] = 0;
}
// Grab subsets based on location-specific DNs, and overwrite location for these users.
foreach ($ldap_ou_locations as $ldap_loc) {
$location_users = Ldap::findLdapUsers($ldap_loc["ldap_ou"]);
$usernames = array();
for ($i = 0; $i < $location_users["count"]; $i++) {
$location_users[$i]["ldap_location_override"] = true;
$location_users[$i]["location_id"] = $ldap_loc["id"];
$usernames[] = $location_users[$i][$ldap_result_username][0];
} }
}
$global_count = $results['count']; // Delete located users from the general group.
$results = array_merge($location_users, $results); foreach ($results as $key => $generic_entry) {
$results['count'] = $global_count; if (in_array($generic_entry[$ldap_result_username][0], $usernames)) {
unset($results[$key]);
}
}
$global_count = $results['count'];
$results = array_merge($location_users, $results);
$results['count'] = $global_count;
}
} }
/* Create user account entries in Snipe-IT */
$tmp_pass = substr(str_shuffle("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), 0, 20); $tmp_pass = substr(str_shuffle("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), 0, 20);
$pass = bcrypt($tmp_pass); $pass = bcrypt($tmp_pass);
for ($i = 0; $i < $results["count"]; $i++) { for ($i = 0; $i < $results["count"]; $i++) {
if (empty($ldap_result_active_flag) || $results[$i][$ldap_result_active_flag][0] == "TRUE") { if (empty($ldap_result_active_flag) || $results[$i][$ldap_result_active_flag][0] == "TRUE") {
@ -207,9 +216,9 @@ class LdapSync extends Command
if ($this->option('summary')) { if ($this->option('summary')) {
for ($x = 0; $x < count($summary); $x++) { for ($x = 0; $x < count($summary); $x++) {
if ($summary[$x]['status']=='error') { if ($summary[$x]['status']=='error') {
$this->error('ERROR: '.$summary[$x]['firstname'].' '.$summary[$x]['lastname'].' (username: '.$summary[$x]['username'].' was not imported: '.$summary[$x]['note']); $this->error('ERROR: '.$summary[$x]['firstname'].' '.$summary[$x]['lastname'].' (username: '.$summary[$x]['username'].') was not imported: '.$summary[$x]['note']);
} else { } else {
$this->info('User '.$summary[$x]['firstname'].' '.$summary[$x]['lastname'].' (username: '.$summary[$x]['username'].' was '.strtoupper($summary[$x]['createorupdate']).'.'); $this->info('User '.$summary[$x]['firstname'].' '.$summary[$x]['lastname'].' (username: '.$summary[$x]['username'].') was '.strtoupper($summary[$x]['createorupdate']).'.');
} }
} }
} else if ($this->option('json_summary')) { } else if ($this->option('json_summary')) {

View file

@ -125,6 +125,38 @@ class CustomFieldsController extends Controller
} }
public function associate(Request $request, $field_id)
{
$this->authorize('edit', CustomFieldset::class);
$field = CustomField::findOrFail($field_id);
$fieldset_id = $request->input('fieldset_id');
foreach ($field->fieldset as $fieldset) {
if ($fieldset->id == $fieldset_id) {
return response()->json(Helper::formatStandardApiResponse('success', $fieldset, trans('admin/custom_fields/message.fieldset.update.success')));
}
}
$fieldset = CustomFieldset::findOrFail($fieldset_id);
$fieldset->fields()->attach($field->id, ["required" => ($request->input('required') == "on"), "order" => $request->input('order', $fieldset->fields->count())]);
return response()->json(Helper::formatStandardApiResponse('success', $fieldset, trans('admin/custom_fields/message.fieldset.update.success')));
}
public function disassociate(Request $request, $field_id)
{
$this->authorize('edit', CustomFieldset::class);
$field = CustomField::findOrFail($field_id);
$fieldset_id = $request->input('fieldset_id');
foreach ($field->fieldset as $fieldset) {
if ($fieldset->id == $fieldset_id) {
$fieldset->fields()->detach($field->id);
return response()->json(Helper::formatStandardApiResponse('success', $fieldset, trans('admin/custom_fields/message.fieldset.update.success')));
}
}
$fieldset = CustomFieldset::findOrFail($fieldset_id);
return response()->json(Helper::formatStandardApiResponse('success', $fieldset, trans('admin/custom_fields/message.fieldset.update.success')));
}
/** /**
* Delete a custom field. * Delete a custom field.

View file

@ -126,7 +126,7 @@ class CustomFieldsetsController extends Controller
{ {
$this->authorize('delete', CustomFieldset::class); $this->authorize('delete', CustomFieldset::class);
$fieldset = CustomFieldset::findOrFail($id); $fieldset = CustomFieldset::findOrFail($id);
$modelsCount = $fieldset->models->count(); $modelsCount = $fieldset->models->count();
$fieldsCount = $fieldset->fields->count(); $fieldsCount = $fieldset->fields->count();
@ -141,7 +141,23 @@ class CustomFieldsetsController extends Controller
return response()->json(Helper::formatStandardApiResponse('error', null, 'Unspecified error')); return response()->json(Helper::formatStandardApiResponse('error', null, 'Unspecified error'));
}
/**
* Return JSON containing a list of fields belonging to a fieldset.
*
* @author [V. Cordes] [<volker@fdatek.de>]
* @since [v4.1.10]
* @param $fieldsetId
* @return string JSON
*/
public function fields($id)
{
$this->authorize('view', CustomFieldset::class);
$set = CustomFieldset::findOrFail($id);
$fields = $set->fields->get();
return (new CustomFieldsTransformer)->transformCustomFields($fields, $fields->count());
} }
} }

View file

@ -46,7 +46,7 @@ class ReportsController extends Controller
]; ];
$sort = in_array($request->input('sort'), $allowed_columns) ? e($request->input('sort')) : 'created_at'; $sort = in_array($request->input('sort'), $allowed_columns) ? e($request->input('sort')) : 'created_at';
$order = $request->input('order') === 'asc' ? 'asc' : 'desc'; $order = $request->input('order') === 'asc' ? 'desc' : 'asc';
$offset = request('offset', 0); $offset = request('offset', 0);
$limit = request('limit', 50); $limit = request('limit', 50);
$total = $actionlogs->count(); $total = $actionlogs->count();

View file

@ -1088,7 +1088,7 @@ class AssetsController extends Controller
\Log::debug($request->input('ids')); \Log::debug($request->input('ids'));
if (($request->has('ids')) && (count($request->input('ids') > 0))) { if (($request->has('ids')) && (count($request->input('ids')) > 0)) {
$assets = $request->input('ids'); $assets = $request->input('ids');
if (($request->has('purchase_date')) if (($request->has('purchase_date'))
|| ($request->has('purchase_cost')) || ($request->has('purchase_cost'))
@ -1131,7 +1131,13 @@ class AssetsController extends Controller
} }
if ($request->has('rtd_location_id')) { if ($request->has('rtd_location_id')) {
$update_array['rtd_location_id'] = $request->input('rtd_location_id'); $update_array['rtd_location_id'] = $request->input('rtd_location_id');
if (($request->has('update_real_loc'))
&& (($request->input('update_real_loc')) == '1'))
{
$update_array['location_id'] = $request->input('location_id');
}
} }
if ($request->has('status_id')) { if ($request->has('status_id')) {
$update_array['status_id'] = $request->input('status_id'); $update_array['status_id'] = $request->input('status_id');
} }

View file

@ -375,6 +375,8 @@ class SettingsController extends Controller
$setting->brand = $request->input('brand', '1'); $setting->brand = $request->input('brand', '1');
$setting->header_color = $request->input('header_color'); $setting->header_color = $request->input('header_color');
$setting->support_footer = $request->input('support_footer');
$setting->footer_text = $request->input('footer_text');
$setting->show_url_in_emails = $request->input('show_url_in_emails', '0'); $setting->show_url_in_emails = $request->input('show_url_in_emails', '0');

View file

@ -461,7 +461,7 @@ class UsersController extends Controller
public function postBulkEditSave(Request $request) public function postBulkEditSave(Request $request)
{ {
$this->authorize('update', User::class); $this->authorize('update', User::class);
if ((!Input::has('ids')) || (count(Input::has('ids')) == 0)) { if ((!Input::has('ids')) || (count(Input::input('ids')) == 0)) {
return redirect()->back()->with('error', 'No users selected'); return redirect()->back()->with('error', 'No users selected');
} else { } else {

View file

@ -36,13 +36,13 @@ class AssetsTransformer
'id' => (int) $asset->assetstatus->id, 'id' => (int) $asset->assetstatus->id,
'name'=> e($asset->assetstatus->name), 'name'=> e($asset->assetstatus->name),
'status_type'=> e($asset->assetstatus->getStatuslabelType()), 'status_type'=> e($asset->assetstatus->getStatuslabelType()),
'status_meta' => e($asset->present()->statusMeta), 'status_meta' => e($asset->present()->statusMeta),
] : null, ] : null,
'category' => ($asset->model->category) ? [ 'category' => (($asset->model) && ($asset->model->category)) ? [
'id' => (int) $asset->model->category->id, 'id' => (int) $asset->model->category->id,
'name'=> e($asset->model->category->name) 'name'=> e($asset->model->category->name)
] : null, ] : null,
'manufacturer' => ($asset->model->manufacturer) ? [ 'manufacturer' => (($asset->model) && ($asset->model->manufacturer)) ? [
'id' => (int) $asset->model->manufacturer->id, 'id' => (int) $asset->model->manufacturer->id,
'name'=> e($asset->model->manufacturer->name) 'name'=> e($asset->model->manufacturer->name)
] : null, ] : null,

View file

@ -22,6 +22,9 @@ class ItemImporter extends Importer
protected function handle($row) protected function handle($row)
{ {
// Need to reset this between iterations or we'll have stale data.
$this->item = [];
$item_category = $this->findCsvMatch($row, "category"); $item_category = $this->findCsvMatch($row, "category");
if ($this->shouldUpdateField($item_category)) { if ($this->shouldUpdateField($item_category)) {
$this->item["category_id"] = $this->createOrFetchCategory($item_category); $this->item["category_id"] = $this->createOrFetchCategory($item_category);

View file

@ -223,7 +223,7 @@ class Asset extends Depreciable
*/ */
public function components() public function components()
{ {
return $this->belongsToMany('\App\Models\Component', 'components_assets', 'asset_id', 'component_id')->withPivot('id')->withTrashed(); return $this->belongsToMany('\App\Models\Component', 'components_assets', 'asset_id', 'component_id')->withPivot('id', 'assigned_qty')->withTrashed();
} }
/** /**

View file

@ -79,14 +79,11 @@ class Setting extends Model
public static function getDefaultEula() public static function getDefaultEula()
{ {
$Parsedown = new \Parsedown(); $Parsedown = new \Parsedown();
if (Setting::getSettings()->default_eula_text) { if (Setting::getSettings()->default_eula_text) {
return $Parsedown->text(e(Setting::getSettings()->default_eula_text)); return $Parsedown->text(e(Setting::getSettings()->default_eula_text));
} else {
return null;
} }
return null;
} }
/** /**

View file

@ -45,6 +45,7 @@ class User extends SnipeModel implements AuthenticatableContract, CanResetPasswo
'country', 'country',
'zip', 'zip',
'activated', 'activated',
'manager_id',
]; ];
protected $casts = [ protected $casts = [

View file

@ -165,7 +165,7 @@ class AssetPresenter extends Presenter
"searchable" => false, "searchable" => false,
"sortable" => false, "sortable" => false,
"visible" => false, "visible" => false,
"title" => 'Warranty Expires', "title" => trans('admin/hardware/form.warranty_expires'),
"formatter" => "dateDisplayFormatter" "formatter" => "dateDisplayFormatter"
],[ ],[
"field" => "notes", "field" => "notes",
@ -246,11 +246,11 @@ class AssetPresenter extends Presenter
"searchable" => false, "searchable" => false,
"sortable" => false, "sortable" => false,
"switchable" => true, "switchable" => true,
"title" => 'Checkin/Checkout', "title" => trans('general.checkin').'/'.trans('general.checkout'),
"visible" => true, "visible" => true,
"formatter" => "hardwareInOutFormatter", "formatter" => "hardwareInOutFormatter",
]; ];
$layout[] = [ $layout[] = [
"field" => "actions", "field" => "actions",
"searchable" => false, "searchable" => false,
@ -263,7 +263,7 @@ class AssetPresenter extends Presenter
return json_encode($layout); return json_encode($layout);
} }
/** /**
* Generate html link to this items name. * Generate html link to this items name.
@ -325,15 +325,14 @@ class AssetPresenter extends Presenter
**/ **/
public function name() public function name()
{ {
if (empty($this->model->name)) { if (empty($this->model->name)) {
if (isset($this->model->model)) { if (isset($this->model->model)) {
return $this->model->model->name.' ('.$this->model->asset_tag.')'; return $this->model->model->name.' ('.$this->model->asset_tag.')';
} }
return $this->model->asset_tag; return $this->model->asset_tag;
} else {
return $this->model->name . ' (' . $this->model->asset_tag . ')';
} }
return $this->model->name . ' (' . $this->model->asset_tag . ')';
} }
@ -399,7 +398,7 @@ class AssetPresenter extends Presenter
public function statusMeta() public function statusMeta()
{ {
if ($this->model->assigned) { if ($this->model->assigned) {
return strtolower(trans('general.deployed')); return 'deployed';
} }
return $this->model->assetstatus->getStatuslabelType(); return $this->model->assetstatus->getStatuslabelType();
} }
@ -483,4 +482,3 @@ class AssetPresenter extends Presenter
return '<i class="fa fa-barcode"></i>'; return '<i class="fa fa-barcode"></i>';
} }
} }

View file

@ -114,7 +114,7 @@ class ComponentPresenter extends Presenter
"searchable" => false, "searchable" => false,
"sortable" => false, "sortable" => false,
"switchable" => true, "switchable" => true,
"title" => 'Checkin/Checkout', "title" => trans('general.checkin').'/'.trans('general.checkout'),
"visible" => true, "visible" => true,
"formatter" => "componentsInOutFormatter", "formatter" => "componentsInOutFormatter",
]; ];

View file

@ -125,7 +125,7 @@ class LicensePresenter extends Presenter
"searchable" => false, "searchable" => false,
"sortable" => false, "sortable" => false,
"switchable" => true, "switchable" => true,
"title" => 'Checkin/Checkout', "title" => trans('general.checkin').'/'.trans('general.checkout'),
"visible" => true, "visible" => true,
"formatter" => "licensesInOutFormatter", "formatter" => "licensesInOutFormatter",
]; ];

View file

@ -57,7 +57,6 @@ class MigrateAssetLogToActionLog extends Migration
$a->deleted_at = $log->deleted_at; $a->deleted_at = $log->deleted_at;
$a->note = $log->note; $a->note = $log->note;
$a->expected_checkin = $log->expected_checkin; $a->expected_checkin = $log->expected_checkin;
$a->thread_id = $log->thread_id;
$a->accepted_id = $log->accepted_id; $a->accepted_id = $log->accepted_id;
$a->filename = $log->filename; $a->filename = $log->filename;

View file

@ -0,0 +1,34 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class AddFooterSettingsToSettings extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('settings', function (Blueprint $table) {
$table->char('support_footer', 5)->nullable()->default('on');
$table->text('footer_text')->nullable()->default(null);
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('settings', function (Blueprint $table) {
$table->text('support_footer');
$table->text('footer_text');
});
}
}

View file

@ -38,6 +38,7 @@ return array(
'tag' => 'Asset Tag', 'tag' => 'Asset Tag',
'update' => 'Asset Update', 'update' => 'Asset Update',
'warranty' => 'Warranty', 'warranty' => 'Warranty',
'warranty_expires' => 'Warranty Expires',
'years' => 'years', 'years' => 'years',
) )
; ;

View file

@ -40,6 +40,8 @@ return array(
'alt_barcode_type' => '1D barcode type', 'alt_barcode_type' => '1D barcode type',
'eula_settings' => 'EULA Settings', 'eula_settings' => 'EULA Settings',
'eula_markdown' => 'This EULA allows <a href="https://help.github.com/articles/github-flavored-markdown/">Github flavored markdown</a>.', 'eula_markdown' => 'This EULA allows <a href="https://help.github.com/articles/github-flavored-markdown/">Github flavored markdown</a>.',
'footer_text' => 'Additional Footer Text ',
'footer_text_help' => 'This text will appear in the right-side footer. Links are allowed using <a href="https://help.github.com/articles/github-flavored-markdown/">Github flavored markdown</a>. Line breaks, headers, images, etc may result in unpredictable results.',
'general_settings' => 'General Settings', 'general_settings' => 'General Settings',
'generate_backup' => 'Generate Backup', 'generate_backup' => 'Generate Backup',
'header_color' => 'Header Color', 'header_color' => 'Header Color',
@ -71,6 +73,7 @@ return array(
'ldap_active_flag' => 'LDAP Active Flag', 'ldap_active_flag' => 'LDAP Active Flag',
'ldap_emp_num' => 'LDAP Employee Number', 'ldap_emp_num' => 'LDAP Employee Number',
'ldap_email' => 'LDAP Email', 'ldap_email' => 'LDAP Email',
'license' => 'Software License',
'load_remote_text' => 'Remote Scripts', 'load_remote_text' => 'Remote Scripts',
'load_remote_help_text' => 'This Snipe-IT install can load scripts from the outside world.', 'load_remote_help_text' => 'This Snipe-IT install can load scripts from the outside world.',
'login_note' => 'Login Note', 'login_note' => 'Login Note',
@ -103,6 +106,8 @@ return array(
'slack_integration' => 'Slack Settings', 'slack_integration' => 'Slack Settings',
'slack_integration_help' => 'Slack integration is optional, however the endpoint and channel are required if you wish to use it. To configure Slack integration, you must first <a href=":slack_link" target="_new">create an incoming webhook</a> on your Slack account.', 'slack_integration_help' => 'Slack integration is optional, however the endpoint and channel are required if you wish to use it. To configure Slack integration, you must first <a href=":slack_link" target="_new">create an incoming webhook</a> on your Slack account.',
'snipe_version' => 'Snipe-IT version', 'snipe_version' => 'Snipe-IT version',
'support_footer' => 'Support Footer Links ',
'support_footer_help' => 'Specify who sees the links to the Snipe-IT Support info and Users Manual',
'system' => 'System Information', 'system' => 'System Information',
'update' => 'Update Settings', 'update' => 'Update Settings',
'value' => 'Value', 'value' => 'Value',

View file

@ -16,6 +16,7 @@ return array(
'restore_user' => 'Click here to restore them.', 'restore_user' => 'Click here to restore them.',
'last_login' => 'Last Login', 'last_login' => 'Last Login',
'ldap_config_text' => 'LDAP configuration settings can be found Admin > Settings. The (optional) selected location will be set for all imported users.', 'ldap_config_text' => 'LDAP configuration settings can be found Admin > Settings. The (optional) selected location will be set for all imported users.',
'print_assigned' => 'Print All Assigned',
'software_user' => 'Software Checked out to :name', 'software_user' => 'Software Checked out to :name',
'view_user' => 'View User :name', 'view_user' => 'View User :name',
'usercsv' => 'CSV file', 'usercsv' => 'CSV file',

View file

@ -70,6 +70,7 @@
'department' => 'Department', 'department' => 'Department',
'deployed' => 'Deployed', 'deployed' => 'Deployed',
'depreciation_report' => 'Depreciation Report', 'depreciation_report' => 'Depreciation Report',
'details' => 'Details',
'download' => 'Download', 'download' => 'Download',
'depreciation' => 'Depreciation', 'depreciation' => 'Depreciation',
'editprofile' => 'Edit Your Profile', 'editprofile' => 'Edit Your Profile',
@ -82,6 +83,7 @@
'first' => 'First', 'first' => 'First',
'first_name' => 'First Name', 'first_name' => 'First Name',
'first_name_format' => 'First Name (jane@example.com)', 'first_name_format' => 'First Name (jane@example.com)',
'files' => 'Files',
'file_name' => 'File', 'file_name' => 'File',
'file_uploads' => 'File Uploads', 'file_uploads' => 'File Uploads',
'generate' => 'Generate', 'generate' => 'Generate',
@ -118,6 +120,7 @@
'locations' => 'Locations', 'locations' => 'Locations',
'logout' => 'Logout', 'logout' => 'Logout',
'lookup_by_tag' => 'Lookup by Asset Tag', 'lookup_by_tag' => 'Lookup by Asset Tag',
'maintenances' => 'Maintenances',
'manufacturer' => 'Manufacturer', 'manufacturer' => 'Manufacturer',
'manufacturers' => 'Manufacturers', 'manufacturers' => 'Manufacturers',
'markdown' => 'This field allows <a href="https://help.github.com/articles/github-flavored-markdown/">Github flavored markdown</a>.', 'markdown' => 'This field allows <a href="https://help.github.com/articles/github-flavored-markdown/">Github flavored markdown</a>.',

View file

@ -58,7 +58,7 @@
<th data-switchable="false" data-searchable="false" data-sortable="false" data-field="name" data-formatter="hardwareLinkFormatter">{{ trans('general.asset') }}</th> <th data-switchable="false" data-searchable="false" data-sortable="false" data-field="name" data-formatter="hardwareLinkFormatter">{{ trans('general.asset') }}</th>
<th data-switchable="false" data-searchable="false" data-sortable="false" data-field="qty">{{ trans('general.qty') }}</th> <th data-switchable="false" data-searchable="false" data-sortable="false" data-field="qty">{{ trans('general.qty') }}</th>
<th data-switchable="false" data-searchable="false" data-sortable="false" data-field="created_at" data-formatter="dateDisplayFormatter">{{ trans('general.date') }}</th> <th data-switchable="false" data-searchable="false" data-sortable="false" data-field="created_at" data-formatter="dateDisplayFormatter">{{ trans('general.date') }}</th>
<th data-switchable="false" data-searchable="false" data-sortable="false" data-field="checkincheckout" data-formatter="componentsInOutFormatter">Checkin/Checkout</th> <th data-switchable="false" data-searchable="false" data-sortable="false" data-field="checkincheckout" data-formatter="componentsInOutFormatter">{{ trans('general.checkin') }}/{{ trans('general.checkout') }}</th>
</tr> </tr>
</thead> </thead>
</table> </table>

View file

@ -54,8 +54,25 @@
<!-- Default Location --> <!-- Default Location -->
@include ('partials.forms.edit.location-select', ['translated_name' => trans('admin/hardware/form.default_location'), 'fieldname' => 'rtd_location_id']) @include ('partials.forms.edit.location-select', ['translated_name' => trans('admin/hardware/form.default_location'), 'fieldname' => 'rtd_location_id'])
<!-- Update actual location -->
<div class="form-group">
<div class="col-sm-3 control-label">
<!-- Purchase Cost --> </div>
<div class="col-sm-9">
<div class="checkbox">
<label for="activated">
{{ Form::radio('update_real_loc', '', true) }} Update default location AND actual location <br>
{{ Form::radio('update_real_loc', '1', Input::old('activated')) }} Only update default location<br>
</label>
</div>
</div>
</div> <!--/form-group-->
<!-- Purchase Cost -->
<div class="form-group {{ $errors->has('purchase_cost') ? ' has-error' : '' }}"> <div class="form-group {{ $errors->has('purchase_cost') ? ' has-error' : '' }}">
<label for="purchase_cost" class="col-md-3 control-label"> <label for="purchase_cost" class="col-md-3 control-label">
{{ trans('admin/hardware/form.cost') }} {{ trans('admin/hardware/form.cost') }}

View file

@ -53,7 +53,7 @@
<div class="nav-tabs-custom"> <div class="nav-tabs-custom">
<ul class="nav nav-tabs"> <ul class="nav nav-tabs">
<li class="active"> <li class="active">
<a href="#details" data-toggle="tab"><span class="hidden-lg hidden-md"><i class="fa fa-info-circle"></i></span> <span class="hidden-xs hidden-sm">Details</span></a> <a href="#details" data-toggle="tab"><span class="hidden-lg hidden-md"><i class="fa fa-info-circle"></i></span> <span class="hidden-xs hidden-sm">{{ trans('general.details') }}</span></a>
</li> </li>
<li> <li>
<a href="#software" data-toggle="tab"><span class="hidden-lg hidden-md"><i class="fa fa-floppy-o"></i></span> <span class="hidden-xs hidden-sm">{{ trans('general.licenses') }}</span></a> <a href="#software" data-toggle="tab"><span class="hidden-lg hidden-md"><i class="fa fa-floppy-o"></i></span> <span class="hidden-xs hidden-sm">{{ trans('general.licenses') }}</span></a>
@ -65,13 +65,13 @@
<a href="#assets" data-toggle="tab"><span class="hidden-lg hidden-md"><i class="fa fa-barcode"></i></span> <span class="hidden-xs hidden-sm">{{ trans('general.assets') }}</span></a> <a href="#assets" data-toggle="tab"><span class="hidden-lg hidden-md"><i class="fa fa-barcode"></i></span> <span class="hidden-xs hidden-sm">{{ trans('general.assets') }}</span></a>
</li> </li>
<li> <li>
<a href="#maintenances" data-toggle="tab"><span class="hidden-lg hidden-md"><i class="fa fa-wrench"></i></span> <span class="hidden-xs hidden-sm">Maintenances</span></a> <a href="#maintenances" data-toggle="tab"><span class="hidden-lg hidden-md"><i class="fa fa-wrench"></i></span> <span class="hidden-xs hidden-sm">{{ trans('general.maintenances') }}</span></a>
</li> </li>
<li> <li>
<a href="#history" data-toggle="tab"><span class="hidden-lg hidden-md"><i class="fa fa-history"></i></span> <span class="hidden-xs hidden-sm">{{ trans('general.history') }}</span></a> <a href="#history" data-toggle="tab"><span class="hidden-lg hidden-md"><i class="fa fa-history"></i></span> <span class="hidden-xs hidden-sm">{{ trans('general.history') }}</span></a>
</li> </li>
<li> <li>
<a href="#files" data-toggle="tab"><span class="hidden-lg hidden-md"><i class="fa fa-files-o"></i></span> <span class="hidden-xs hidden-sm">Files</span></a> <a href="#files" data-toggle="tab"><span class="hidden-lg hidden-md"><i class="fa fa-files-o"></i></span> <span class="hidden-xs hidden-sm">{{ trans('general.files') }}</span></a>
</li> </li>
<li class="pull-right"> <li class="pull-right">
<!-- <a href="#" data-toggle="modal" data-target="#uploadFileModal"><i class="fa fa-paperclip"></i> </a> --> <!-- <a href="#" data-toggle="modal" data-target="#uploadFileModal"><i class="fa fa-paperclip"></i> </a> -->
@ -542,12 +542,22 @@
<div class="col-md-12"> <div class="col-md-12">
@if(count($asset->components) > 0) @if(count($asset->components) > 0)
<table class="table table-striped"> <table class="table table-striped">
<thead>
<th>{{ trans('general.name') }}</th>
<th>{{ trans('general.qty') }}</th>
<th>{{ trans('general.purchase_cost') }}</th>
</thead>
<tbody> <tbody>
<?php $totalCost = 0; ?> <?php $totalCost = 0; ?>
@foreach ($asset->components as $component) @foreach ($asset->components as $component)
@if (is_null($component->deleted_at)) @if (is_null($component->deleted_at))
<tr> <tr>
<td><a href="{{ route('components.show', $component->id) }}">{{ $component->name }}</a></td> <td>
<a href="{{ route('components.show', $component->id) }}">{{ $component->name }}</a>
</td>
<td>{{ $component->pivot->assigned_qty }}</td>
<td>{{ $component->purchase_cost }}</td>
</tr> </tr>
@endif @endif
@endforeach @endforeach

View file

@ -726,13 +726,25 @@
</div><!-- /.content-wrapper --> </div><!-- /.content-wrapper -->
<footer class="main-footer hidden-print"> <footer class="main-footer hidden-print">
<div class="pull-right hidden-xs"> <div class="pull-right hidden-xs">
<b>Version</b> {{ config('version.app_version') }} - build {{ config('version.build_version') }} ({{ config('version.branch') }}) <b>Version</b> {{ config('version.app_version') }} - build {{ config('version.build_version') }} ({{ config('version.branch') }})
<a target="_blank" class="btn btn-default btn-xs" href="https://snipe-it.readme.io/docs/overview" rel="noopener">User's Manual</a>
<a target="_blank" class="btn btn-default btn-xs" href="https://snipeitapp.com/support/" rel="noopener">Report a Bug</a> @if ($snipeSettings->support_footer!='off')
@if (($snipeSettings->support_footer=='on') || (($snipeSettings->support_footer=='admin') && (Auth::user()->isSuperUser()=='1')))
<a target="_blank" class="btn btn-default btn-xs" href="https://snipe-it.readme.io/docs/overview" rel="noopener">User's Manual</a>
<a target="_blank" class="btn btn-default btn-xs" href="https://snipeitapp.com/support/" rel="noopener">Report a Bug</a>
@endif
@endif
</div> </div>
<a target="_blank" href="https://snipeitapp.com" rel="noopener">Snipe-IT</a> is an open source @if ($snipeSettings->footer_text!='')
project, made with <i class="fa fa-heart" style="color: #a94442; font-size: 10px"></i> by <a href="https://twitter.com/snipeitapp" rel="noopener">@snipeitapp</a> under the <a href="https://www.gnu.org/licenses/agpl-3.0.en.html" rel="noopener">AGPL3 license</a>. <div class="pull-right">
{!! Parsedown::instance()->text(e($snipeSettings->footer_text)) !!}
</div>
@endif
<a target="_blank" href="https://snipeitapp.com" rel="noopener">Snipe-IT</a> is open source software, made with <i class="fa fa-heart" style="color: #a94442; font-size: 10px"></i> by <a href="https://twitter.com/snipeitapp" rel="noopener">@snipeitapp</a>.
</footer> </footer>

View file

@ -58,7 +58,7 @@
<th class="col-md-3" data-formatter="usersLinkObjFormatter" data-field="assigned_user">{{ trans('admin/licenses/general.user') }}</th> <th class="col-md-3" data-formatter="usersLinkObjFormatter" data-field="assigned_user">{{ trans('admin/licenses/general.user') }}</th>
<th class="col-md-3" data-formatter="hardwareLinkObjFormatter" data-field="assigned_asset">{{ trans('admin/licenses/form.asset') }}</th> <th class="col-md-3" data-formatter="hardwareLinkObjFormatter" data-field="assigned_asset">{{ trans('admin/licenses/form.asset') }}</th>
<th class="col-md-3" data-formatter="locationsLinkObjFormatter" data-field="location">{{ trans('general.location') }}</th> <th class="col-md-3" data-formatter="locationsLinkObjFormatter" data-field="location">{{ trans('general.location') }}</th>
<th class="col-md-1" data-searchable="false" data-sortable="false" data-field="checkincheckout" data-formatter="licenseSeatInOutFormatter">Checkin/Checkout</th> <th class="col-md-1" data-searchable="false" data-sortable="false" data-field="checkincheckout" data-formatter="licenseSeatInOutFormatter">{{ trans('general.checkin') }}/{{ trans('general.checkout') }}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>

View file

@ -8,8 +8,10 @@
{{-- Page title --}} {{-- Page title --}}
@section('header_right') @section('header_right')
<a href="{{ route('manufacturers.create') }}" class="btn btn-primary pull-right"> @can('create', \App\Models\Manufacturer::class)
{{ trans('general.create') }}</a> <a href="{{ route('manufacturers.create') }}" class="btn btn-primary pull-right">
{{ trans('general.create') }}</a>
@endcan
@stop @stop
{{-- Page content --}} {{-- Page content --}}

View file

@ -175,19 +175,24 @@
var text_color; var text_color;
var icon_style; var icon_style;
var text_help; var text_help;
var status_meta = {
'deployed': '{{ strtolower(trans('general.deployed')) }}',
'deployable': '{{ strtolower(trans('admin/hardware/general.deployable')) }}',
'pending': '{{ strtolower(trans('general.pending')) }}'
}
switch (value.status_meta) { switch (value.status_meta) {
case '{{ strtolower(trans('general.deployed')) }}': case 'deployed':
text_color = 'blue'; text_color = 'blue';
icon_style = 'fa-circle'; icon_style = 'fa-circle';
text_help = '<label class="label label-default">{{ trans('general.deployed') }}</label>'; text_help = '<label class="label label-default">{{ trans('general.deployed') }}</label>';
break; break;
case '{{ strtolower(trans('admin/hardware/general.deployable')) }}': case 'deployable':
text_color = 'green'; text_color = 'green';
icon_style = 'fa-circle'; icon_style = 'fa-circle';
text_help = ''; text_help = '';
break; break;
case '{{ strtolower(trans('general.pending')) }}': case 'pending':
text_color = 'orange'; text_color = 'orange';
icon_style = 'fa-circle'; icon_style = 'fa-circle';
text_help = ''; text_help = '';
@ -198,7 +203,7 @@
text_help = ''; text_help = '';
} }
return '<nobr><a href="{{ url('/') }}/' + destination + '/' + value.id + '" data-tooltip="true" title="'+ value.status_meta + '"> <i class="fa ' + icon_style + ' text-' + text_color + '"></i> ' + value.name + ' ' + text_help + ' </a> </nobr>'; return '<nobr><a href="{{ url('/') }}/' + destination + '/' + value.id + '" data-tooltip="true" title="'+ status_meta[value.status_meta] + '"> <i class="fa ' + icon_style + ' text-' + text_color + '"></i> ' + value.name + ' ' + text_help + ' </a> </nobr>';
} else if ((value) && (value.name)) { } else if ((value) && (value.name)) {
return '<nobr><a href="{{ url('/') }}/' + destination + '/' + value.id + '"> ' + value.name + '</a></span>'; return '<nobr><a href="{{ url('/') }}/' + destination + '/' + value.id + '"> ' + value.name + '</a></span>';
} }
@ -327,7 +332,7 @@
return '<a href="{{ url('/') }}/' + destination + '/' + row.assigned_pivot_id + '/checkin" class="btn btn-sm bg-purple" data-tooltip="true" title="Check this item in so it is available for re-imaging, re-issue, etc.">{{ trans('general.checkin') }}</a>'; return '<a href="{{ url('/') }}/' + destination + '/' + row.assigned_pivot_id + '/checkin" class="btn btn-sm bg-purple" data-tooltip="true" title="Check this item in so it is available for re-imaging, re-issue, etc.">{{ trans('general.checkin') }}</a>';
} }
} }
} }
@ -525,7 +530,7 @@
}, 0); }, 0);
return total_sum.toFixed(2); return total_sum.toFixed(2);
} }
$(function () { $(function () {
$('#bulkEdit').click(function () { $('#bulkEdit').click(function () {

View file

@ -139,6 +139,42 @@
</div> </div>
<!-- Support Footer -->
<div class="form-group {{ $errors->has('support_footer') ? 'error' : '' }}">
<div class="col-md-3">
{{ Form::label('support_footer', trans('admin/settings/general.support_footer')) }}
</div>
<div class="col-md-9">
@if (config('app.lock_passwords')===true)
{!! Form::select('support_footer', array('on'=>'Enabled','off'=>'Disabled','admin'=>'Superadmin Only'), Input::old('support_footer', $setting->support_footer), ['class' => 'form-control disabled', 'style'=>'width: 150px ;', 'disabled' => 'disabled']) !!}
@else
{!! Form::select('support_footer', array('on'=>'Enabled','off'=>'Disabled','admin'=>'Superadmin Only'), Input::old('support_footer', $setting->support_footer), array('class' => 'form-control', 'style'=>'width: 150px ;')) !!}
@endif
<p class="help-block">{{ trans('admin/settings/general.support_footer_help') }}</p>
{!! $errors->first('support_footer', '<span class="alert-msg">:message</span>') !!}
</div>
</div>
<!-- Additional footer -->
<div class="form-group {{ $errors->has('footer_text') ? 'error' : '' }}">
<div class="col-md-3">
{{ Form::label('custom_css', trans('admin/settings/general.footer_text')) }}
</div>
<div class="col-md-9">
@if (config('app.lock_passwords')===true)
{{ Form::textarea('footer_text', Input::old('footer_text', $setting->footer_text), array('class' => 'form-control', 'rows' => '4', 'placeholder' => 'Optional footer text','disabled'=>'disabled')) }}
<p class="help-block">{{ trans('general.lock_passwords') }}</p>
@else
{{ Form::textarea('footer_text', Input::old('footer_text', $setting->footer_text), array('class' => 'form-control','rows' => '4','placeholder' => 'Optional footer text')) }}
@endif
<p class="help-block">{!! trans('admin/settings/general.footer_text_help') !!}</p>
{!! $errors->first('footer_text', '<span class="alert-msg">:message</span>') !!}
</div>
</div>
</div> </div>

View file

@ -215,6 +215,12 @@
{{ config('version.app_version') }} build {{ config('version.build_version') }} ({{ config('version.hash_version') }}) {{ config('version.app_version') }} build {{ config('version.build_version') }} ({{ config('version.hash_version') }})
</td> </td>
</tr> </tr>
<tr>
<td>{{ trans('admin/settings/general.license') }}</td>
<td>
<a href="https://www.gnu.org/licenses/agpl-3.0.en.html" rel="noopener">AGPL3</a>
</td>
</tr>
<tr> <tr>
<td>{{ trans('admin/settings/general.php') }}</td> <td>{{ trans('admin/settings/general.php') }}</td>
<td> {{ phpversion() }}</td> <td> {{ phpversion() }}</td>
@ -225,6 +231,10 @@
{{ $snipeSettings->lar_ver() }} {{ $snipeSettings->lar_ver() }}
</td> </td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
</div> </div>

View file

@ -63,7 +63,12 @@
{{ Form::label('ldap_integration', trans('admin/settings/general.ldap_integration')) }} {{ Form::label('ldap_integration', trans('admin/settings/general.ldap_integration')) }}
</div> </div>
<div class="col-md-9"> <div class="col-md-9">
{{ Form::checkbox('ldap_enabled', '1', Input::old('ldap_enabled', $setting->ldap_enabled),array('class' => 'minimal')) }} @if (config('app.lock_passwords')===true)
{{ Form::checkbox('ldap_enabled', '1', Input::old('ldap_enabled', $setting->ldap_enabled),['class' => 'minimal disabled', 'disabled' => 'disabled']) }}
@else
{{ Form::checkbox('ldap_enabled', '1', Input::old('ldap_enabled', $setting->ldap_enabled),array('class' => 'minimal')) }}
@endcan
{{ trans('admin/settings/general.ldap_enabled') }} {{ trans('admin/settings/general.ldap_enabled') }}
{!! $errors->first('ldap_enabled', '<span class="alert-msg">:message</span>') !!} {!! $errors->first('ldap_enabled', '<span class="alert-msg">:message</span>') !!}
</div> </div>
@ -75,7 +80,12 @@
{{ Form::label('is_ad', trans('admin/settings/general.ad')) }} {{ Form::label('is_ad', trans('admin/settings/general.ad')) }}
</div> </div>
<div class="col-md-9"> <div class="col-md-9">
{{ Form::checkbox('is_ad', '1', Input::old('is_ad', $setting->is_ad),array('class' => 'minimal')) }} @if (config('app.lock_passwords')===true)
{{ Form::checkbox('is_ad', '1', Input::old('is_ad', $setting->is_ad),['class' => 'minimal disabled', 'disabled' => 'disabled']) }}
@else
{{ Form::checkbox('is_ad', '1', Input::old('is_ad', $setting->is_ad),array('class' => 'minimal')) }}
@endif
{{ trans('admin/settings/general.is_ad') }} {{ trans('admin/settings/general.is_ad') }}
{!! $errors->first('is_ad', '<span class="alert-msg">:message</span>') !!} {!! $errors->first('is_ad', '<span class="alert-msg">:message</span>') !!}
</div> </div>
@ -84,10 +94,16 @@
<!-- LDAP Password Sync --> <!-- LDAP Password Sync -->
<div class="form-group"> <div class="form-group">
<div class="col-md-3"> <div class="col-md-3">
{{ Form::label('is_ad', trans('admin/settings/general.ldap_pw_sync')) }} {{ Form::label('ldap_pw_sync', trans('admin/settings/general.ldap_pw_sync')) }}
</div> </div>
<div class="col-md-9"> <div class="col-md-9">
{{ Form::checkbox('ldap_pw_sync', '1', Input::old('ldap_pw_sync', $setting->ldap_pw_sync),array('class' => 'minimal')) }} @if (config('app.lock_passwords')===true)
{{ Form::checkbox('ldap_pw_sync', '1', Input::old('ldap_pw_sync', $setting->ldap_pw_sync),['class' => 'minimal disabled', 'disabled' => 'disabled']) }}
@else
{{ Form::checkbox('ldap_pw_sync', '1', Input::old('ldap_pw_sync', $setting->ldap_pw_sync),array('class' => 'minimal')) }}
@endif
{{ trans('general.yes') }} {{ trans('general.yes') }}
<p class="help-block">{{ trans('admin/settings/general.ldap_pw_sync_help') }}</p> <p class="help-block">{{ trans('admin/settings/general.ldap_pw_sync_help') }}</p>
{!! $errors->first('ldap_pw_sync', '<span class="alert-msg">:message</span>') !!} {!! $errors->first('ldap_pw_sync', '<span class="alert-msg">:message</span>') !!}
@ -132,7 +148,13 @@
{{ Form::label('ldap_tls', trans('admin/settings/general.ldap_tls')) }} {{ Form::label('ldap_tls', trans('admin/settings/general.ldap_tls')) }}
</div> </div>
<div class="col-md-9"> <div class="col-md-9">
{{ Form::checkbox('ldap_tls', '1', Input::old('ldap_tls', $setting->ldap_tls),array('class' => 'minimal')) }} @if (config('app.lock_passwords')===true)
{{ Form::checkbox('ldap_tls', '1', Input::old('ldap_tls', $setting->ldap_tls),['class' => 'minimal disabled', 'disabled' => 'disabled']) }}
@else
{{ Form::checkbox('ldap_tls', '1', Input::old('ldap_tls', $setting->ldap_tls),array('class' => 'minimal')) }}
@endif
{{ trans('admin/settings/general.ldap_tls_help') }} {{ trans('admin/settings/general.ldap_tls_help') }}
{!! $errors->first('ldap_tls', '<span class="alert-msg">:message</span>') !!} {!! $errors->first('ldap_tls', '<span class="alert-msg">:message</span>') !!}
</div> </div>
@ -144,7 +166,13 @@
{{ Form::label('ldap_server_cert_ignore', trans('admin/settings/general.ldap_server_cert')) }} {{ Form::label('ldap_server_cert_ignore', trans('admin/settings/general.ldap_server_cert')) }}
</div> </div>
<div class="col-md-9"> <div class="col-md-9">
{{ Form::checkbox('ldap_server_cert_ignore', '1', Input::old('ldap_server_cert_ignore', $setting->ldap_server_cert_ignore),array('class' => 'minimal')) }} @if (config('app.lock_passwords')===true)
{{ Form::checkbox('ldap_server_cert_ignore', '1', Input::old('ldap_server_cert_ignore', $setting->ldap_server_cert_ignore),['class' => 'minimal disabled', 'disabled' => 'disabled']) }}
@else
{{ Form::checkbox('ldap_server_cert_ignore', '1', Input::old('ldap_server_cert_ignore', $setting->ldap_server_cert_ignore),array('class' => 'minimal')) }}
@endif
{{ trans('admin/settings/general.ldap_server_cert_ignore') }} {{ trans('admin/settings/general.ldap_server_cert_ignore') }}
{!! $errors->first('ldap_server_cert_ignore', '<span class="alert-msg">:message</span>') !!} {!! $errors->first('ldap_server_cert_ignore', '<span class="alert-msg">:message</span>') !!}
<p class="help-block">{{ trans('admin/settings/general.ldap_server_cert_help') }}</p> <p class="help-block">{{ trans('admin/settings/general.ldap_server_cert_help') }}</p>

View file

@ -51,7 +51,7 @@
<th data-searchable="false" data-sortable="false" data-field="serial">{{ trans('admin/hardware/form.serial') }}</th> <th data-searchable="false" data-sortable="false" data-field="serial">{{ trans('admin/hardware/form.serial') }}</th>
<th data-searchable="false" data-visible="false" data-sortable="true" data-field="category" data-formatter="categoriesLinkObjFormatter">{{ trans('general.category') }}</th> <th data-searchable="false" data-visible="false" data-sortable="true" data-field="category" data-formatter="categoriesLinkObjFormatter">{{ trans('general.category') }}</th>
<th data-field="purchase_cost" data-footer-formatter="sumFormatter">{{ trans('general.purchase_cost') }}</th> <th data-field="purchase_cost" data-footer-formatter="sumFormatter">{{ trans('general.purchase_cost') }}</th>
<th data-searchable="false" data-sortable="false" data-field="checkincheckout" data-formatter="hardwareInOutFormatter">Checkin/Checkout</th> <th data-searchable="false" data-sortable="false" data-field="checkincheckout" data-formatter="hardwareInOutFormatter">{{ trans('general.checkin') }}/{{ trans('general.checkout') }}</th>
<th data-searchable="false" data-sortable="false" data-field="actions" data-formatter="hardwareActionsFormatter">{{ trans('table.actions') }}</th> <th data-searchable="false" data-sortable="false" data-field="actions" data-formatter="hardwareActionsFormatter">{{ trans('table.actions') }}</th>
</tr> </tr>
</thead> </thead>

View file

@ -241,7 +241,7 @@
<a href="{{ route('clone/user', $user->id) }}" style="width: 100%;" class="btn btn-sm btn-default hidden-print">{{ trans('admin/users/general.clone') }}</a> <a href="{{ route('clone/user', $user->id) }}" style="width: 100%;" class="btn btn-sm btn-default hidden-print">{{ trans('admin/users/general.clone') }}</a>
</div> </div>
<div class="col-md-12" style="padding-top: 5px;"> <div class="col-md-12" style="padding-top: 5px;">
<a href="{{ route('users.print', $user->id) }}" style="width: 100%;" class="btn btn-sm btn-default hidden-print">Print All Assigned</a> <a href="{{ route('users.print', $user->id) }}" style="width: 100%;" class="btn btn-sm btn-default hidden-print">{{ trans('admin/users/general.print_assigned') }}</a>
</div> </div>
@can('delete', $user) @can('delete', $user)
@ -478,7 +478,7 @@
<thead> <thead>
<tr> <tr>
<th data-field="icon" style="width: 40px;" class="hidden-xs" data-formatter="iconFormatter"></th> <th data-field="icon" style="width: 40px;" class="hidden-xs" data-formatter="iconFormatter"></th>
<th class="col-sm-3" data-field="created_at" data-formatter="dateDisplayFormatter">{{ trans('general.date') }}</th> <th class="col-sm-3" data-field="created_at" data-formatter="dateDisplayFormatter" data-sortable="true">{{ trans('general.date') }}</th>
<th class="col-sm-2" data-field="admin" data-formatter="usersLinkObjFormatter">{{ trans('general.admin') }}</th> <th class="col-sm-2" data-field="admin" data-formatter="usersLinkObjFormatter">{{ trans('general.admin') }}</th>
<th class="col-sm-2" data-field="action_type">{{ trans('general.action') }}</th> <th class="col-sm-2" data-field="action_type">{{ trans('general.action') }}</th>
<th class="col-sm-3" data-field="item" data-formatter="polymorphicItemFormatter">{{ trans('general.item') }}</th> <th class="col-sm-3" data-field="item" data-formatter="polymorphicItemFormatter">{{ trans('general.item') }}</th>

View file

@ -219,11 +219,32 @@ Route::group(['prefix' => 'v1','namespace' => 'Api'], function () {
'uses' => 'CustomFieldsController@postReorder' 'uses' => 'CustomFieldsController@postReorder'
] ]
); );
Route::post('{field}/associate',
[
'as' => 'api.customfields.associate',
'uses' => 'CustomFieldsController@associate'
]
);
Route::post('{field}/disassociate',
[
'as' => 'api.customfields.disassociate',
'uses' => 'CustomFieldsController@disassociate'
]
);
}); // Fields group }); // Fields group
/*--- Fieldsets API ---*/ /*--- Fieldsets API ---*/
Route::group(['prefix' => 'fieldsets'], function () {
Route::get('{fieldset}/fields',
[
'as' => 'api.fieldsets.fields',
'uses' => 'CustomFieldsetsController@fields'
]
);
});
Route::resource('fieldsets', 'CustomFieldsetsController', Route::resource('fieldsets', 'CustomFieldsetsController',
[ [
'names' => 'names' =>
@ -240,7 +261,6 @@ Route::group(['prefix' => 'v1','namespace' => 'Api'], function () {
); // Custom fieldset resource ); // Custom fieldset resource
/*--- Groups API ---*/ /*--- Groups API ---*/
Route::resource('groups', 'GroupsController', Route::resource('groups', 'GroupsController',