mirror of
https://github.com/snipe/snipe-it.git
synced 2024-12-24 21:24:13 -08:00
Merge branch 'develop' into feature/sc-24120
This commit is contained in:
commit
430f1b0212
|
@ -1,4 +1,4 @@
|
||||||
FROM alpine:3.17.3
|
FROM alpine:3.18.5
|
||||||
# Apache + PHP
|
# Apache + PHP
|
||||||
RUN apk add --no-cache \
|
RUN apk add --no-cache \
|
||||||
apache2 \
|
apache2 \
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
[![Crowdin](https://d322cqt584bo4o.cloudfront.net/snipe-it/localized.svg)](https://crowdin.com/project/snipe-it) [![Docker Pulls](https://img.shields.io/docker/pulls/snipe/snipe-it.svg)](https://hub.docker.com/r/snipe/snipe-it/) [![Twitter Follow](https://img.shields.io/twitter/follow/snipeitapp.svg?style=social)](https://twitter.com/snipeitapp) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/553ce52037fc43ea99149785afcfe641)](https://www.codacy.com/app/snipe/snipe-it?utm_source=github.com&utm_medium=referral&utm_content=snipe/snipe-it&utm_campaign=Badge_Grade)
|
![snipe-it-by-grok](https://github.com/snipe/snipe-it/assets/197404/b515673b-c7c8-4d9a-80f5-9fa58829a602)
|
||||||
[![All Contributors](https://img.shields.io/badge/all_contributors-330-orange.svg?style=flat-square)](#contributors) [![Discord](https://badgen.net/badge/icon/discord?icon=discord&label)](https://discord.gg/yZFtShAcKk) [![huntr](https://cdn.huntr.dev/huntr_security_badge_mono.svg)](https://huntr.dev)
|
|
||||||
|
[![Crowdin](https://d322cqt584bo4o.cloudfront.net/snipe-it/localized.svg)](https://crowdin.com/project/snipe-it) [![Docker Pulls](https://img.shields.io/docker/pulls/snipe/snipe-it.svg)](https://hub.docker.com/r/snipe/snipe-it/) [![Twitter Follow](https://img.shields.io/twitter/follow/snipeitapp.svg?style=social)](https://twitter.com/snipeitapp) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/553ce52037fc43ea99149785afcfe641)](https://www.codacy.com/app/snipe/snipe-it?utm_source=github.com&utm_medium=referral&utm_content=snipe/snipe-it&utm_campaign=Badge_Grade) [![Tests](https://github.com/snipe/snipe-it/actions/workflows/tests.yml/badge.svg)](https://github.com/snipe/snipe-it/actions/workflows/tests.yml)
|
||||||
|
[![All Contributors](https://img.shields.io/badge/all_contributors-330-orange.svg?style=flat-square)](#contributors) [![Discord](https://badgen.net/badge/icon/discord?icon=discord&label)](https://discord.gg/yZFtShAcKk)
|
||||||
|
|
||||||
## Snipe-IT - Open Source Asset Management System
|
## Snipe-IT - Open Source Asset Management System
|
||||||
|
|
||||||
|
|
|
@ -84,35 +84,36 @@ class RestoreFromBackup extends Command
|
||||||
|
|
||||||
|
|
||||||
$private_dirs = [
|
$private_dirs = [
|
||||||
|
'storage/private_uploads/accessories',
|
||||||
|
'storage/private_uploads/assetmodels',
|
||||||
'storage/private_uploads/assets', // these are asset _files_, not the pictures.
|
'storage/private_uploads/assets', // these are asset _files_, not the pictures.
|
||||||
'storage/private_uploads/audits',
|
'storage/private_uploads/audits',
|
||||||
|
'storage/private_uploads/components',
|
||||||
|
'storage/private_uploads/consumables',
|
||||||
|
'storage/private_uploads/eula-pdfs',
|
||||||
'storage/private_uploads/imports',
|
'storage/private_uploads/imports',
|
||||||
'storage/private_uploads/assetmodels',
|
|
||||||
'storage/private_uploads/users',
|
|
||||||
'storage/private_uploads/licenses',
|
'storage/private_uploads/licenses',
|
||||||
'storage/private_uploads/signatures',
|
'storage/private_uploads/signatures',
|
||||||
|
'storage/private_uploads/users',
|
||||||
];
|
];
|
||||||
$private_files = [
|
$private_files = [
|
||||||
'storage/oauth-private.key',
|
'storage/oauth-private.key',
|
||||||
'storage/oauth-public.key',
|
'storage/oauth-public.key',
|
||||||
];
|
];
|
||||||
$public_dirs = [
|
$public_dirs = [
|
||||||
|
'public/uploads/accessories',
|
||||||
|
'public/uploads/assets', // these are asset _pictures_, not asset files
|
||||||
|
'public/uploads/avatars',
|
||||||
|
//'public/uploads/barcodes', // we don't want this, let the barcodes be regenerated
|
||||||
|
'public/uploads/categories',
|
||||||
'public/uploads/companies',
|
'public/uploads/companies',
|
||||||
'public/uploads/components',
|
'public/uploads/components',
|
||||||
'public/uploads/categories',
|
|
||||||
'public/uploads/manufacturers',
|
|
||||||
//'public/uploads/barcodes', // we don't want this, let the barcodes be regenerated
|
|
||||||
'public/uploads/consumables',
|
'public/uploads/consumables',
|
||||||
'public/uploads/departments',
|
'public/uploads/departments',
|
||||||
'public/uploads/avatars',
|
|
||||||
'public/uploads/suppliers',
|
|
||||||
'public/uploads/assets', // these are asset _pictures_, not asset files
|
|
||||||
'public/uploads/locations',
|
'public/uploads/locations',
|
||||||
'public/uploads/accessories',
|
|
||||||
'public/uploads/models',
|
|
||||||
'public/uploads/categories',
|
|
||||||
'public/uploads/avatars',
|
|
||||||
'public/uploads/manufacturers',
|
'public/uploads/manufacturers',
|
||||||
|
'public/uploads/models',
|
||||||
|
'public/uploads/suppliers',
|
||||||
];
|
];
|
||||||
|
|
||||||
$public_files = [
|
$public_files = [
|
||||||
|
|
|
@ -354,7 +354,7 @@ class Helper
|
||||||
|
|
||||||
if ($index >= $total_colors) {
|
if ($index >= $total_colors) {
|
||||||
|
|
||||||
\Log::error('Status label count is '.$index.' and exceeds the allowed count of 266.');
|
\Log::info('Status label count is '.$index.' and exceeds the allowed count of 266.');
|
||||||
//patch fix for array key overflow (color count starts at 1, array starts at 0)
|
//patch fix for array key overflow (color count starts at 1, array starts at 0)
|
||||||
$index = $index - $total_colors - 1;
|
$index = $index - $total_colors - 1;
|
||||||
|
|
||||||
|
|
|
@ -116,41 +116,17 @@ class AssetMaintenancesController extends Controller
|
||||||
{
|
{
|
||||||
$this->authorize('update', Asset::class);
|
$this->authorize('update', Asset::class);
|
||||||
// create a new model instance
|
// create a new model instance
|
||||||
$assetMaintenance = new AssetMaintenance();
|
$maintenance = new AssetMaintenance();
|
||||||
$assetMaintenance->supplier_id = $request->input('supplier_id');
|
$maintenance->fill($request->all());
|
||||||
$assetMaintenance->is_warranty = $request->input('is_warranty');
|
$maintenance->user_id = Auth::id();
|
||||||
$assetMaintenance->cost = $request->input('cost');
|
|
||||||
$assetMaintenance->notes = e($request->input('notes'));
|
|
||||||
$asset = Asset::find(e($request->input('asset_id')));
|
|
||||||
|
|
||||||
if (! Company::isCurrentUserHasAccess($asset)) {
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, 'You cannot add a maintenance for that asset'));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save the asset maintenance data
|
|
||||||
$assetMaintenance->asset_id = $request->input('asset_id');
|
|
||||||
$assetMaintenance->asset_maintenance_type = $request->input('asset_maintenance_type');
|
|
||||||
$assetMaintenance->title = $request->input('title');
|
|
||||||
$assetMaintenance->start_date = $request->input('start_date');
|
|
||||||
$assetMaintenance->completion_date = $request->input('completion_date');
|
|
||||||
$assetMaintenance->user_id = Auth::id();
|
|
||||||
|
|
||||||
if (($assetMaintenance->completion_date !== null)
|
|
||||||
&& ($assetMaintenance->start_date !== '')
|
|
||||||
&& ($assetMaintenance->start_date !== '0000-00-00')
|
|
||||||
) {
|
|
||||||
$startDate = Carbon::parse($assetMaintenance->start_date);
|
|
||||||
$completionDate = Carbon::parse($assetMaintenance->completion_date);
|
|
||||||
$assetMaintenance->asset_maintenance_time = $completionDate->diffInDays($startDate);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Was the asset maintenance created?
|
// Was the asset maintenance created?
|
||||||
if ($assetMaintenance->save()) {
|
if ($maintenance->save()) {
|
||||||
return response()->json(Helper::formatStandardApiResponse('success', $assetMaintenance, trans('admin/asset_maintenances/message.create.success')));
|
return response()->json(Helper::formatStandardApiResponse('success', $maintenance, trans('admin/asset_maintenances/message.create.success')));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, $assetMaintenance->getErrors()));
|
return response()->json(Helper::formatStandardApiResponse('error', null, $maintenance->getErrors()));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,65 +134,39 @@ class AssetMaintenancesController extends Controller
|
||||||
* Validates and stores an update to an asset maintenance
|
* Validates and stores an update to an asset maintenance
|
||||||
*
|
*
|
||||||
* @author A. Gianotto <snipe@snipe.net>
|
* @author A. Gianotto <snipe@snipe.net>
|
||||||
* @param int $assetMaintenanceId
|
* @param int $id
|
||||||
* @param int $request
|
* @param int $request
|
||||||
* @version v1.0
|
* @version v1.0
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
* @return string JSON
|
* @return string JSON
|
||||||
*/
|
*/
|
||||||
public function update(Request $request, $assetMaintenanceId = null)
|
public function update(Request $request, $id)
|
||||||
{
|
{
|
||||||
$this->authorize('update', Asset::class);
|
$this->authorize('update', Asset::class);
|
||||||
// Check if the asset maintenance exists
|
|
||||||
$assetMaintenance = AssetMaintenance::findOrFail($assetMaintenanceId);
|
|
||||||
|
|
||||||
if (! Company::isCurrentUserHasAccess($assetMaintenance->asset)) {
|
if ($maintenance = AssetMaintenance::with('asset')->find($id)) {
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, 'You cannot edit a maintenance for that asset'));
|
|
||||||
}
|
|
||||||
|
|
||||||
$assetMaintenance->supplier_id = e($request->input('supplier_id'));
|
// Can this user manage this asset?
|
||||||
$assetMaintenance->is_warranty = e($request->input('is_warranty'));
|
if (! Company::isCurrentUserHasAccess($maintenance->asset)) {
|
||||||
$assetMaintenance->cost = $request->input('cost');
|
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.action_permission_denied', ['item_type' => trans('admin/asset_maintenances/general.maintenance'), 'id' => $id, 'action' => trans('general.edit')])));
|
||||||
$assetMaintenance->notes = e($request->input('notes'));
|
|
||||||
|
|
||||||
$asset = Asset::find(request('asset_id'));
|
|
||||||
|
|
||||||
if (! Company::isCurrentUserHasAccess($asset)) {
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, 'You cannot edit a maintenance for that asset'));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save the asset maintenance data
|
|
||||||
$assetMaintenance->asset_id = $request->input('asset_id');
|
|
||||||
$assetMaintenance->asset_maintenance_type = $request->input('asset_maintenance_type');
|
|
||||||
$assetMaintenance->title = $request->input('title');
|
|
||||||
$assetMaintenance->start_date = $request->input('start_date');
|
|
||||||
$assetMaintenance->completion_date = $request->input('completion_date');
|
|
||||||
|
|
||||||
if (($assetMaintenance->completion_date == null)
|
|
||||||
) {
|
|
||||||
if (($assetMaintenance->asset_maintenance_time !== 0)
|
|
||||||
|| (! is_null($assetMaintenance->asset_maintenance_time))
|
|
||||||
) {
|
|
||||||
$assetMaintenance->asset_maintenance_time = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The asset this miantenance is attached to is not valid or has been deleted
|
||||||
|
if (!$maintenance->asset) {
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.item_not_found', ['item_type' => trans('general.asset'), 'id' => $id])));
|
||||||
|
}
|
||||||
|
|
||||||
|
$maintenance->fill($request->all());
|
||||||
|
|
||||||
|
if ($maintenance->save()) {
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('success', $maintenance, trans('admin/asset_maintenances/message.edit.success')));
|
||||||
|
}
|
||||||
|
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('error', null, $maintenance->getErrors()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (($assetMaintenance->completion_date !== null)
|
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.item_not_found', ['item_type' => trans('admin/asset_maintenances/general.maintenance'), 'id' => $id])));
|
||||||
&& ($assetMaintenance->start_date !== '')
|
|
||||||
&& ($assetMaintenance->start_date !== '0000-00-00')
|
|
||||||
) {
|
|
||||||
$startDate = Carbon::parse($assetMaintenance->start_date);
|
|
||||||
$completionDate = Carbon::parse($assetMaintenance->completion_date);
|
|
||||||
$assetMaintenance->asset_maintenance_time = $completionDate->diffInDays($startDate);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Was the asset maintenance created?
|
|
||||||
if ($assetMaintenance->save()) {
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('success', $assetMaintenance, trans('admin/asset_maintenances/message.edit.success')));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, $assetMaintenance->getErrors()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -885,13 +885,17 @@ class AssetsController extends Controller
|
||||||
public function checkin(Request $request, $asset_id)
|
public function checkin(Request $request, $asset_id)
|
||||||
{
|
{
|
||||||
$this->authorize('checkin', Asset::class);
|
$this->authorize('checkin', Asset::class);
|
||||||
$asset = Asset::findOrFail($asset_id);
|
$asset = Asset::with('model')->findOrFail($asset_id);
|
||||||
$this->authorize('checkin', $asset);
|
$this->authorize('checkin', $asset);
|
||||||
|
|
||||||
|
|
||||||
$target = $asset->assignedTo;
|
$target = $asset->assignedTo;
|
||||||
if (is_null($target)) {
|
if (is_null($target)) {
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', ['asset'=> e($asset->asset_tag)], trans('admin/hardware/message.checkin.already_checked_in')));
|
return response()->json(Helper::formatStandardApiResponse('error', [
|
||||||
|
'asset_tag'=> e($asset->asset_tag),
|
||||||
|
'model' => e($asset->model->name),
|
||||||
|
'model_number' => e($asset->model->model_number)
|
||||||
|
], trans('admin/hardware/message.checkin.already_checked_in')));
|
||||||
}
|
}
|
||||||
|
|
||||||
$asset->expected_checkin = null;
|
$asset->expected_checkin = null;
|
||||||
|
@ -925,7 +929,11 @@ class AssetsController extends Controller
|
||||||
if ($asset->save()) {
|
if ($asset->save()) {
|
||||||
event(new CheckoutableCheckedIn($asset, $target, Auth::user(), $request->input('note'), $checkin_at, $originalValues));
|
event(new CheckoutableCheckedIn($asset, $target, Auth::user(), $request->input('note'), $checkin_at, $originalValues));
|
||||||
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('success', ['asset'=> e($asset->asset_tag)], trans('admin/hardware/message.checkin.success')));
|
return response()->json(Helper::formatStandardApiResponse('success', [
|
||||||
|
'asset_tag'=> e($asset->asset_tag),
|
||||||
|
'model' => e($asset->model->name),
|
||||||
|
'model_number' => e($asset->model->model_number)
|
||||||
|
], trans('admin/hardware/message.checkin.success')));
|
||||||
}
|
}
|
||||||
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', ['asset'=> e($asset->asset_tag)], trans('admin/hardware/message.checkin.error')));
|
return response()->json(Helper::formatStandardApiResponse('error', ['asset'=> e($asset->asset_tag)], trans('admin/hardware/message.checkin.error')));
|
||||||
|
|
|
@ -353,6 +353,7 @@ class UsersController extends Controller
|
||||||
|
|
||||||
$user = new User;
|
$user = new User;
|
||||||
$user->fill($request->all());
|
$user->fill($request->all());
|
||||||
|
$user->created_by = Auth::user()->id;
|
||||||
|
|
||||||
if ($request->has('permissions')) {
|
if ($request->has('permissions')) {
|
||||||
$permissions_array = $request->input('permissions');
|
$permissions_array = $request->input('permissions');
|
||||||
|
|
|
@ -88,7 +88,7 @@ class AssetModelsController extends Controller
|
||||||
$model->requestable = Request::has('requestable');
|
$model->requestable = Request::has('requestable');
|
||||||
|
|
||||||
if ($request->input('fieldset_id') != '') {
|
if ($request->input('fieldset_id') != '') {
|
||||||
$model->fieldset_id = e($request->input('fieldset_id'));
|
$model->fieldset_id = $request->input('fieldset_id');
|
||||||
}
|
}
|
||||||
|
|
||||||
$model = $request->handleImages($model);
|
$model = $request->handleImages($model);
|
||||||
|
@ -101,7 +101,6 @@ class AssetModelsController extends Controller
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Redirect to the new model page
|
|
||||||
return redirect()->route('models.index')->with('success', trans('admin/models/message.create.success'));
|
return redirect()->route('models.index')->with('success', trans('admin/models/message.create.success'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,17 +165,14 @@ class AssetModelsController extends Controller
|
||||||
|
|
||||||
$this->removeCustomFieldsDefaultValues($model);
|
$this->removeCustomFieldsDefaultValues($model);
|
||||||
|
|
||||||
if ($request->input('fieldset_id') == '') {
|
$model->fieldset_id = $request->input('fieldset_id');
|
||||||
$model->fieldset_id = null;
|
|
||||||
} else {
|
|
||||||
$model->fieldset_id = $request->input('fieldset_id');
|
|
||||||
|
|
||||||
if ($this->shouldAddDefaultValues($request->input())) {
|
if ($this->shouldAddDefaultValues($request->input())) {
|
||||||
if (!$this->assignCustomFieldsDefaultValues($model, $request->input('default_values'))){
|
if (!$this->assignCustomFieldsDefaultValues($model, $request->input('default_values'))){
|
||||||
return redirect()->back()->withInput()->with('error', trans('admin/custom_fields/message.fieldset_default_value.error'));
|
return redirect()->back()->withInput()->with('error', trans('admin/custom_fields/message.fieldset_default_value.error'));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -98,7 +98,7 @@ class AssetCheckoutController extends Controller
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($asset->checkOut($target, $admin, $checkout_at, $expected_checkin, e($request->get('note')), $request->get('name'))) {
|
if ($asset->checkOut($target, $admin, $checkout_at, $expected_checkin, $request->get('note'), $request->get('name'))) {
|
||||||
return redirect()->route('hardware.index')->with('success', trans('admin/hardware/message.checkout.success'));
|
return redirect()->route('hardware.index')->with('success', trans('admin/hardware/message.checkout.success'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,8 @@ use App\Helpers\Helper;
|
||||||
use App\Http\Controllers\CheckInOutRequest;
|
use App\Http\Controllers\CheckInOutRequest;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Models\Asset;
|
use App\Models\Asset;
|
||||||
|
use App\Models\AssetModel;
|
||||||
|
use App\Models\Statuslabel;
|
||||||
use App\Models\Setting;
|
use App\Models\Setting;
|
||||||
use App\View\Label;
|
use App\View\Label;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
@ -23,6 +25,13 @@ class BulkAssetsController extends Controller
|
||||||
/**
|
/**
|
||||||
* Display the bulk edit page.
|
* Display the bulk edit page.
|
||||||
*
|
*
|
||||||
|
* This method is super weird because it's kinda of like a controller within a controller.
|
||||||
|
* It's main function is to determine what the bulk action in, and then return a view with
|
||||||
|
* the information that view needs, be it bulk delete, bulk edit, restore, etc.
|
||||||
|
*
|
||||||
|
* This is something that made sense at the time, but sort of doesn't make sense now. A JS front-end to determine form
|
||||||
|
* action would make a lot more sense here and make things a lot more clear.
|
||||||
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @return View
|
* @return View
|
||||||
* @internal param int $assetId
|
* @internal param int $assetId
|
||||||
|
@ -32,7 +41,10 @@ class BulkAssetsController extends Controller
|
||||||
public function edit(Request $request)
|
public function edit(Request $request)
|
||||||
{
|
{
|
||||||
$this->authorize('view', Asset::class);
|
$this->authorize('view', Asset::class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* No asset IDs were passed
|
||||||
|
*/
|
||||||
if (! $request->filled('ids')) {
|
if (! $request->filled('ids')) {
|
||||||
return redirect()->back()->with('error', trans('admin/hardware/message.update.no_assets_selected'));
|
return redirect()->back()->with('error', trans('admin/hardware/message.update.no_assets_selected'));
|
||||||
}
|
}
|
||||||
|
@ -41,59 +53,52 @@ class BulkAssetsController extends Controller
|
||||||
$bulk_back_url = request()->headers->get('referer');
|
$bulk_back_url = request()->headers->get('referer');
|
||||||
session(['bulk_back_url' => $bulk_back_url]);
|
session(['bulk_back_url' => $bulk_back_url]);
|
||||||
|
|
||||||
$asset_ids = array_values(array_unique($request->input('ids')));
|
|
||||||
|
|
||||||
//custom fields logic
|
|
||||||
$asset_custom_field = Asset::with(['model.fieldset.fields', 'model'])->whereIn('id', $asset_ids)->whereHas('model', function ($query) {
|
|
||||||
return $query->where('fieldset_id', '!=', null);
|
|
||||||
})->get();
|
|
||||||
|
|
||||||
$models = $asset_custom_field->unique('model_id');
|
$asset_ids = $request->input('ids');
|
||||||
|
$assets = Asset::with('assignedTo', 'location', 'model')->find($asset_ids);
|
||||||
|
|
||||||
|
$models = $assets->unique('model_id');
|
||||||
$modelNames = [];
|
$modelNames = [];
|
||||||
foreach($models as $model) {
|
foreach($models as $model) {
|
||||||
$modelNames[] = $model->model->name;
|
$modelNames[] = $model->model->name;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($request->filled('bulk_actions')) {
|
if ($request->filled('bulk_actions')) {
|
||||||
|
|
||||||
|
|
||||||
switch ($request->input('bulk_actions')) {
|
switch ($request->input('bulk_actions')) {
|
||||||
case 'labels':
|
case 'labels':
|
||||||
$this->authorize('view', Asset::class);
|
$this->authorize('view', Asset::class);
|
||||||
$assets_found = Asset::find($asset_ids);
|
|
||||||
|
|
||||||
if ($assets_found->isEmpty()){
|
|
||||||
return redirect()->back();
|
|
||||||
}
|
|
||||||
|
|
||||||
return (new Label)
|
return (new Label)
|
||||||
->with('assets', $assets_found)
|
->with('assets', $assets)
|
||||||
->with('settings', Setting::getSettings())
|
->with('settings', Setting::getSettings())
|
||||||
->with('bulkedit', true)
|
->with('bulkedit', true)
|
||||||
->with('count', 0);
|
->with('count', 0);
|
||||||
|
|
||||||
case 'delete':
|
case 'delete':
|
||||||
$this->authorize('delete', Asset::class);
|
$this->authorize('delete', Asset::class);
|
||||||
$assets = Asset::with('assignedTo', 'location')->find($asset_ids);
|
$assets->each(function ($assets) {
|
||||||
$assets->each(function ($asset) {
|
$this->authorize('delete', $assets);
|
||||||
$this->authorize('delete', $asset);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return view('hardware/bulk-delete')->with('assets', $assets);
|
return view('hardware/bulk-delete')->with('assets', $assets);
|
||||||
|
|
||||||
case 'restore':
|
case 'restore':
|
||||||
$this->authorize('update', Asset::class);
|
$this->authorize('update', Asset::class);
|
||||||
$assets = Asset::withTrashed()->find($asset_ids);
|
$assets = Asset::withTrashed()->find($asset_ids);
|
||||||
$assets->each(function ($asset) {
|
$assets->each(function ($asset) {
|
||||||
$this->authorize('delete', $asset);
|
$this->authorize('delete', $asset);
|
||||||
});
|
});
|
||||||
|
|
||||||
return view('hardware/bulk-restore')->with('assets', $assets);
|
return view('hardware/bulk-restore')->with('assets', $assets);
|
||||||
|
|
||||||
case 'edit':
|
case 'edit':
|
||||||
$this->authorize('update', Asset::class);
|
$this->authorize('update', Asset::class);
|
||||||
|
|
||||||
return view('hardware/bulk')
|
return view('hardware/bulk')
|
||||||
->with('assets', $asset_ids)
|
->with('assets', $asset_ids)
|
||||||
->with('statuslabel_list', Helper::statusLabelList())
|
->with('statuslabel_list', Helper::statusLabelList())
|
||||||
->with('models', $models->pluck(['model']))
|
->with('models', $models->pluck(['model']))
|
||||||
->with('modelNames', $modelNames);
|
->with('modelNames', $modelNames);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -117,25 +122,31 @@ class BulkAssetsController extends Controller
|
||||||
|
|
||||||
// Get the back url from the session and then destroy the session
|
// Get the back url from the session and then destroy the session
|
||||||
$bulk_back_url = route('hardware.index');
|
$bulk_back_url = route('hardware.index');
|
||||||
|
|
||||||
if ($request->session()->has('bulk_back_url')) {
|
if ($request->session()->has('bulk_back_url')) {
|
||||||
$bulk_back_url = $request->session()->pull('bulk_back_url');
|
$bulk_back_url = $request->session()->pull('bulk_back_url');
|
||||||
}
|
}
|
||||||
|
|
||||||
$custom_field_columns = CustomField::all()->pluck('db_column')->toArray();
|
$custom_field_columns = CustomField::all()->pluck('db_column')->toArray();
|
||||||
|
|
||||||
|
|
||||||
if (Session::exists('ids')) {
|
if (! $request->filled('ids') || count($request->input('ids')) == 0) {
|
||||||
$assets = Session::get('ids');
|
|
||||||
} elseif (! $request->filled('ids') || count($request->input('ids')) <= 0) {
|
|
||||||
return redirect($bulk_back_url)->with('error', trans('admin/hardware/message.update.no_assets_selected'));
|
return redirect($bulk_back_url)->with('error', trans('admin/hardware/message.update.no_assets_selected'));
|
||||||
}
|
}
|
||||||
|
|
||||||
$assets = array_keys($request->input('ids'));
|
|
||||||
|
$assets = Asset::whereIn('id', array_keys($request->input('ids')))->get();
|
||||||
if ($request->anyFilled($custom_field_columns)) {
|
|
||||||
$custom_fields_present = true;
|
|
||||||
} else {
|
|
||||||
$custom_fields_present = false;
|
/**
|
||||||
}
|
* If ANY of these are filled, prepare to update the values on the assets.
|
||||||
|
*
|
||||||
|
* Additional checks will be needed for some of them to make sure the values
|
||||||
|
* make sense (for example, changing the status ID to something incompatible with
|
||||||
|
* its checkout status.
|
||||||
|
*/
|
||||||
|
|
||||||
if (($request->filled('purchase_date'))
|
if (($request->filled('purchase_date'))
|
||||||
|| ($request->filled('expected_checkin'))
|
|| ($request->filled('expected_checkin'))
|
||||||
|| ($request->filled('purchase_cost'))
|
|| ($request->filled('purchase_cost'))
|
||||||
|
@ -154,22 +165,32 @@ class BulkAssetsController extends Controller
|
||||||
|| ($request->anyFilled($custom_field_columns))
|
|| ($request->anyFilled($custom_field_columns))
|
||||||
|
|
||||||
) {
|
) {
|
||||||
foreach ($assets as $assetId) {
|
// Let's loop through those assets and build an update array
|
||||||
|
foreach ($assets as $asset) {
|
||||||
|
|
||||||
$this->update_array = [];
|
$this->update_array = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Leave out model_id and status here because we do math on that later. We have to do some extra
|
||||||
|
* validation and checks on those two.
|
||||||
|
*
|
||||||
|
* It's tempting to make these match the request check above, but some of these values require
|
||||||
|
* extra work to make sure the data makes sense.
|
||||||
|
*/
|
||||||
$this->conditionallyAddItem('purchase_date')
|
$this->conditionallyAddItem('purchase_date')
|
||||||
->conditionallyAddItem('expected_checkin')
|
->conditionallyAddItem('expected_checkin')
|
||||||
->conditionallyAddItem('order_number')
|
->conditionallyAddItem('order_number')
|
||||||
->conditionallyAddItem('requestable')
|
->conditionallyAddItem('requestable')
|
||||||
->conditionallyAddItem('status_id')
|
|
||||||
->conditionallyAddItem('supplier_id')
|
->conditionallyAddItem('supplier_id')
|
||||||
->conditionallyAddItem('warranty_months')
|
->conditionallyAddItem('warranty_months')
|
||||||
->conditionallyAddItem('next_audit_date');
|
->conditionallyAddItem('next_audit_date');
|
||||||
foreach ($custom_field_columns as $key => $custom_field_column) {
|
foreach ($custom_field_columns as $key => $custom_field_column) {
|
||||||
$this->conditionallyAddItem($custom_field_column);
|
$this->conditionallyAddItem($custom_field_column);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Blank out fields that were requested to be blanked out via checkbox
|
||||||
|
*/
|
||||||
if ($request->input('null_purchase_date')=='1') {
|
if ($request->input('null_purchase_date')=='1') {
|
||||||
$this->update_array['purchase_date'] = null;
|
$this->update_array['purchase_date'] = null;
|
||||||
}
|
}
|
||||||
|
@ -186,7 +207,6 @@ class BulkAssetsController extends Controller
|
||||||
$this->update_array['purchase_cost'] = $request->input('purchase_cost');
|
$this->update_array['purchase_cost'] = $request->input('purchase_cost');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if ($request->filled('company_id')) {
|
if ($request->filled('company_id')) {
|
||||||
$this->update_array['company_id'] = $request->input('company_id');
|
$this->update_array['company_id'] = $request->input('company_id');
|
||||||
if ($request->input('company_id') == 'clear') {
|
if ($request->input('company_id') == 'clear') {
|
||||||
|
@ -194,88 +214,129 @@ class BulkAssetsController extends Controller
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We're trying to change the model ID - we need to do some extra checks here to make sure
|
||||||
|
* the custom field values work for the custom fieldset rules around this asset. Uniqueness
|
||||||
|
* and requiredness across the fieldset is particularly important, since those are
|
||||||
|
* fieldset-specific attributes.
|
||||||
|
*/
|
||||||
|
if ($request->filled('model_id')) {
|
||||||
|
$this->update_array['model_id'] = AssetModel::find($request->input('model_id'))->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We're trying to change the status ID - we need to do some extra checks here to
|
||||||
|
* make sure the status label type is one that makes sense for the state of the asset,
|
||||||
|
* for example, we shouldn't be able to make an asset archived if it's currently assigned
|
||||||
|
* to someone/something.
|
||||||
|
*/
|
||||||
|
if ($request->filled('status_id')) {
|
||||||
|
$updated_status = Statuslabel::find($request->input('status_id'));
|
||||||
|
|
||||||
|
// We cannot assign a non-deployable status type if the asset is already assigned.
|
||||||
|
// This could probably be added to a form request.
|
||||||
|
// If the asset isn't assigned, we don't care what the status is.
|
||||||
|
// Otherwise we need to make sure the status type is still a deployable one.
|
||||||
|
if (
|
||||||
|
($asset->assigned_to == '')
|
||||||
|
|| ($updated_status->deployable == '1') && ($asset->assetstatus->deployable == '1')
|
||||||
|
) {
|
||||||
|
$this->update_array['status_id'] = $updated_status->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We're changing the location ID - figure out which location we should apply
|
||||||
|
* this change to:
|
||||||
|
*
|
||||||
|
* 0 - RTD location only
|
||||||
|
* 1 - location ID and RTD location ID
|
||||||
|
* 2 - location ID only
|
||||||
|
*
|
||||||
|
* Note: this is kinda dumb and we should just use human-readable values IMHO. - snipe
|
||||||
|
*/
|
||||||
if ($request->filled('rtd_location_id')) {
|
if ($request->filled('rtd_location_id')) {
|
||||||
|
|
||||||
if (($request->filled('update_real_loc')) && (($request->input('update_real_loc')) == '0')) {
|
if (($request->filled('update_real_loc')) && (($request->input('update_real_loc')) == '0')) {
|
||||||
$this->update_array['rtd_location_id'] = $request->input('rtd_location_id');
|
$this->update_array['rtd_location_id'] = $request->input('rtd_location_id');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (($request->filled('update_real_loc')) && (($request->input('update_real_loc')) == '1')) {
|
if (($request->filled('update_real_loc')) && (($request->input('update_real_loc')) == '1')) {
|
||||||
$this->update_array['location_id'] = $request->input('rtd_location_id');
|
$this->update_array['location_id'] = $request->input('rtd_location_id');
|
||||||
$this->update_array['rtd_location_id'] = $request->input('rtd_location_id');
|
$this->update_array['rtd_location_id'] = $request->input('rtd_location_id');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (($request->filled('update_real_loc')) && (($request->input('update_real_loc')) == '2')) {
|
if (($request->filled('update_real_loc')) && (($request->input('update_real_loc')) == '2')) {
|
||||||
$this->update_array['location_id'] = $request->input('rtd_location_id');
|
$this->update_array['location_id'] = $request->input('rtd_location_id');
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ------------------------------------------------------------------------------
|
||||||
|
* ANYTHING that happens past this foreach
|
||||||
|
* WILL NOT BE logged in the edit log_meta data
|
||||||
|
* ------------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
$changed = [];
|
$changed = [];
|
||||||
$asset = Asset::find($assetId);
|
|
||||||
|
|
||||||
foreach ($this->update_array as $key => $value) {
|
foreach ($this->update_array as $key => $value) {
|
||||||
|
|
||||||
if ($this->update_array[$key] != $asset->{$key}) {
|
if ($this->update_array[$key] != $asset->{$key}) {
|
||||||
$changed[$key]['old'] = $asset->{$key};
|
$changed[$key]['old'] = $asset->{$key};
|
||||||
$changed[$key]['new'] = $this->update_array[$key];
|
$changed[$key]['new'] = $this->update_array[$key];
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($custom_fields_present) {
|
|
||||||
|
|
||||||
$model = $asset->model()->first();
|
/**
|
||||||
|
* Start all the custom fields shenanigans
|
||||||
|
*/
|
||||||
|
|
||||||
// Use the rules of the new model fieldsets if the model changed
|
// Does the model have a fieldset?
|
||||||
if ($request->filled('model_id')) {
|
if ($asset->model->fieldset) {
|
||||||
$this->update_array['model_id'] = $request->input('model_id');
|
foreach ($asset->model->fieldset->fields as $field) {
|
||||||
$model = \App\Models\AssetModel::find($request->input('model_id'));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if ((array_key_exists($field->db_column, $this->update_array)) && ($field->field_encrypted == '1')) {
|
||||||
|
$decrypted_old = Helper::gracefulDecrypt($field, $asset->{$field->db_column});
|
||||||
|
|
||||||
// Make sure this model is valid
|
/*
|
||||||
$assetCustomFields = ($model) ? $model->fieldset : null;
|
* Check if the decrypted existing value is different from one we just submitted
|
||||||
|
* and if not, pull it out of the object since it shouldn't really be updating at all.
|
||||||
if ($assetCustomFields && $assetCustomFields->fields) {
|
* If we don't do this, it will try to re-encrypt it, and the same value encrypted two
|
||||||
|
* different times will have different values, so it will *look* like it was updated
|
||||||
foreach ($assetCustomFields->fields as $field) {
|
* but it wasn't.
|
||||||
|
*/
|
||||||
if ((array_key_exists($field->db_column, $this->update_array)) && ($field->field_encrypted=='1')) {
|
if ($decrypted_old != $this->update_array[$field->db_column]) {
|
||||||
$decrypted_old = Helper::gracefulDecrypt($field, $asset->{$field->db_column});
|
$asset->{$field->db_column} = \Crypt::encrypt($this->update_array[$field->db_column]);
|
||||||
|
} else {
|
||||||
/*
|
|
||||||
* Check if the decrypted existing value is different from one we just submitted
|
|
||||||
* and if not, pull it out of the object since it shouldn't really be updating at all.
|
|
||||||
* If we don't do this, it will try to re-encrypt it, and the same value encrypted two
|
|
||||||
* different times will have different values, so it will *look* like it was updated
|
|
||||||
* but it wasn't.
|
|
||||||
*/
|
|
||||||
if ($decrypted_old != $this->update_array[$field->db_column]) {
|
|
||||||
$asset->{$field->db_column} = \Crypt::encrypt($this->update_array[$field->db_column]);
|
|
||||||
} else {
|
|
||||||
/*
|
|
||||||
* Remove the encrypted custom field from the update_array, since nothing changed
|
|
||||||
*/
|
|
||||||
unset($this->update_array[$field->db_column]);
|
|
||||||
unset($asset->{$field->db_column});
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* These custom fields aren't encrypted, just carry on as usual
|
* Remove the encrypted custom field from the update_array, since nothing changed
|
||||||
*/
|
*/
|
||||||
|
unset($this->update_array[$field->db_column]);
|
||||||
|
unset($asset->{$field->db_column});
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* These custom fields aren't encrypted, just carry on as usual
|
||||||
|
*/
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if ((array_key_exists($field->db_column, $this->update_array)) && ($asset->{$field->db_column} != $this->update_array[$field->db_column])) {
|
||||||
|
|
||||||
|
// Check if this is an array, and if so, flatten it
|
||||||
|
if (is_array($this->update_array[$field->db_column])) {
|
||||||
|
$asset->{$field->db_column} = implode(', ', $this->update_array[$field->db_column]);
|
||||||
} else {
|
} else {
|
||||||
|
$asset->{$field->db_column} = $this->update_array[$field->db_column];
|
||||||
|
|
||||||
if ((array_key_exists($field->db_column, $this->update_array)) && ($asset->{$field->db_column} != $this->update_array[$field->db_column])) {
|
|
||||||
|
|
||||||
// Check if this is an array, and if so, flatten it
|
|
||||||
if (is_array($this->update_array[$field->db_column])) {
|
|
||||||
$asset->{$field->db_column} = implode(', ', $this->update_array[$field->db_column]);
|
|
||||||
} else {
|
|
||||||
$asset->{$field->db_column} = $this->update_array[$field->db_column];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // endforeach
|
} // endforeach
|
||||||
} // end custom field check
|
}
|
||||||
} // end custom fields handler
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Check if it passes validation, and then try to save
|
// Check if it passes validation, and then try to save
|
||||||
|
|
|
@ -266,7 +266,7 @@ class Asset extends Depreciable
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines if an asset is available for checkout.
|
* Determines if an asset is available for checkout.
|
||||||
* This checks to see if the it's checked out to an invalid (deleted) user
|
* This checks to see if it's checked out to an invalid (deleted) user
|
||||||
* OR if the assigned_to and deleted_at fields on the asset are empty AND
|
* OR if the assigned_to and deleted_at fields on the asset are empty AND
|
||||||
* that the status is deployable
|
* that the status is deployable
|
||||||
*
|
*
|
||||||
|
@ -753,7 +753,7 @@ class Asset extends Depreciable
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Establishes the asset -> status relationship
|
* Establishes the asset -> license seats relationship
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v4.0]
|
* @since [v4.0]
|
||||||
|
@ -921,6 +921,27 @@ class Asset extends Depreciable
|
||||||
return $cost;
|
return $cost;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* -----------------------------------------------
|
||||||
|
* BEGIN MUTATORS
|
||||||
|
* -----------------------------------------------
|
||||||
|
**/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This sets the requestable to a boolean 0 or 1. This accounts for forms or API calls that
|
||||||
|
* explicitly pass the requestable field but it has a null or empty value.
|
||||||
|
*
|
||||||
|
* This will also correctly parse a 1/0 if "true"/"false" is passed.
|
||||||
|
*
|
||||||
|
* @param $value
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setRequestableAttribute($value)
|
||||||
|
{
|
||||||
|
$this->attributes['requestable'] = (int) filter_var($value, FILTER_VALIDATE_BOOLEAN);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* -----------------------------------------------
|
* -----------------------------------------------
|
||||||
* BEGIN QUERY SCOPES
|
* BEGIN QUERY SCOPES
|
||||||
|
|
|
@ -20,10 +20,9 @@ class AssetMaintenance extends Model implements ICompanyableChild
|
||||||
use SoftDeletes;
|
use SoftDeletes;
|
||||||
use CompanyableChildTrait;
|
use CompanyableChildTrait;
|
||||||
use ValidatingTrait;
|
use ValidatingTrait;
|
||||||
protected $casts = [
|
|
||||||
'start_date' => 'datetime',
|
|
||||||
'completion_date' => 'datetime',
|
|
||||||
];
|
|
||||||
protected $table = 'asset_maintenances';
|
protected $table = 'asset_maintenances';
|
||||||
protected $rules = [
|
protected $rules = [
|
||||||
'asset_id' => 'required|integer',
|
'asset_id' => 'required|integer',
|
||||||
|
@ -31,12 +30,31 @@ class AssetMaintenance extends Model implements ICompanyableChild
|
||||||
'asset_maintenance_type' => 'required',
|
'asset_maintenance_type' => 'required',
|
||||||
'title' => 'required|max:100',
|
'title' => 'required|max:100',
|
||||||
'is_warranty' => 'boolean',
|
'is_warranty' => 'boolean',
|
||||||
'start_date' => 'required|date',
|
'start_date' => 'required|date_format:Y-m-d',
|
||||||
'completion_date' => 'nullable|date',
|
'completion_date' => 'date_format:Y-m-d|nullable',
|
||||||
'notes' => 'string|nullable',
|
'notes' => 'string|nullable',
|
||||||
'cost' => 'numeric|nullable',
|
'cost' => 'numeric|nullable',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The attributes that are mass assignable.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $fillable = [
|
||||||
|
'title',
|
||||||
|
'asset_id',
|
||||||
|
'supplier_id',
|
||||||
|
'asset_maintenance_type',
|
||||||
|
'is_warranty',
|
||||||
|
'start_date',
|
||||||
|
'completion_date',
|
||||||
|
'asset_maintenance_time',
|
||||||
|
'notes',
|
||||||
|
'cost',
|
||||||
|
];
|
||||||
|
|
||||||
use Searchable;
|
use Searchable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -74,12 +74,16 @@
|
||||||
"unicodeveloper/laravel-password": "^1.0",
|
"unicodeveloper/laravel-password": "^1.0",
|
||||||
"watson/validating": "^6.1"
|
"watson/validating": "^6.1"
|
||||||
},
|
},
|
||||||
|
"suggest": {
|
||||||
|
"ext-ldap": "*"
|
||||||
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"brianium/paratest": "^6.6",
|
"brianium/paratest": "^6.6",
|
||||||
"fakerphp/faker": "^1.16",
|
"fakerphp/faker": "^1.16",
|
||||||
"mockery/mockery": "^1.4",
|
"mockery/mockery": "^1.4",
|
||||||
"nunomaduro/larastan": "^1.0",
|
"nunomaduro/larastan": "^1.0",
|
||||||
"nunomaduro/phpinsights": "^2.7",
|
"nunomaduro/phpinsights": "^2.7",
|
||||||
|
"php-mock/php-mock-phpunit": "^2.8",
|
||||||
"phpunit/php-token-stream": "^3.1",
|
"phpunit/php-token-stream": "^3.1",
|
||||||
"phpunit/phpunit": "^9.0",
|
"phpunit/phpunit": "^9.0",
|
||||||
"squizlabs/php_codesniffer": "^3.5",
|
"squizlabs/php_codesniffer": "^3.5",
|
||||||
|
|
224
composer.lock
generated
224
composer.lock
generated
|
@ -4,7 +4,7 @@
|
||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "348f96db24a0f8dfb595ee38b38b34eb",
|
"content-hash": "f4f3b6b02d044ed3e54cdd509b01c3dc",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "alek13/slack",
|
"name": "alek13/slack",
|
||||||
|
@ -7011,16 +7011,16 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpseclib/phpseclib",
|
"name": "phpseclib/phpseclib",
|
||||||
"version": "3.0.14",
|
"version": "3.0.34",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/phpseclib/phpseclib.git",
|
"url": "https://github.com/phpseclib/phpseclib.git",
|
||||||
"reference": "2f0b7af658cbea265cbb4a791d6c29a6613f98ef"
|
"reference": "56c79f16a6ae17e42089c06a2144467acc35348a"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/2f0b7af658cbea265cbb4a791d6c29a6613f98ef",
|
"url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/56c79f16a6ae17e42089c06a2144467acc35348a",
|
||||||
"reference": "2f0b7af658cbea265cbb4a791d6c29a6613f98ef",
|
"reference": "56c79f16a6ae17e42089c06a2144467acc35348a",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -7032,6 +7032,7 @@
|
||||||
"phpunit/phpunit": "*"
|
"phpunit/phpunit": "*"
|
||||||
},
|
},
|
||||||
"suggest": {
|
"suggest": {
|
||||||
|
"ext-dom": "Install the DOM extension to load XML formatted public keys.",
|
||||||
"ext-gmp": "Install the GMP (GNU Multiple Precision) extension in order to speed up arbitrary precision integer arithmetic operations.",
|
"ext-gmp": "Install the GMP (GNU Multiple Precision) extension in order to speed up arbitrary precision integer arithmetic operations.",
|
||||||
"ext-libsodium": "SSH2/SFTP can make use of some algorithms provided by the libsodium-php extension.",
|
"ext-libsodium": "SSH2/SFTP can make use of some algorithms provided by the libsodium-php extension.",
|
||||||
"ext-mcrypt": "Install the Mcrypt extension in order to speed up a few other cryptographic operations.",
|
"ext-mcrypt": "Install the Mcrypt extension in order to speed up a few other cryptographic operations.",
|
||||||
|
@ -7100,7 +7101,7 @@
|
||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/phpseclib/phpseclib/issues",
|
"issues": "https://github.com/phpseclib/phpseclib/issues",
|
||||||
"source": "https://github.com/phpseclib/phpseclib/tree/3.0.14"
|
"source": "https://github.com/phpseclib/phpseclib/tree/3.0.34"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
|
@ -7116,7 +7117,7 @@
|
||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2022-04-04T05:15:45+00:00"
|
"time": "2023-11-27T11:13:31+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpspec/prophecy",
|
"name": "phpspec/prophecy",
|
||||||
|
@ -14100,6 +14101,213 @@
|
||||||
},
|
},
|
||||||
"time": "2022-02-21T01:04:05+00:00"
|
"time": "2022-02-21T01:04:05+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "php-mock/php-mock",
|
||||||
|
"version": "2.4.1",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/php-mock/php-mock.git",
|
||||||
|
"reference": "6240b6f0a76d7b9d1ee4d70e686a7cc711619a9d"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/php-mock/php-mock/zipball/6240b6f0a76d7b9d1ee4d70e686a7cc711619a9d",
|
||||||
|
"reference": "6240b6f0a76d7b9d1ee4d70e686a7cc711619a9d",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": "^5.6 || ^7.0 || ^8.0",
|
||||||
|
"phpunit/php-text-template": "^1 || ^2 || ^3"
|
||||||
|
},
|
||||||
|
"replace": {
|
||||||
|
"malkusch/php-mock": "*"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "^5.7 || ^6.5 || ^7.5 || ^8.0 || ^9.0 || ^10.0",
|
||||||
|
"squizlabs/php_codesniffer": "^3.5"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"php-mock/php-mock-phpunit": "Allows integration into PHPUnit testcase with the trait PHPMock."
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"files": [
|
||||||
|
"autoload.php"
|
||||||
|
],
|
||||||
|
"psr-4": {
|
||||||
|
"phpmock\\": [
|
||||||
|
"classes/",
|
||||||
|
"tests/"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"WTFPL"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Markus Malkusch",
|
||||||
|
"email": "markus@malkusch.de",
|
||||||
|
"homepage": "http://markus.malkusch.de",
|
||||||
|
"role": "Developer"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "PHP-Mock can mock built-in PHP functions (e.g. time()). PHP-Mock relies on PHP's namespace fallback policy. No further extension is needed.",
|
||||||
|
"homepage": "https://github.com/php-mock/php-mock",
|
||||||
|
"keywords": [
|
||||||
|
"BDD",
|
||||||
|
"TDD",
|
||||||
|
"function",
|
||||||
|
"mock",
|
||||||
|
"stub",
|
||||||
|
"test",
|
||||||
|
"test double",
|
||||||
|
"testing"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/php-mock/php-mock/issues",
|
||||||
|
"source": "https://github.com/php-mock/php-mock/tree/2.4.1"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://github.com/michalbundyra",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2023-06-12T20:48:52+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "php-mock/php-mock-integration",
|
||||||
|
"version": "2.2.1",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/php-mock/php-mock-integration.git",
|
||||||
|
"reference": "04f4a8d5442ca457b102b5204673f77323e3edb5"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/php-mock/php-mock-integration/zipball/04f4a8d5442ca457b102b5204673f77323e3edb5",
|
||||||
|
"reference": "04f4a8d5442ca457b102b5204673f77323e3edb5",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=5.6",
|
||||||
|
"php-mock/php-mock": "^2.4",
|
||||||
|
"phpunit/php-text-template": "^1 || ^2 || ^3"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "^5.7.27 || ^6 || ^7 || ^8 || ^9 || ^10"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"phpmock\\integration\\": "classes/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"WTFPL"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Markus Malkusch",
|
||||||
|
"email": "markus@malkusch.de",
|
||||||
|
"homepage": "http://markus.malkusch.de",
|
||||||
|
"role": "Developer"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Integration package for PHP-Mock",
|
||||||
|
"homepage": "https://github.com/php-mock/php-mock-integration",
|
||||||
|
"keywords": [
|
||||||
|
"BDD",
|
||||||
|
"TDD",
|
||||||
|
"function",
|
||||||
|
"mock",
|
||||||
|
"stub",
|
||||||
|
"test",
|
||||||
|
"test double"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/php-mock/php-mock-integration/issues",
|
||||||
|
"source": "https://github.com/php-mock/php-mock-integration/tree/2.2.1"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://github.com/michalbundyra",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2023-02-13T09:51:29+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "php-mock/php-mock-phpunit",
|
||||||
|
"version": "2.8.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/php-mock/php-mock-phpunit.git",
|
||||||
|
"reference": "56edee85ad3232caa0202f98f2a3c899ab16bdb7"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/php-mock/php-mock-phpunit/zipball/56edee85ad3232caa0202f98f2a3c899ab16bdb7",
|
||||||
|
"reference": "56edee85ad3232caa0202f98f2a3c899ab16bdb7",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=7",
|
||||||
|
"php-mock/php-mock-integration": "^2.2.1",
|
||||||
|
"phpunit/phpunit": "^6 || ^7 || ^8 || ^9 || ^10.0.17"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"mockery/mockery": "^1.3.6"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"files": [
|
||||||
|
"autoload.php"
|
||||||
|
],
|
||||||
|
"psr-4": {
|
||||||
|
"phpmock\\phpunit\\": "classes/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"WTFPL"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Markus Malkusch",
|
||||||
|
"email": "markus@malkusch.de",
|
||||||
|
"homepage": "http://markus.malkusch.de",
|
||||||
|
"role": "Developer"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Mock built-in PHP functions (e.g. time()) with PHPUnit. This package relies on PHP's namespace fallback policy. No further extension is needed.",
|
||||||
|
"homepage": "https://github.com/php-mock/php-mock-phpunit",
|
||||||
|
"keywords": [
|
||||||
|
"BDD",
|
||||||
|
"TDD",
|
||||||
|
"function",
|
||||||
|
"mock",
|
||||||
|
"phpunit",
|
||||||
|
"stub",
|
||||||
|
"test",
|
||||||
|
"test double",
|
||||||
|
"testing"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/php-mock/php-mock-phpunit/issues",
|
||||||
|
"source": "https://github.com/php-mock/php-mock-phpunit/tree/2.8.0"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://github.com/michalbundyra",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2023-10-30T07:06:12+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "php-parallel-lint/php-parallel-lint",
|
"name": "php-parallel-lint/php-parallel-lint",
|
||||||
"version": "v1.3.2",
|
"version": "v1.3.2",
|
||||||
|
@ -16600,5 +16808,5 @@
|
||||||
"ext-pdo": "*"
|
"ext-pdo": "*"
|
||||||
},
|
},
|
||||||
"platform-dev": [],
|
"platform-dev": [],
|
||||||
"plugin-api-version": "2.3.0"
|
"plugin-api-version": "2.6.0"
|
||||||
}
|
}
|
||||||
|
|
|
@ -99,10 +99,22 @@ class CustomFieldFactory extends Factory
|
||||||
return [
|
return [
|
||||||
'name' => 'Test Checkbox',
|
'name' => 'Test Checkbox',
|
||||||
'help_text' => 'This is a sample checkbox.',
|
'help_text' => 'This is a sample checkbox.',
|
||||||
'field_values' => "One\nTwo\nThree",
|
'field_values' => "One\r\nTwo\r\nThree",
|
||||||
'element' => 'checkbox',
|
'element' => 'checkbox',
|
||||||
];
|
];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testRadio()
|
||||||
|
{
|
||||||
|
return $this->state(function () {
|
||||||
|
return [
|
||||||
|
'name' => 'Test Radio',
|
||||||
|
'help_text' => 'This is a sample radio.',
|
||||||
|
'field_values' => "One\r\nTwo\r\nThree",
|
||||||
|
'element' => 'radio',
|
||||||
|
];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,6 +35,7 @@ class CustomFieldSeeder extends Seeder
|
||||||
CustomField::factory()->count(1)->macAddress()->create();
|
CustomField::factory()->count(1)->macAddress()->create();
|
||||||
CustomField::factory()->count(1)->testEncrypted()->create();
|
CustomField::factory()->count(1)->testEncrypted()->create();
|
||||||
CustomField::factory()->count(1)->testCheckbox()->create();
|
CustomField::factory()->count(1)->testCheckbox()->create();
|
||||||
|
CustomField::factory()->count(1)->testRadio()->create();
|
||||||
|
|
||||||
|
|
||||||
DB::table('custom_field_custom_fieldset')->insert([
|
DB::table('custom_field_custom_fieldset')->insert([
|
||||||
|
@ -96,6 +97,19 @@ class CustomFieldSeeder extends Seeder
|
||||||
'required' => 0,
|
'required' => 0,
|
||||||
],
|
],
|
||||||
|
|
||||||
|
[
|
||||||
|
'custom_field_id' => '8',
|
||||||
|
'custom_fieldset_id' => '2',
|
||||||
|
'order' => 0,
|
||||||
|
'required' => 0,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'custom_field_id' => '8',
|
||||||
|
'custom_fieldset_id' => '1',
|
||||||
|
'order' => 0,
|
||||||
|
'required' => 0,
|
||||||
|
],
|
||||||
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
"acorn-import-assertions": "^1.9.0",
|
"acorn-import-assertions": "^1.9.0",
|
||||||
"admin-lte": "^2.4.18",
|
"admin-lte": "^2.4.18",
|
||||||
"ajv": "^6.12.6",
|
"ajv": "^6.12.6",
|
||||||
"alpinejs": "^3.13.2",
|
"alpinejs": "^3.13.3",
|
||||||
"blueimp-file-upload": "^9.34.0",
|
"blueimp-file-upload": "^9.34.0",
|
||||||
"bootstrap": "^3.4.1",
|
"bootstrap": "^3.4.1",
|
||||||
"bootstrap-colorpicker": "^2.5.3",
|
"bootstrap-colorpicker": "^2.5.3",
|
||||||
|
|
Binary file not shown.
Binary file not shown.
BIN
public/css/dist/all.css
vendored
BIN
public/css/dist/all.css
vendored
Binary file not shown.
BIN
public/css/dist/skins/skin-black-dark.css
vendored
BIN
public/css/dist/skins/skin-black-dark.css
vendored
Binary file not shown.
BIN
public/css/dist/skins/skin-black-dark.min.css
vendored
BIN
public/css/dist/skins/skin-black-dark.min.css
vendored
Binary file not shown.
|
@ -1,8 +1,8 @@
|
||||||
{
|
{
|
||||||
"/js/build/app.js": "/js/build/app.js?id=41293fc7aa00ece89fd524e1e0e31a68",
|
"/js/build/app.js": "/js/build/app.js?id=41293fc7aa00ece89fd524e1e0e31a68",
|
||||||
"/css/dist/skins/skin-blue.css": "/css/dist/skins/skin-blue.css?id=f677207c6cf9678eb539abecb408c374",
|
"/css/dist/skins/skin-blue.css": "/css/dist/skins/skin-blue.css?id=f677207c6cf9678eb539abecb408c374",
|
||||||
"/css/build/overrides.css": "/css/build/overrides.css?id=1681749b20329c40a052156ea4cb42fe",
|
"/css/build/overrides.css": "/css/build/overrides.css?id=8453824ff928a55d685947c84e6b3079",
|
||||||
"/css/build/app.css": "/css/build/app.css?id=cc0fd2d77504fdd7f03e91e2369d02a9",
|
"/css/build/app.css": "/css/build/app.css?id=ddf74e5777fbad72decf760fe8e57570",
|
||||||
"/css/build/AdminLTE.css": "/css/build/AdminLTE.css?id=dc383f8560a8d4adb51d44fb4043e03b",
|
"/css/build/AdminLTE.css": "/css/build/AdminLTE.css?id=dc383f8560a8d4adb51d44fb4043e03b",
|
||||||
"/css/dist/skins/skin-orange.css": "/css/dist/skins/skin-orange.css?id=6f0563e726c2fe4fab4026daaa5bfdf2",
|
"/css/dist/skins/skin-orange.css": "/css/dist/skins/skin-orange.css?id=6f0563e726c2fe4fab4026daaa5bfdf2",
|
||||||
"/css/dist/skins/skin-orange-dark.css": "/css/dist/skins/skin-orange-dark.css?id=e6e53eef152bba01a4c666a4d8b01117",
|
"/css/dist/skins/skin-orange-dark.css": "/css/dist/skins/skin-orange-dark.css?id=e6e53eef152bba01a4c666a4d8b01117",
|
||||||
|
@ -12,13 +12,13 @@
|
||||||
"/css/dist/skins/skin-purple-dark.css": "/css/dist/skins/skin-purple-dark.css?id=7d92dea45d94be7e1d4e427c728d335d",
|
"/css/dist/skins/skin-purple-dark.css": "/css/dist/skins/skin-purple-dark.css?id=7d92dea45d94be7e1d4e427c728d335d",
|
||||||
"/css/dist/skins/skin-purple.css": "/css/dist/skins/skin-purple.css?id=6fe68325d5356197672c27bc77cedcb4",
|
"/css/dist/skins/skin-purple.css": "/css/dist/skins/skin-purple.css?id=6fe68325d5356197672c27bc77cedcb4",
|
||||||
"/css/dist/skins/skin-red-dark.css": "/css/dist/skins/skin-red-dark.css?id=8ca888bbc050d9680cbb65021382acba",
|
"/css/dist/skins/skin-red-dark.css": "/css/dist/skins/skin-red-dark.css?id=8ca888bbc050d9680cbb65021382acba",
|
||||||
"/css/dist/skins/skin-black-dark.css": "/css/dist/skins/skin-black-dark.css?id=bdfc704731682c67645a2248b0b8d2d7",
|
"/css/dist/skins/skin-black-dark.css": "/css/dist/skins/skin-black-dark.css?id=b061bb141af3bdb6280c6ee772cf8f4f",
|
||||||
"/css/dist/skins/skin-black.css": "/css/dist/skins/skin-black.css?id=76482123f6c70e866d6b971ba91de7bb",
|
"/css/dist/skins/skin-black.css": "/css/dist/skins/skin-black.css?id=76482123f6c70e866d6b971ba91de7bb",
|
||||||
"/css/dist/skins/skin-green-dark.css": "/css/dist/skins/skin-green-dark.css?id=d419cb63a12dc175d71645c876bfc2ab",
|
"/css/dist/skins/skin-green-dark.css": "/css/dist/skins/skin-green-dark.css?id=d419cb63a12dc175d71645c876bfc2ab",
|
||||||
"/css/dist/skins/skin-green.css": "/css/dist/skins/skin-green.css?id=0a82a6ae6bb4e58fe62d162c4fb50397",
|
"/css/dist/skins/skin-green.css": "/css/dist/skins/skin-green.css?id=0a82a6ae6bb4e58fe62d162c4fb50397",
|
||||||
"/css/dist/skins/skin-contrast.css": "/css/dist/skins/skin-contrast.css?id=da6c7997d9de2f8329142399f0ce50da",
|
"/css/dist/skins/skin-contrast.css": "/css/dist/skins/skin-contrast.css?id=da6c7997d9de2f8329142399f0ce50da",
|
||||||
"/css/dist/skins/skin-red.css": "/css/dist/skins/skin-red.css?id=44bf834f2110504a793dadec132a5898",
|
"/css/dist/skins/skin-red.css": "/css/dist/skins/skin-red.css?id=44bf834f2110504a793dadec132a5898",
|
||||||
"/css/dist/all.css": "/css/dist/all.css?id=391b67f142742a6b11a92b042c6d475c",
|
"/css/dist/all.css": "/css/dist/all.css?id=5fa237d9baa78a00f78c75819cd794e6",
|
||||||
"/css/dist/signature-pad.css": "/css/dist/signature-pad.css?id=6a89d3cd901305e66ced1cf5f13147f7",
|
"/css/dist/signature-pad.css": "/css/dist/signature-pad.css?id=6a89d3cd901305e66ced1cf5f13147f7",
|
||||||
"/css/dist/signature-pad.min.css": "/css/dist/signature-pad.min.css?id=6a89d3cd901305e66ced1cf5f13147f7",
|
"/css/dist/signature-pad.min.css": "/css/dist/signature-pad.min.css?id=6a89d3cd901305e66ced1cf5f13147f7",
|
||||||
"/css/webfonts/fa-brands-400.ttf": "/css/webfonts/fa-brands-400.ttf?id=a656b2d865fe379d8851757e8e4001ef",
|
"/css/webfonts/fa-brands-400.ttf": "/css/webfonts/fa-brands-400.ttf?id=a656b2d865fe379d8851757e8e4001ef",
|
||||||
|
@ -37,7 +37,7 @@
|
||||||
"/css/dist/skins/skin-green.min.css": "/css/dist/skins/skin-green.min.css?id=0a82a6ae6bb4e58fe62d162c4fb50397",
|
"/css/dist/skins/skin-green.min.css": "/css/dist/skins/skin-green.min.css?id=0a82a6ae6bb4e58fe62d162c4fb50397",
|
||||||
"/css/dist/skins/skin-green-dark.min.css": "/css/dist/skins/skin-green-dark.min.css?id=d419cb63a12dc175d71645c876bfc2ab",
|
"/css/dist/skins/skin-green-dark.min.css": "/css/dist/skins/skin-green-dark.min.css?id=d419cb63a12dc175d71645c876bfc2ab",
|
||||||
"/css/dist/skins/skin-black.min.css": "/css/dist/skins/skin-black.min.css?id=76482123f6c70e866d6b971ba91de7bb",
|
"/css/dist/skins/skin-black.min.css": "/css/dist/skins/skin-black.min.css?id=76482123f6c70e866d6b971ba91de7bb",
|
||||||
"/css/dist/skins/skin-black-dark.min.css": "/css/dist/skins/skin-black-dark.min.css?id=bdfc704731682c67645a2248b0b8d2d7",
|
"/css/dist/skins/skin-black-dark.min.css": "/css/dist/skins/skin-black-dark.min.css?id=b061bb141af3bdb6280c6ee772cf8f4f",
|
||||||
"/css/dist/skins/skin-blue.min.css": "/css/dist/skins/skin-blue.min.css?id=f677207c6cf9678eb539abecb408c374",
|
"/css/dist/skins/skin-blue.min.css": "/css/dist/skins/skin-blue.min.css?id=f677207c6cf9678eb539abecb408c374",
|
||||||
"/css/dist/skins/skin-blue-dark.min.css": "/css/dist/skins/skin-blue-dark.min.css?id=07273f6ca3c698a39e8fc2075af4fa07",
|
"/css/dist/skins/skin-blue-dark.min.css": "/css/dist/skins/skin-blue-dark.min.css?id=07273f6ca3c698a39e8fc2075af4fa07",
|
||||||
"/css/dist/skins/skin-yellow.min.css": "/css/dist/skins/skin-yellow.min.css?id=7b315b9612b8fde8f9c5b0ddb6bba690",
|
"/css/dist/skins/skin-yellow.min.css": "/css/dist/skins/skin-yellow.min.css?id=7b315b9612b8fde8f9c5b0ddb6bba690",
|
||||||
|
|
|
@ -399,7 +399,7 @@ img.navbar-brand-img, .navbar-brand>img {
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-med {
|
.icon-med {
|
||||||
font-size: 20px;
|
font-size: 14px;
|
||||||
color: #889195;
|
color: #889195;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -124,11 +124,11 @@ a {
|
||||||
--button-primary: darken(@black, 25%);
|
--button-primary: darken(@black, 25%);
|
||||||
--button-hover: darken(@black, 30%);
|
--button-hover: darken(@black, 30%);
|
||||||
--header: @black; /* Use same as Header picker */
|
--header: @black; /* Use same as Header picker */
|
||||||
--text-main: #BBB;
|
--text-main: #fff;
|
||||||
--text-sub: #9b9b9b;
|
--text-sub: #9b9b9b;
|
||||||
--link: #AAA; /* Use same as Header picker, lighten by 70% */
|
--link: #fff; /* Use same as Header picker, lighten by 70% */
|
||||||
--visited-link: lighten(@black, 40%); /* Use same as Header picker, lighten by 70% */
|
--visited-link: #fff; /* Use same as Header picker, lighten by 70% */
|
||||||
--hover-link: lighten(@black, 45%); /* Use same as Header picker, lighten by 70% */
|
--hover-link: #949494; /* Use same as Header picker, lighten by 70% */
|
||||||
--nav-link: #FFF; /* Use same as Header picker */
|
--nav-link: #FFF; /* Use same as Header picker */
|
||||||
--light-link: #fff; /* Use same as Header picker */
|
--light-link: #fff; /* Use same as Header picker */
|
||||||
}
|
}
|
||||||
|
@ -193,18 +193,6 @@ h2.task_menu{
|
||||||
color: var(--text-main);
|
color: var(--text-main);
|
||||||
}
|
}
|
||||||
|
|
||||||
a:link {
|
|
||||||
color: var(--link);
|
|
||||||
}
|
|
||||||
|
|
||||||
a:visited {
|
|
||||||
color: var(--nav-link);
|
|
||||||
}
|
|
||||||
|
|
||||||
a:hover {
|
|
||||||
color: var(--hover-link);
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-primary.hover {
|
.btn-primary.hover {
|
||||||
color: var(--nav-link);
|
color: var(--nav-link);
|
||||||
}
|
}
|
||||||
|
@ -318,8 +306,11 @@ input[type=text], input[type=search] {
|
||||||
background-color: var(--back-sub);
|
background-color: var(--back-sub);
|
||||||
color: var(--text-main);
|
color: var(--text-main);
|
||||||
}
|
}
|
||||||
|
.search-highlight, .search-highlight:hover{
|
||||||
|
background-color: var(--back-sub) !important;
|
||||||
|
}
|
||||||
.input-group, .input-group-addon {
|
.input-group, .input-group-addon {
|
||||||
background-color: var(--back-sub)!important;
|
background-color: var(--back-sub);
|
||||||
color: var(--text-main);
|
color: var(--text-main);
|
||||||
}
|
}
|
||||||
#licensesTable>tbody>tr>td>nobr>a>i.fa {
|
#licensesTable>tbody>tr>td>nobr>a>i.fa {
|
||||||
|
@ -363,11 +354,11 @@ input[type=text], input[type=search] {
|
||||||
}
|
}
|
||||||
.select2-container--default .select2-results__option[aria-selected=true], .select2-container--default .select2-results__option[aria-selected=true]:hover {
|
.select2-container--default .select2-results__option[aria-selected=true], .select2-container--default .select2-results__option[aria-selected=true]:hover {
|
||||||
background-color: var(--back-sub);
|
background-color: var(--back-sub);
|
||||||
color: var(--header);
|
color: var(--nav-link);
|
||||||
}
|
}
|
||||||
.select2-container--default .select2-results__option--highlighted[aria-selected] {
|
.select2-container--default .select2-results__option--highlighted[aria-selected] {
|
||||||
background-color: var(--header);
|
background-color: var(--back-sub);
|
||||||
color: var(--back-main);
|
color: var(--visited-link);
|
||||||
}
|
}
|
||||||
.select2-container--default .select2-selection--single .select2-selection__rendered {
|
.select2-container--default .select2-selection--single .select2-selection__rendered {
|
||||||
color: var(--text-main);
|
color: var(--text-main);
|
||||||
|
@ -426,9 +417,6 @@ a {
|
||||||
color: var(--hover-link);
|
color: var(--hover-link);
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
&:visited {
|
|
||||||
color: var(--visited-link)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.row-striped {
|
.row-striped {
|
||||||
|
@ -463,4 +451,7 @@ a {
|
||||||
}
|
}
|
||||||
div.container.row-new-striped{
|
div.container.row-new-striped{
|
||||||
background-color: var(--back-sub);
|
background-color: var(--back-sub);
|
||||||
|
}
|
||||||
|
.table > thead > tr > td.danger, .table > tbody > tr > td.danger, .table > tfoot > tr > td.danger, .table > thead > tr > th.danger, .table > tbody > tr > th.danger, .table > tfoot > tr > th.danger, .table > thead > tr.danger > td, .table > tbody > tr.danger > td, .table > tfoot > tr.danger > td, .table > thead > tr.danger > th, .table > tbody > tr.danger > th, .table > tfoot > tr.danger > th {
|
||||||
|
background-color: var(--back-sub);
|
||||||
}
|
}
|
|
@ -9,6 +9,7 @@ return [
|
||||||
'ad_append_domain_help' => 'User isn\'t required to write "username@domain.local", they can just type "username".',
|
'ad_append_domain_help' => 'User isn\'t required to write "username@domain.local", they can just type "username".',
|
||||||
'admin_cc_email' => 'CC Email',
|
'admin_cc_email' => 'CC Email',
|
||||||
'admin_cc_email_help' => 'If you would like to send a copy of checkin/checkout emails that are sent to users to an additional email account, enter it here. Otherwise leave this field blank.',
|
'admin_cc_email_help' => 'If you would like to send a copy of checkin/checkout emails that are sent to users to an additional email account, enter it here. Otherwise leave this field blank.',
|
||||||
|
'admin_settings' => 'Admin Settings',
|
||||||
'is_ad' => 'This is an Active Directory server',
|
'is_ad' => 'This is an Active Directory server',
|
||||||
'alerts' => 'Alerts',
|
'alerts' => 'Alerts',
|
||||||
'alert_title' => 'Update Notification Settings',
|
'alert_title' => 'Update Notification Settings',
|
||||||
|
|
|
@ -21,6 +21,7 @@ return array(
|
||||||
'manager' => 'Manager',
|
'manager' => 'Manager',
|
||||||
'managed_locations' => 'Managed Locations',
|
'managed_locations' => 'Managed Locations',
|
||||||
'name' => 'Name',
|
'name' => 'Name',
|
||||||
|
'nogroup' => 'No groups have been created yet. To add one, visit: ',
|
||||||
'notes' => 'Notes',
|
'notes' => 'Notes',
|
||||||
'password_confirm' => 'Confirm Password',
|
'password_confirm' => 'Confirm Password',
|
||||||
'password' => 'Password',
|
'password' => 'Password',
|
||||||
|
|
|
@ -156,6 +156,7 @@ return [
|
||||||
'image_filetypes_help' => 'Accepted filetypes are jpg, webp, png, gif, and svg. Max upload size allowed is :size.',
|
'image_filetypes_help' => 'Accepted filetypes are jpg, webp, png, gif, and svg. Max upload size allowed is :size.',
|
||||||
'unaccepted_image_type' => 'This image file was not readable. Accepted filetypes are jpg, webp, png, gif, and svg. The mimetype of this file is: :mimetype.',
|
'unaccepted_image_type' => 'This image file was not readable. Accepted filetypes are jpg, webp, png, gif, and svg. The mimetype of this file is: :mimetype.',
|
||||||
'import' => 'Import',
|
'import' => 'Import',
|
||||||
|
'import_this_file' => 'Map fields and process this file',
|
||||||
'importing' => 'Importing',
|
'importing' => 'Importing',
|
||||||
'importing_help' => 'You can import assets, accessories, licenses, components, consumables, and users via CSV file. <br><br>The CSV should be comma-delimited and formatted with headers that match the ones in the <a href="https://snipe-it.readme.io/docs/importing" target="_new">sample CSVs in the documentation</a>.',
|
'importing_help' => 'You can import assets, accessories, licenses, components, consumables, and users via CSV file. <br><br>The CSV should be comma-delimited and formatted with headers that match the ones in the <a href="https://snipe-it.readme.io/docs/importing" target="_new">sample CSVs in the documentation</a>.',
|
||||||
'import-history' => 'Import History',
|
'import-history' => 'Import History',
|
||||||
|
@ -491,5 +492,11 @@ return [
|
||||||
'upload_error' => 'Error uploading file. Please check that there are no empty rows and that no column names are duplicated.',
|
'upload_error' => 'Error uploading file. Please check that there are no empty rows and that no column names are duplicated.',
|
||||||
'copy_to_clipboard' => 'Copy to Clipboard',
|
'copy_to_clipboard' => 'Copy to Clipboard',
|
||||||
'copied' => 'Copied!',
|
'copied' => 'Copied!',
|
||||||
|
'status_compatibility' => 'If assets are already assigned, they cannot be changed to a non-deployable status type and this value change will be skipped.',
|
||||||
|
'rtd_location_help' => 'This is the location of the asset when it is not checked out',
|
||||||
|
'item_not_found' => ':item_type ID :id does not exist or has been deleted',
|
||||||
|
'action_permission_denied' => 'You do not have permission to :action :item_type ID :id',
|
||||||
|
'action_permission_generic' => 'You do not have permission to :action this :item_type',
|
||||||
|
'edit' => 'edit',
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
|
@ -491,7 +491,7 @@
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="col-md-4">{{ trans('general.name') }}</th>
|
<th class="col-md-4">{{ trans('general.name') }}</th>
|
||||||
<th class="col-md-4">{{ trans('admin/hardware/form.serial') }}</th>
|
<th class="col-md-4">{{ trans('admin/licenses/form.license_key') }}</th>
|
||||||
<th class="col-md-4">{{ trans('general.category') }}</th>
|
<th class="col-md-4">{{ trans('general.category') }}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
<tr>
|
<tr>
|
||||||
<td></td>
|
<td></td>
|
||||||
<td>{{ trans('admin/hardware/table.id') }}</td>
|
<td>{{ trans('admin/hardware/table.id') }}</td>
|
||||||
<td>{{ trans('admin/hardware/table.name') }}</td>
|
<td>{{ trans('admin/hardware/form.name') }}</td>
|
||||||
<td>{{ trans('admin/hardware/table.location')}}</td>
|
<td>{{ trans('admin/hardware/table.location')}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
|
|
@ -19,18 +19,22 @@
|
||||||
|
|
||||||
<p>{{ trans('admin/hardware/form.bulk_update_help') }}</p>
|
<p>{{ trans('admin/hardware/form.bulk_update_help') }}</p>
|
||||||
|
|
||||||
<div class="callout callout-warning">
|
|
||||||
<i class="fas fa-exclamation-triangle"></i> {{ trans_choice('admin/hardware/form.bulk_update_warn', count($assets), ['asset_count' => count($assets)]) }}
|
|
||||||
@if (count($models) > 0)
|
|
||||||
{{ trans_choice('admin/hardware/form.bulk_update_with_custom_field', count($models), ['asset_model_count' => count($models)]) }}
|
|
||||||
@endif
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<form class="form-horizontal" method="post" action="{{ route('hardware/bulksave') }}" autocomplete="off" role="form">
|
<form class="form-horizontal" method="post" action="{{ route('hardware/bulksave') }}" autocomplete="off" role="form">
|
||||||
{{ csrf_field() }}
|
{{ csrf_field() }}
|
||||||
|
|
||||||
<div class="box box-default">
|
<div class="box box-default">
|
||||||
<div class="box-body">
|
<div class="box-body">
|
||||||
|
|
||||||
|
<div class="callout callout-warning">
|
||||||
|
<i class="fas fa-exclamation-triangle"></i> {{ trans_choice('admin/hardware/form.bulk_update_warn', count($assets), ['asset_count' => count($assets)]) }}
|
||||||
|
|
||||||
|
@if (count($models) > 0)
|
||||||
|
{{ trans_choice('admin/hardware/form.bulk_update_with_custom_field', count($models), ['asset_model_count' => count($models)]) }}
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Purchase Date -->
|
<!-- Purchase Date -->
|
||||||
<div class="form-group {{ $errors->has('purchase_date') ? ' has-error' : '' }}">
|
<div class="form-group {{ $errors->has('purchase_date') ? ' has-error' : '' }}">
|
||||||
<label for="purchase_date" class="col-md-3 control-label">{{ trans('admin/hardware/form.date') }}</label>
|
<label for="purchase_date" class="col-md-3 control-label">{{ trans('admin/hardware/form.date') }}</label>
|
||||||
|
@ -76,6 +80,7 @@
|
||||||
</label>
|
</label>
|
||||||
<div class="col-md-7">
|
<div class="col-md-7">
|
||||||
{{ Form::select('status_id', $statuslabel_list , old('status_id'), array('class'=>'select2', 'style'=>'width:100%', 'aria-label'=>'status_id')) }}
|
{{ Form::select('status_id', $statuslabel_list , old('status_id'), array('class'=>'select2', 'style'=>'width:100%', 'aria-label'=>'status_id')) }}
|
||||||
|
<p class="help-block">{{ trans('general.status_compatibility') }}</p>
|
||||||
{!! $errors->first('status_id', '<span class="alert-msg" aria-hidden="true"><i class="fas fa-times" aria-hidden="true"></i> :message</span>') !!}
|
{!! $errors->first('status_id', '<span class="alert-msg" aria-hidden="true"><i class="fas fa-times" aria-hidden="true"></i> :message</span>') !!}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -189,8 +194,8 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@include("models/custom_fields_form_bulk_edit",["models" => $models])
|
@include("models/custom_fields_form_bulk_edit",["models" => $models])
|
||||||
|
|
||||||
@foreach ($assets as $key => $value)
|
@foreach ($assets as $key => $value)
|
||||||
<input type="hidden" name="ids[{{ $value }}]" value="1">
|
<input type="hidden" name="ids[{{ $value }}]" value="1">
|
||||||
@endforeach
|
@endforeach
|
||||||
|
|
|
@ -65,7 +65,7 @@
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
@include ('partials.forms.edit.notes')
|
@include ('partials.forms.edit.notes')
|
||||||
@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', 'help_text' => trans('general.rtd_location_help')])
|
||||||
@include ('partials.forms.edit.requestable', ['requestable_text' => trans('admin/hardware/general.requestable')])
|
@include ('partials.forms.edit.requestable', ['requestable_text' => trans('admin/hardware/general.requestable')])
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -81,6 +81,8 @@
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{{ trans('general.asset_tag') }}</th>
|
<th>{{ trans('general.asset_tag') }}</th>
|
||||||
|
<th>{{ trans('general.asset_model') }}</th>
|
||||||
|
<th>{{ trans('general.model_no') }}</th>
|
||||||
<th>{{ trans('general.quickscan_checkin_status') }}</th>
|
<th>{{ trans('general.quickscan_checkin_status') }}</th>
|
||||||
<th></th>
|
<th></th>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -126,7 +128,7 @@
|
||||||
data : formData,
|
data : formData,
|
||||||
success : function (data) {
|
success : function (data) {
|
||||||
if (data.status == 'success') {
|
if (data.status == 'success') {
|
||||||
$('#checkedin tbody').prepend("<tr class='success'><td>" + data.payload.asset + "</td><td>" + data.messages + "</td><td><i class='fas fa-check text-success'></i></td></tr>");
|
$('#checkedin tbody').prepend("<tr class='success'><td>" + data.payload.asset_tag + "</td><td>" + data.payload.model + "</td><td>" + data.payload.model_number + "</td><td>" + data.messages + "</td><td><i class='fas fa-check text-success'></i></td></tr>");
|
||||||
incrementOnSuccess();
|
incrementOnSuccess();
|
||||||
} else {
|
} else {
|
||||||
handlecheckinFail(data);
|
handlecheckinFail(data);
|
||||||
|
@ -146,17 +148,21 @@
|
||||||
});
|
});
|
||||||
|
|
||||||
function handlecheckinFail (data) {
|
function handlecheckinFail (data) {
|
||||||
if (data.payload.asset) {
|
if (data.payload.asset_tag) {
|
||||||
var asset = data.payload.asset;
|
var asset_tag = data.payload.asset_tag;
|
||||||
|
var model = data.payload.model;
|
||||||
|
var model_number = data.payload.model_number;
|
||||||
} else {
|
} else {
|
||||||
var asset = '';
|
var asset_tag = '';
|
||||||
|
var model = '';
|
||||||
|
var model_number = '';
|
||||||
}
|
}
|
||||||
if (data.messages) {
|
if (data.messages) {
|
||||||
var messages = data.messages;
|
var messages = data.messages;
|
||||||
} else {
|
} else {
|
||||||
var messages = '';
|
var messages = '';
|
||||||
}
|
}
|
||||||
$('#checkedin tbody').prepend("<tr class='danger'><td>" + asset + "</td><td>" + messages + "</td><td><i class='fas fa-times text-danger'></i></td></tr>");
|
$('#checkedin tbody').prepend("<tr class='danger'><td>" + asset_tag + "</td><td>" + model + "</td><td>" + model_number + "</td><td>" + messages + "</td><td><i class='fas fa-times text-danger'></i></td></tr>");
|
||||||
}
|
}
|
||||||
|
|
||||||
function incrementOnSuccess() {
|
function incrementOnSuccess() {
|
||||||
|
|
|
@ -46,7 +46,8 @@
|
||||||
<th class="col-md-2" data-sortable="true">{{ trans('admin/hardware/form.expected_checkin') }}</th>
|
<th class="col-md-2" data-sortable="true">{{ trans('admin/hardware/form.expected_checkin') }}</th>
|
||||||
<th class="col-md-3" data-sortable="true">{{ trans('admin/hardware/table.requesting_user') }}</th>
|
<th class="col-md-3" data-sortable="true">{{ trans('admin/hardware/table.requesting_user') }}</th>
|
||||||
<th class="col-md-2">{{ trans('admin/hardware/table.requested_date') }}</th>
|
<th class="col-md-2">{{ trans('admin/hardware/table.requested_date') }}</th>
|
||||||
<th class="col-md-1">{{ trans('button.actions') }}</th> <th></th>
|
<th class="col-md-1">{{ trans('button.actions') }}</th>
|
||||||
|
<th class="col-md-1">{{ trans('general.checkout') }}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
|
|
@ -1206,15 +1206,15 @@
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th data-visible="true" data-field="icon" style="width: 40px;" class="hidden-xs" data-formatter="iconFormatter">{{ trans('admin/hardware/table.icon') }}</th>
|
<th data-visible="true" data-field="icon" style="width: 40px;" class="hidden-xs" data-formatter="iconFormatter">{{ trans('admin/hardware/table.icon') }}</th>
|
||||||
<th class="col-sm-2" data-visible="true" data-field="action_date" data-formatter="dateDisplayFormatter">{{ trans('general.date') }}</th>
|
<th data-visible="true" data-field="action_date" data-formatter="dateDisplayFormatter">{{ trans('general.date') }}</th>
|
||||||
<th class="col-sm-1" data-visible="true" data-field="admin" data-formatter="usersLinkObjFormatter">{{ trans('general.admin') }}</th>
|
<th data-visible="true" data-field="admin" data-formatter="usersLinkObjFormatter">{{ trans('general.admin') }}</th>
|
||||||
<th class="col-sm-1" data-visible="true" data-field="action_type">{{ trans('general.action') }}</th>
|
<th data-visible="true" data-field="action_type">{{ trans('general.action') }}</th>
|
||||||
<th class="col-sm-2" data-visible="true" data-field="item" data-formatter="polymorphicItemFormatter">{{ trans('general.item') }}</th>
|
<th data-visible="true" data-field="item" data-formatter="polymorphicItemFormatter">{{ trans('general.item') }}</th>
|
||||||
<th class="col-sm-2" data-visible="true" data-field="target" data-formatter="polymorphicItemFormatter">{{ trans('general.target') }}</th>
|
<th data-visible="true" data-field="target" data-formatter="polymorphicItemFormatter">{{ trans('general.target') }}</th>
|
||||||
<th class="col-sm-2" data-field="note">{{ trans('general.notes') }}</th>
|
<th data-field="note">{{ trans('general.notes') }}</th>
|
||||||
<th class="col-md-3" data-field="signature_file" data-visible="false" data-formatter="imageFormatter">{{ trans('general.signature') }}</th>
|
<th data-field="signature_file" data-visible="false" data-formatter="imageFormatter">{{ trans('general.signature') }}</th>
|
||||||
<th class="col-md-3" data-visible="false" data-field="file" data-visible="false" data-formatter="fileUploadFormatter">{{ trans('general.download') }}</th>
|
<th data-visible="false" data-field="file" data-visible="false" data-formatter="fileUploadFormatter">{{ trans('general.download') }}</th>
|
||||||
<th class="col-sm-2" data-field="log_meta" data-visible="true" data-formatter="changeLogFormatter">{{ trans('admin/hardware/table.changed')}}</th>
|
<th data-field="log_meta" data-visible="true" data-formatter="changeLogFormatter">{{ trans('admin/hardware/table.changed')}}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
</table>
|
</table>
|
||||||
|
|
|
@ -624,7 +624,7 @@
|
||||||
@can('import')
|
@can('import')
|
||||||
<li{!! (Request::is('import/*') ? ' class="active"' : '') !!}>
|
<li{!! (Request::is('import/*') ? ' class="active"' : '') !!}>
|
||||||
<a href="{{ route('imports.index') }}">
|
<a href="{{ route('imports.index') }}">
|
||||||
<i class="fas fa-cloud-download-alt fa-fw" aria-hidden="true"></i>
|
<i class="fas fa-cloud-upload-alt fa-fw" aria-hidden="true"></i>
|
||||||
<span>{{ trans('general.import') }}</span>
|
<span>{{ trans('general.import') }}</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -36,7 +36,7 @@
|
||||||
|
|
||||||
<!-- Serial -->
|
<!-- Serial -->
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="col-sm-2 control-label">{{ trans('admin/hardware/form.serial') }}</label>
|
<label class="col-sm-2 control-label">{{ trans('admin/licenses/form.license_key') }}</label>
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<p class="form-control-static">
|
<p class="form-control-static">
|
||||||
@can('viewKeys', $licenseSeat->license)
|
@can('viewKeys', $licenseSeat->license)
|
||||||
|
|
|
@ -43,7 +43,7 @@
|
||||||
|
|
||||||
<!-- Serial -->
|
<!-- Serial -->
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="col-sm-3 control-label">{{ trans('admin/hardware/form.serial') }}</label>
|
<label class="col-sm-3 control-label">{{ trans('admin/licenses/form.license_key') }}</label>
|
||||||
<div class="col-md-9">
|
<div class="col-md-9">
|
||||||
<p class="form-control-static" style="word-wrap: break-word;">
|
<p class="form-control-static" style="word-wrap: break-word;">
|
||||||
@can('viewKeys', $license)
|
@can('viewKeys', $license)
|
||||||
|
|
|
@ -1,54 +1,80 @@
|
||||||
<span> {{-- This <span> doesn't seem to fix it, neither does a div? --}}
|
<span>
|
||||||
|
|
||||||
<div class="form-group{{ $errors->has('custom_fieldset') ? ' has-error' : '' }}">
|
<div class="form-group{{ $errors->has('custom_fieldset') ? ' has-error' : '' }}">
|
||||||
<label for="custom_fieldset" class="col-md-3 control-label">{{ trans('admin/models/general.fieldset') }}</label>
|
<label for="custom_fieldset" class="col-md-3 control-label">
|
||||||
<div class="col-md-5">
|
{{ trans('admin/models/general.fieldset') }}
|
||||||
{{ Form::select('fieldset_id', Helper::customFieldsetList(), old('fieldset_id', $fieldset_id), array('class'=>'select2 js-fieldset-field livewire-select2', 'style'=>'width:100%; min-width:350px', 'aria-label'=>'custom_fieldset', 'data-livewire-component' => $_instance->id)) }}
|
</label>
|
||||||
{!! $errors->first('custom_fieldset', '<span class="alert-msg" aria-hidden="true"><br><i class="fas fa-times"></i> :message</span>') !!}
|
<div class="col-md-5">
|
||||||
</div>
|
{{ Form::select('fieldset_id', Helper::customFieldsetList(), old('fieldset_id', $fieldset_id), array('class'=>'select2 js-fieldset-field livewire-select2', 'style'=>'width:100%; min-width:350px', 'aria-label'=>'custom_fieldset', 'data-livewire-component' => $_instance->id)) }}
|
||||||
<div class="col-md-3">
|
{!! $errors->first('custom_fieldset', '<span class="alert-msg" aria-hidden="true"><br><i class="fas fa-times"></i> :message</span>') !!}
|
||||||
<label class="form-control">
|
</div>
|
||||||
{{ Form::checkbox('add_default_values', 1, old('add_default_values', $add_default_values), ['data-livewire-component' => $_instance->id, 'id' => 'add_default_values', 'wire:model' => 'add_default_values']) }}
|
<div class="col-md-3">
|
||||||
{{ trans('admin/models/general.add_default_values') }}
|
<label class="form-control">
|
||||||
</label>
|
{{ Form::checkbox('add_default_values', 1, old('add_default_values', $add_default_values), ['data-livewire-component' => $_instance->id, 'id' => 'add_default_values', 'wire:model' => 'add_default_values']) }}
|
||||||
</div>
|
{{ trans('admin/models/general.add_default_values') }}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@if ($this->add_default_values ) {{-- 'if the checkbox is enabled *AND* there are more than 0 fields in the fieldsset' --}}
|
@if ($this->add_default_values ) {{-- 'if the checkbox is enabled *AND* there are more than 0 fields in the fieldsset' --}}
|
||||||
<div style="padding-left: 10px; padding-bottom: 0px; margin-bottom: -15px;">
|
|
||||||
<div class="form-group">
|
|
||||||
@if ($fields)
|
@if ($fields)
|
||||||
|
|
||||||
@foreach ($fields as $field)
|
@foreach ($fields as $field)
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
|
||||||
<label class="col-md-3 control-label{{ $errors->has($field->name) ? ' has-error' : '' }}" for="default-value{{ $field->id }}">{{ $field->name }}</label>
|
|
||||||
|
|
||||||
<div class="col-md-7">
|
<label class="col-md-3 control-label{{ $errors->has($field->name) ? ' has-error' : '' }}">{{ $field->name }}</label>
|
||||||
|
|
||||||
|
<div class="col-md-7">
|
||||||
|
|
||||||
@if ($field->format == "DATE")
|
@if ($field->format == "DATE")
|
||||||
|
|
||||||
<div class="input-group col-md-4" style="padding-left: 0px;">
|
<div class="input-group col-md-4" style="padding-left: 0px;">
|
||||||
<div class="input-group date" data-provide="datepicker" data-date-format="yyyy-mm-dd" data-autoclose="true">
|
<div class="input-group date" data-provide="datepicker" data-date-format="yyyy-mm-dd" data-autoclose="true">
|
||||||
<input type="text" class="form-control" placeholder="{{ trans('general.select_date') }}" name="default_values[{{ $field->id }}]" id="default-value{{ $field->id }}" value="{{ $field->defaultValue($model_id) }}">
|
<input type="text" class="form-control" placeholder="{{ trans('general.select_date') }}" name="default_values[{{ $field->id }}]" id="default-value{{ $field->id }}" value="{{ $field->defaultValue($model_id) }}">
|
||||||
<span class="input-group-addon"><i class="fas fa-calendar" aria-hidden="true"></i></span>
|
<span class="input-group-addon"><i class="fas fa-calendar" aria-hidden="true"></i></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@elseif ($field->element == "text")
|
@elseif ($field->element == "text")
|
||||||
<input class="form-control m-b-xs" type="text" value="{{ $field->defaultValue($model_id) }}" id="default-value{{ $field->id }}" name="default_values[{{ $field->id }}]">
|
|
||||||
|
|
||||||
|
<input class="form-control" type="text" value="{{ $field->defaultValue($model_id) }}" id="default-value{{ $field->id }}" name="default_values[{{ $field->id }}]">
|
||||||
|
|
||||||
|
|
||||||
@elseif($field->element == "textarea")
|
@elseif($field->element == "textarea")
|
||||||
<textarea class="form-control" style="width: 100%;" id="default-value{{ $field->id }}" name="default_values[{{ $field->id }}]">{{ $field->defaultValue($model_id) }}</textarea><br>
|
|
||||||
|
|
||||||
|
<textarea class="form-control" style="width: 100%;" id="default-value{{ $field->id }}" name="default_values[{{ $field->id }}]">{{ $field->defaultValue($model_id) }}</textarea>
|
||||||
|
|
||||||
|
|
||||||
@elseif($field->element == "listbox")
|
@elseif($field->element == "listbox")
|
||||||
|
|
||||||
<select class="form-control m-b-xs" name="default_values[{{ $field->id }}]">
|
|
||||||
<option value=""></option>
|
<select class="form-control" name="default_values[{{ $field->id }}]">
|
||||||
@foreach(explode("\r\n", $field->field_values) as $field_value)
|
<option value=""></option>
|
||||||
<option value="{{$field_value}}" {{ $field->defaultValue($model_id) == $field_value ? 'selected="selected"': '' }}>{{ $field_value }}</option>
|
@foreach(explode("\r\n", $field->field_values) as $field_value)
|
||||||
@endforeach
|
<option value="{{$field_value}}" {{ $field->defaultValue($model_id) == $field_value ? 'selected="selected"': '' }}>{{ $field_value }}</option>
|
||||||
</select>
|
@endforeach
|
||||||
|
</select>
|
||||||
|
|
||||||
|
|
||||||
@elseif($field->element == "radio")
|
@elseif($field->element == "radio")
|
||||||
|
|
||||||
@foreach(explode("\r\n", $field->field_values) as $field_value)
|
@foreach(explode("\r\n", $field->field_values) as $field_value)
|
||||||
<input type='radio' name="default_values[{{ $field->id }}]" value="{{$field_value}}" {{ $field->defaultValue($model_id) == $field_value ? 'checked="checked"': '' }} />{{ $field_value }}<br />
|
<label class="col-md-3 form-control" for="{{ str_slug($field_value) }}">
|
||||||
|
<input id="{{ str_slug($field_value) }}" aria-label="{{ str_slug($field->name) }}" type='radio' name="default_values[{{ $field->id }}]" value="{{$field_value}}" {{ $field->defaultValue($model_id) == $field_value ? 'checked="checked"': '' }} />{{ $field_value }}
|
||||||
|
</label>
|
||||||
@endforeach
|
@endforeach
|
||||||
|
|
||||||
@elseif($field->element == "checkbox")
|
@elseif($field->element == "checkbox")
|
||||||
@foreach(explode("\r\n", $field->field_values) as $field_value)
|
|
||||||
<input type='checkbox' name="default_values[{{ $field->id }}][]" value="{{$field_value}}" {{ in_array($field_value, explode(', ',$field->defaultValue($model_id))) ? 'checked="checked"': '' }} /> {{ $field_value }}<br />
|
@foreach(explode("\r\n", $field->field_values) as $field_value)
|
||||||
|
<label class="col-md-3 form-control" for="{{ str_slug($field_value) }}">
|
||||||
|
<input id="{{ str_slug($field_value) }}" type="checkbox" aria-label="{{ str_slug($field->name) }}" name="default_values[{{ $field->id }}][]" value="{{ $field_value }}"{{ in_array($field_value, explode(', ',$field->defaultValue($model_id))) ? ' checked="checked"': '' }}> {{ $field_value }}
|
||||||
|
</label>
|
||||||
@endforeach
|
@endforeach
|
||||||
|
|
||||||
|
|
||||||
@else
|
@else
|
||||||
<span class="help-block form-error">
|
<span class="help-block form-error">
|
||||||
Unknown field element: {{ $field->element }}
|
Unknown field element: {{ $field->element }}
|
||||||
|
@ -58,9 +84,8 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@endforeach
|
@endforeach
|
||||||
|
</div>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@endif
|
@endif
|
||||||
</span>
|
</span>
|
||||||
|
|
|
@ -129,8 +129,8 @@
|
||||||
<td class="col-md-3">{{ Helper::getFormattedDateObject($currentFile->created_at, 'datetime', false) }}</td>
|
<td class="col-md-3">{{ Helper::getFormattedDateObject($currentFile->created_at, 'datetime', false) }}</td>
|
||||||
<td class="col-md-1">{{ Helper::formatFilesizeUnits($currentFile->filesize) }}</td>
|
<td class="col-md-1">{{ Helper::formatFilesizeUnits($currentFile->filesize) }}</td>
|
||||||
<td class="col-md-1 text-right" style="white-space: nowrap;">
|
<td class="col-md-1 text-right" style="white-space: nowrap;">
|
||||||
<button class="btn btn-sm btn-info" wire:click="selectFile({{ $currentFile->id }})">
|
<button class="btn btn-sm btn-info" wire:click="selectFile({{ $currentFile->id }})" data-tooltip="true" title="{{ trans('general.import_this_file') }}">
|
||||||
<i class="fas fa-retweet fa-fw" aria-hidden="true"></i>
|
<i class="fa-solid fa-list-check" aria-hidden="true"></i>
|
||||||
<span class="sr-only">{{ trans('general.import') }}</span>
|
<span class="sr-only">{{ trans('general.import') }}</span>
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-sm btn-danger" wire:click="destroy({{ $currentFile->id }})">
|
<button class="btn btn-sm btn-danger" wire:click="destroy({{ $currentFile->id }})">
|
||||||
|
|
|
@ -40,7 +40,8 @@
|
||||||
data-id-table="system-backups"
|
data-id-table="system-backups"
|
||||||
data-search="true"
|
data-search="true"
|
||||||
data-side-pagination="client"
|
data-side-pagination="client"
|
||||||
data-sort-order="asc"
|
data-sort-order="desc"
|
||||||
|
data-sort-name="modified_display"
|
||||||
id="system-backups"
|
id="system-backups"
|
||||||
class="table table-striped snipe-table">
|
class="table table-striped snipe-table">
|
||||||
<thead>
|
<thead>
|
||||||
|
|
|
@ -553,7 +553,7 @@
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
@else
|
@else
|
||||||
<p>No groups have been created yet. Visit <code>Admin Settings > Permission Groups</code> to add one.</p>
|
<p>{{ trans('admin/users/table.nogroup') }} <code>{{ trans('admin/settings/general.admin_settings') }} <i class="fa fa-cogs"></i> > {{ trans('general.groups') }} <i class="fas fa-user-friends"></i></code> </p>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -638,13 +638,14 @@
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
|
@if($user->getUserTotalCost()->total_user_cost > 0)
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
|
||||||
<div class="col-md-3">
|
<div class="col-md-3">
|
||||||
{{ trans('admin/users/table.total_assets_cost') }}
|
{{ trans('admin/users/table.total_assets_cost') }}
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-9">
|
<div class="col-md-9">
|
||||||
{{Helper::formatCurrencyOutput($user->getUserTotalCost()->total_user_cost)}}
|
{{Helper::formatCurrencyOutput($user->getUserTotalCost()->total_user_cost)}}
|
||||||
|
|
||||||
<a id="optional_info" class="text-primary">
|
<a id="optional_info" class="text-primary">
|
||||||
<i class="fa fa-caret-right fa-2x" id="optional_info_icon"></i>
|
<i class="fa fa-caret-right fa-2x" id="optional_info_icon"></i>
|
||||||
<strong>{{ trans('admin/hardware/form.optional_infos') }}</strong>
|
<strong>{{ trans('admin/hardware/form.optional_infos') }}</strong>
|
||||||
|
@ -658,13 +659,10 @@
|
||||||
{{trans('general.accessories').': '.Helper::formatCurrencyOutput($user->getUserTotalCost()->accessory_cost)}}<br>
|
{{trans('general.accessories').': '.Helper::formatCurrencyOutput($user->getUserTotalCost()->accessory_cost)}}<br>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div><!--/.row-->
|
||||||
|
@endif
|
||||||
</div> <!--/end striped container-->
|
</div> <!--/end striped container-->
|
||||||
</div> <!-- end col-md-9 -->
|
</div> <!-- end col-md-9 -->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div> <!--/.row-->
|
</div> <!--/.row-->
|
||||||
</div><!-- /.tab-pane -->
|
</div><!-- /.tab-pane -->
|
||||||
|
|
||||||
|
@ -729,7 +727,7 @@
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="col-md-5">{{ trans('general.name') }}</th>
|
<th class="col-md-5">{{ trans('general.name') }}</th>
|
||||||
<th>{{ trans('admin/hardware/form.serial') }}</th>
|
<th>{{ trans('admin/licenses/form.license_key') }}</th>
|
||||||
<th data-footer-formatter="sumFormatter" data-fieldname="purchase_cost">{{ trans('general.purchase_cost') }}</th>
|
<th data-footer-formatter="sumFormatter" data-fieldname="purchase_cost">{{ trans('general.purchase_cost') }}</th>
|
||||||
<th>{{ trans('admin/licenses/form.purchase_order') }}</th>
|
<th>{{ trans('admin/licenses/form.purchase_order') }}</th>
|
||||||
<th>{{ trans('general.order_number') }}</th>
|
<th>{{ trans('general.order_number') }}</th>
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
namespace Tests\Support;
|
namespace Tests\Support;
|
||||||
|
|
||||||
use App\Models\Setting;
|
use App\Models\Setting;
|
||||||
|
use Illuminate\Support\Facades\Crypt;
|
||||||
|
|
||||||
class Settings
|
class Settings
|
||||||
{
|
{
|
||||||
|
@ -67,6 +68,39 @@ class Settings
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function enableLdap(): Settings
|
||||||
|
{
|
||||||
|
return $this->update([
|
||||||
|
'ldap_enabled' => 1,
|
||||||
|
'ldap_server' => 'ldaps://ldap.example.com',
|
||||||
|
'ldap_uname' => 'fake_username',
|
||||||
|
'ldap_pword' => Crypt::encrypt("fake_password"),
|
||||||
|
'ldap_basedn' => 'CN=Users,DC=ad,DC=example,Dc=com'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function enableAnonymousLdap(): Settings
|
||||||
|
{
|
||||||
|
return $this->update([
|
||||||
|
'ldap_enabled' => 1,
|
||||||
|
'ldap_server' => 'ldaps://ldap.example.com',
|
||||||
|
// 'ldap_uname' => 'fake_username',
|
||||||
|
'ldap_pword' => Crypt::encrypt("fake_password"),
|
||||||
|
'ldap_basedn' => 'CN=Users,DC=ad,DC=example,Dc=com'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function enableBadPasswordLdap(): Settings
|
||||||
|
{
|
||||||
|
return $this->update([
|
||||||
|
'ldap_enabled' => 1,
|
||||||
|
'ldap_server' => 'ldaps://ldap.example.com',
|
||||||
|
'ldap_uname' => 'fake_username',
|
||||||
|
'ldap_pword' => "badly_encrypted_password!",
|
||||||
|
'ldap_basedn' => 'CN=Users,DC=ad,DC=example,Dc=com'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param array $attributes Attributes to modify in the application's settings.
|
* @param array $attributes Attributes to modify in the application's settings.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -46,7 +46,5 @@ class AssetMaintenanceTest extends TestCase
|
||||||
$this->assertTrue($c->completion_date === null);
|
$this->assertTrue($c->completion_date === null);
|
||||||
$c->completion_date = '0000-00-00';
|
$c->completion_date = '0000-00-00';
|
||||||
$this->assertTrue($c->completion_date === null);
|
$this->assertTrue($c->completion_date === null);
|
||||||
$c->completion_date = '2017-05-12';
|
|
||||||
$this->assertTrue($c->completion_date == Carbon::parse('2017-05-12'));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
210
tests/Unit/LdapTest.php
Normal file
210
tests/Unit/LdapTest.php
Normal file
|
@ -0,0 +1,210 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests\Unit;
|
||||||
|
|
||||||
|
use App\Models\Ldap;
|
||||||
|
use Exception;
|
||||||
|
use Tests\Support\InteractsWithSettings;
|
||||||
|
use Tests\TestCase;
|
||||||
|
|
||||||
|
class LdapTest extends TestCase
|
||||||
|
{
|
||||||
|
use InteractsWithSettings;
|
||||||
|
use \phpmock\phpunit\PHPMock;
|
||||||
|
|
||||||
|
public function testConnect()
|
||||||
|
{
|
||||||
|
$this->settings->enableLdap();
|
||||||
|
|
||||||
|
$ldap_connect = $this->getFunctionMock("App\\Models", "ldap_connect");
|
||||||
|
$ldap_connect->expects($this->once())->willReturn('hello');
|
||||||
|
|
||||||
|
$ldap_set_option = $this->getFunctionMock("App\\Models", "ldap_set_option");
|
||||||
|
$ldap_set_option->expects($this->exactly(3));
|
||||||
|
|
||||||
|
|
||||||
|
$blah = Ldap::connectToLdap();
|
||||||
|
$this->assertEquals('hello',$blah,"LDAP_connect should return 'hello'");
|
||||||
|
}
|
||||||
|
|
||||||
|
// other test cases - with/without client-side certs?
|
||||||
|
// with/without LDAP version 3?
|
||||||
|
// with/without ignore cert validation?
|
||||||
|
// test (and mock) ldap_start_tls() ?
|
||||||
|
|
||||||
|
public function testBindAdmin()
|
||||||
|
{
|
||||||
|
$this->settings->enableLdap();
|
||||||
|
$this->getFunctionMock("App\\Models", "ldap_bind")->expects($this->once())->willReturn(true);
|
||||||
|
$this->assertNull(Ldap::bindAdminToLdap("dummy"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testBindBad()
|
||||||
|
{
|
||||||
|
$this->settings->enableLdap();
|
||||||
|
$this->getFunctionMock("App\\Models", "ldap_bind")->expects($this->once())->willReturn(false);
|
||||||
|
$this->getFunctionMock("App\\Models","ldap_error")->expects($this->once())->willReturn("exception");
|
||||||
|
$this->expectExceptionMessage("Could not bind to LDAP:");
|
||||||
|
|
||||||
|
$this->assertNull(Ldap::bindAdminToLdap("dummy"));
|
||||||
|
}
|
||||||
|
// other test cases - test donked password?
|
||||||
|
|
||||||
|
public function testAnonymousBind()
|
||||||
|
{
|
||||||
|
//todo - would be nice to introspect somehow to make sure the right parameters were passed?
|
||||||
|
$this->settings->enableAnonymousLdap();
|
||||||
|
$this->getFunctionMock("App\\Models", "ldap_bind")->expects($this->once())->willReturn(true);
|
||||||
|
$this->assertNull(Ldap::bindAdminToLdap("dummy"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testBadAnonymousBind()
|
||||||
|
{
|
||||||
|
$this->settings->enableAnonymousLdap();
|
||||||
|
$this->getFunctionMock("App\\Models", "ldap_bind")->expects($this->once())->willReturn(false);
|
||||||
|
$this->getFunctionMock("App\\Models","ldap_error")->expects($this->once())->willReturn("exception");
|
||||||
|
$this->expectExceptionMessage("Could not bind to LDAP:");
|
||||||
|
|
||||||
|
$this->assertNull(Ldap::bindAdminToLdap("dummy"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testBadEncryptedPassword()
|
||||||
|
{
|
||||||
|
$this->settings->enableBadPasswordLdap();
|
||||||
|
|
||||||
|
$this->expectExceptionMessage("Your app key has changed");
|
||||||
|
$this->assertNull(Ldap::bindAdminToLdap("dummy"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testFindAndBind()
|
||||||
|
{
|
||||||
|
$this->settings->enableLdap();
|
||||||
|
|
||||||
|
$ldap_connect = $this->getFunctionMock("App\\Models", "ldap_connect");
|
||||||
|
$ldap_connect->expects($this->once())->willReturn('hello');
|
||||||
|
|
||||||
|
$ldap_set_option = $this->getFunctionMock("App\\Models", "ldap_set_option");
|
||||||
|
$ldap_set_option->expects($this->exactly(3));
|
||||||
|
|
||||||
|
$this->getFunctionMock("App\\Models", "ldap_bind")->expects($this->once())->willReturn(true);
|
||||||
|
|
||||||
|
$this->getFunctionMock("App\\Models", "ldap_search")->expects($this->once())->willReturn(true);
|
||||||
|
|
||||||
|
$this->getFunctionMock("App\\Models", "ldap_first_entry")->expects($this->once())->willReturn(true);
|
||||||
|
|
||||||
|
$this->getFunctionMock("App\\Models", "ldap_get_attributes")->expects($this->once())->willReturn(
|
||||||
|
[
|
||||||
|
"count" => 1,
|
||||||
|
0 => [
|
||||||
|
'sn' => 'Surname',
|
||||||
|
'firstName' => 'FirstName'
|
||||||
|
]
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$results = Ldap::findAndBindUserLdap("username","password");
|
||||||
|
$this->assertEqualsCanonicalizing(["count" =>1,0 =>['sn' => 'Surname','firstname' => 'FirstName']],$results);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testFindAndBindBadPassword()
|
||||||
|
{
|
||||||
|
$this->settings->enableLdap();
|
||||||
|
|
||||||
|
$ldap_connect = $this->getFunctionMock("App\\Models", "ldap_connect");
|
||||||
|
$ldap_connect->expects($this->once())->willReturn('hello');
|
||||||
|
|
||||||
|
$ldap_set_option = $this->getFunctionMock("App\\Models", "ldap_set_option");
|
||||||
|
$ldap_set_option->expects($this->exactly(3));
|
||||||
|
|
||||||
|
// note - we return FALSE first, to simulate a bad-bind, then TRUE the second time to simulate a successful admin bind
|
||||||
|
$this->getFunctionMock("App\\Models", "ldap_bind")->expects($this->exactly(2))->willReturn(false, true);
|
||||||
|
|
||||||
|
// $this->getFunctionMock("App\\Models","ldap_error")->expects($this->once())->willReturn("exception");
|
||||||
|
|
||||||
|
|
||||||
|
// $this->expectExceptionMessage("exception");
|
||||||
|
$results = Ldap::findAndBindUserLdap("username","password");
|
||||||
|
$this->assertFalse($results);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testFindAndBindCannotFindSelf()
|
||||||
|
{
|
||||||
|
$this->settings->enableLdap();
|
||||||
|
|
||||||
|
$ldap_connect = $this->getFunctionMock("App\\Models", "ldap_connect");
|
||||||
|
$ldap_connect->expects($this->once())->willReturn('hello');
|
||||||
|
|
||||||
|
$ldap_set_option = $this->getFunctionMock("App\\Models", "ldap_set_option");
|
||||||
|
$ldap_set_option->expects($this->exactly(3));
|
||||||
|
|
||||||
|
$this->getFunctionMock("App\\Models", "ldap_bind")->expects($this->once())->willReturn(true);
|
||||||
|
|
||||||
|
$this->getFunctionMock("App\\Models", "ldap_search")->expects($this->once())->willReturn(false);
|
||||||
|
|
||||||
|
$this->expectExceptionMessage("Could not search LDAP:");
|
||||||
|
$results = Ldap::findAndBindUserLdap("username","password");
|
||||||
|
$this->assertFalse($results);
|
||||||
|
}
|
||||||
|
|
||||||
|
//maybe should do an AD test as well?
|
||||||
|
|
||||||
|
public function testFindLdapUsers()
|
||||||
|
{
|
||||||
|
$this->settings->enableLdap();
|
||||||
|
|
||||||
|
$ldap_connect = $this->getFunctionMock("App\\Models", "ldap_connect");
|
||||||
|
$ldap_connect->expects($this->once())->willReturn('hello');
|
||||||
|
|
||||||
|
$ldap_set_option = $this->getFunctionMock("App\\Models", "ldap_set_option");
|
||||||
|
$ldap_set_option->expects($this->exactly(3));
|
||||||
|
|
||||||
|
$this->getFunctionMock("App\\Models", "ldap_bind")->expects($this->once())->willReturn(true);
|
||||||
|
|
||||||
|
$this->getFunctionMock("App\\Models", "ldap_search")->expects($this->once())->willReturn(["stuff"]);
|
||||||
|
|
||||||
|
$this->getFunctionMock("App\\Models", "ldap_parse_result")->expects($this->once())->willReturn(true);
|
||||||
|
|
||||||
|
$this->getFunctionMock("App\\Models", "ldap_get_entries")->expects($this->once())->willReturn(["count" => 1]);
|
||||||
|
|
||||||
|
$results = Ldap::findLdapUsers();
|
||||||
|
|
||||||
|
$this->assertEqualsCanonicalizing(["count" => 1], $results);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testFindLdapUsersPaginated()
|
||||||
|
{
|
||||||
|
$this->settings->enableLdap();
|
||||||
|
|
||||||
|
$ldap_connect = $this->getFunctionMock("App\\Models", "ldap_connect");
|
||||||
|
$ldap_connect->expects($this->once())->willReturn('hello');
|
||||||
|
|
||||||
|
$ldap_set_option = $this->getFunctionMock("App\\Models", "ldap_set_option");
|
||||||
|
$ldap_set_option->expects($this->exactly(3));
|
||||||
|
|
||||||
|
$this->getFunctionMock("App\\Models", "ldap_bind")->expects($this->once())->willReturn(true);
|
||||||
|
|
||||||
|
$this->getFunctionMock("App\\Models", "ldap_search")->expects($this->exactly(2))->willReturn(["stuff"]);
|
||||||
|
|
||||||
|
$this->getFunctionMock("App\\Models", "ldap_parse_result")->expects($this->exactly(2))->willReturnCallback(
|
||||||
|
function ($ldapconn, $search_results, $errcode , $matcheddn , $errmsg , $referrals, &$controls) {
|
||||||
|
static $count = 0;
|
||||||
|
if($count == 0) {
|
||||||
|
$count++;
|
||||||
|
$controls[LDAP_CONTROL_PAGEDRESULTS]['value']['cookie'] = "cookie";
|
||||||
|
return ["count" => 1];
|
||||||
|
} else {
|
||||||
|
$controls = [];
|
||||||
|
return ["count" => 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->getFunctionMock("App\\Models", "ldap_get_entries")->expects($this->exactly(2))->willReturn(["count" => 1]);
|
||||||
|
|
||||||
|
$results = Ldap::findLdapUsers();
|
||||||
|
|
||||||
|
$this->assertEqualsCanonicalizing(["count" => 2], $results);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in a new issue