Merge pull request #12849 from snipe/features/adds_license_checkin_checkout_to_all_in_gui

Added license checkin/checkout to all in license GUI
This commit is contained in:
snipe 2023-04-18 12:32:30 -07:00 committed by GitHub
commit bfda46276a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
32 changed files with 480 additions and 129 deletions

View file

@ -20,13 +20,14 @@ class CreateAdmin extends Command
* @property string $password
* @property boolean $activated
* @property boolean $show_in_list
* @property boolean $autoassign_licenses
* @property \Illuminate\Support\Carbon|null $created_at
* @property mixed $created_by
*/
protected $signature = 'snipeit:create-admin {--first_name=} {--last_name=} {--email=} {--username=} {--password=} {show_in_list?}';
protected $signature = 'snipeit:create-admin {--first_name=} {--last_name=} {--email=} {--username=} {--password=} {show_in_list?} {autoassign_licenses?}';
/**
* The console command description.
@ -54,6 +55,9 @@ class CreateAdmin extends Command
$email = $this->option('email');
$password = $this->option('password');
$show_in_list = $this->argument('show_in_list');
$autoassign_licenses = $this->argument('autoassign_licenses');
if (($first_name == '') || ($last_name == '') || ($username == '') || ($email == '') || ($password == '')) {
$this->info('ERROR: All fields are required.');
@ -70,6 +74,11 @@ class CreateAdmin extends Command
if ($show_in_list == 'false') {
$user->show_in_list = 0;
}
if ($autoassign_licenses == 'false') {
$user->autoassign_licenses = 0;
}
if ($user->save()) {
$this->info('New user created');
$user->groups()->attach(1);

View file

@ -71,6 +71,7 @@ class UsersController extends Controller
'users.start_date',
'users.end_date',
'users.vip',
'users.autoassign_licenses',
])->with('manager', 'groups', 'userloc', 'company', 'department', 'assets', 'licenses', 'accessories', 'consumables', 'createdBy',)
->withCount('assets as assets_count', 'licenses as licenses_count', 'accessories as accessories_count', 'consumables as consumables_count');
@ -187,6 +188,10 @@ class UsersController extends Controller
$users->has('accessories', '=', $request->input('accessories_count'));
}
if ($request->filled('autoassign_licenses')) {
$users->where('autoassign_licenses', '=', $request->input('autoassign_licenses'));
}
if ($request->filled('search')) {
$users = $users->TextSearch($request->input('search'));
}
@ -259,6 +264,7 @@ class UsersController extends Controller
'vip',
'start_date',
'end_date',
'autoassign_licenses',
];
$sort = in_array($request->get('sort'), $allowed_columns) ? $request->get('sort') : 'first_name';
@ -356,7 +362,7 @@ class UsersController extends Controller
$user->permissions = $permissions_array;
}
$tmp_pass = substr(str_shuffle('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'), 0, 20);
$tmp_pass = substr(str_shuffle('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'), 0, 40);
$user->password = bcrypt($request->get('password', $tmp_pass));
app('App\Http\Requests\ImageUploadRequest')->handleImages($user, 600, 'image', 'avatars', 'avatar');

View file

@ -112,4 +112,54 @@ class LicenseCheckinController extends Controller
// Redirect to the license page with error
return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.checkin.error'));
}
/**
* Bulk checkin all license seats
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @see LicenseCheckinController::create() method that provides the form view
* @since [v6.1.1]
* @return \Illuminate\Http\RedirectResponse
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function bulkCheckin(Request $request, $licenseId) {
$license = License::findOrFail($licenseId);
$this->authorize('checkin', $license);
$licenseSeatsByUser = LicenseSeat::where('license_id', '=', $licenseId)
->whereNotNull('assigned_to')
->with('user')
->get();
foreach ($licenseSeatsByUser as $user_seat) {
$user_seat->assigned_to = null;
if ($user_seat->save()) {
\Log::debug('Checking in '.$license->name.' from user '.$user_seat->username);
$user_seat->logCheckin($user_seat->user, trans('admin/licenses/general.bulk.checkin_all.log_msg'));
}
}
$licenseSeatsByAsset = LicenseSeat::where('license_id', '=', $licenseId)
->whereNotNull('asset_id')
->with('asset')
->get();
$count = 0;
foreach ($licenseSeatsByAsset as $asset_seat) {
$asset_seat->asset_id = null;
if ($asset_seat->save()) {
\Log::debug('Checking in '.$license->name.' from asset '.$asset_seat->asset_tag);
$asset_seat->logCheckin($asset_seat->asset, trans('admin/licenses/general.bulk.checkin_all.log_msg'));
$count++;
}
}
return redirect()->back()->with('success', trans_choice('admin/licenses/general.bulk.checkin_all.success', 2, ['count' => $count] ));
}
}

View file

@ -126,4 +126,70 @@ class LicenseCheckoutController extends Controller
return false;
}
/**
* Bulk checkin all license seats
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @see LicenseCheckinController::create() method that provides the form view
* @since [v6.1.1]
* @return \Illuminate\Http\RedirectResponse
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function bulkCheckout($licenseId) {
\Log::debug('Checking out '.$licenseId.' via bulk');
$license = License::findOrFail($licenseId);
$this->authorize('checkin', $license);
$avail_count = $license->getAvailSeatsCountAttribute();
$users = User::whereNull('deleted_at')->where('autoassign_licenses', '=', 1)->with('licenses')->get();
\Log::debug($avail_count.' will be assigned');
if ($users->count() > $avail_count) {
\Log::debug('You do not have enough free seats to complete this task, so we will check out as many as we can. ');
}
// If the license is valid, check that there is an available seat
if ($license->availCount()->count() < 1) {
return redirect()->back()->with('error', trans('admin/licenses/general.bulk.checkout_all.error_no_seats'));
}
$assigned_count = 0;
foreach ($users as $user) {
// Check to make sure this user doesn't already have this license checked out to them
if ($user->licenses->where('id', '=', $licenseId)->count()) {
\Log::debug($user->username.' already has this license checked out to them. Skipping... ');
continue;
}
$licenseSeat = $license->freeSeat();
// Update the seat with checkout info
$licenseSeat->assigned_to = $user->id;
if ($licenseSeat->save()) {
$avail_count--;
$assigned_count++;
$licenseSeat->logCheckout(trans('admin/licenses/general.bulk.checkout_all.log_msg'), $user);
\Log::debug('License '.$license->name.' seat '.$licenseSeat->id.' checked out to '.$user->username);
}
if ($avail_count == 0) {
return redirect()->back()->with('warning', trans('admin/licenses/general.bulk.checkout_all.warn_not_enough_seats', ['count' => $assigned_count]));
}
}
if ($assigned_count == 0) {
return redirect()->back()->with('warning', trans('admin/licenses/general.bulk.checkout_all.warn_no_avail_users', ['count' => $assigned_count]));
}
return redirect()->back()->with('success', trans_choice('admin/licenses/general.bulk.checkout_all.success', 2, ['count' => $assigned_count] ));
}
}

View file

@ -6,6 +6,8 @@ use App\Helpers\Helper;
use App\Http\Controllers\Controller;
use App\Models\Company;
use App\Models\License;
use App\Models\LicenseSeat;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
@ -232,17 +234,39 @@ class LicensesController extends Controller
public function show($licenseId = null)
{
$license = License::with('assignedusers')->find($licenseId);
$users_count = User::where('autoassign_licenses', '1')->count();
$total_seats_count = $license->totalSeatsByLicenseID();
$available_seats_count = $license->availCount()->count();
$checkedout_seats_count = ($total_seats_count - $available_seats_count);
\Log::debug('Total: '.$total_seats_count);
\Log::debug('Users: '.$users_count);
\Log::debug('Available: '.$available_seats_count);
\Log::debug('Checkedout: '.$checkedout_seats_count);
if ($license) {
$this->authorize('view', $license);
return view('licenses/view', compact('license'));
return view('licenses.view', compact('license'))
->with('users_count', $users_count)
->with('total_seats_count', $total_seats_count)
->with('available_seats_count', $available_seats_count)
->with('checkedout_seats_count', $checkedout_seats_count);
}
return redirect()->route('licenses.index')
return redirect()->route('licenses.view')
->with('error', trans('admin/licenses/message.does_not_exist'));
}
/**
* Returns a view with prepopulated data for clone
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @param int $licenseId
* @return \Illuminate\Http\RedirectResponse
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function getClone($licenseId = null)
{
if (is_null($license_to_clone = License::find($licenseId))) {

View file

@ -113,7 +113,8 @@ class BulkUsersController extends Controller
->conditionallyAddItem('locale')
->conditionallyAddItem('remote')
->conditionallyAddItem('ldap_import')
->conditionallyAddItem('activated');
->conditionallyAddItem('activated')
->conditionallyAddItem('autoassign_licenses');
// If the manager_id is one of the users being updated, generate a warning.

View file

@ -120,7 +120,7 @@ class UsersController extends Controller
$user->created_by = Auth::user()->id;
$user->start_date = $request->input('start_date', null);
$user->end_date = $request->input('end_date', null);
$user->autoassign_licenses= $request->input('autoassign_licenses', 1);
$user->autoassign_licenses = $request->input('autoassign_licenses', 0);
// Strip out the superuser permission if the user isn't a superadmin
$permissions_array = $request->input('permission');
@ -275,7 +275,7 @@ class UsersController extends Controller
$user->website = $request->input('website', null);
$user->start_date = $request->input('start_date', null);
$user->end_date = $request->input('end_date', null);
$user->autoassign_licenses = $request->input('autoassign_licenses', 1);
$user->autoassign_licenses = $request->input('autoassign_licenses', 0);
// Update the location of any assets checked out to this user
Asset::where('assigned_type', User::class)

View file

@ -56,7 +56,7 @@ class LicensesTransformer
'checkin' => Gate::allows('checkin', License::class),
'clone' => Gate::allows('create', License::class),
'update' => Gate::allows('update', License::class),
'delete' => Gate::allows('delete', License::class),
'delete' => (Gate::allows('delete', License::class) && ($license->seats == $license->availCount()->count())) ? true : false,
];
$array += $permissions_array;

View file

@ -56,6 +56,7 @@ class UsersTransformer
'notes'=> e($user->notes),
'permissions' => $user->decodePermissions(),
'activated' => ($user->activated == '1') ? true : false,
'autoassign_licenses' => ($user->autoassign_licenses == '1') ? true : false,
'ldap_import' => ($user->ldap_import == '1') ? true : false,
'two_factor_enrolled' => ($user->two_factor_active_and_enrolled()) ? true : false,
'two_factor_optin' => ($user->two_factor_active()) ? true : false,

View file

@ -58,7 +58,8 @@ class UserImporter extends ItemImporter
$this->item['department_id'] = $this->createOrFetchDepartment($this->findCsvMatch($row, 'department'));
$this->item['manager_id'] = $this->fetchManager($this->findCsvMatch($row, 'manager_first_name'), $this->findCsvMatch($row, 'manager_last_name'));
$this->item['remote'] =($this->fetchHumanBoolean($this->findCsvMatch($row, 'remote')) ==1 ) ? '1' : 0;
$this->item['vip'] =($this->fetchHumanBoolean($this->findCsvMatch($row, 'vip')) ==1 ) ? '1' : 0;
$this->item['vip'] = ($this->fetchHumanBoolean($this->findCsvMatch($row, 'vip')) ==1 ) ? '1' : 0;
$this->item['autoassign_licenses'] = ($this->fetchHumanBoolean($this->findCsvMatch($row, 'autoassign_licenses')) ==1 ) ? '1' : 0;
$user_department = $this->findCsvMatch($row, 'department');

View file

@ -106,10 +106,10 @@ class License extends Depreciable
* @var array
*/
protected $searchableRelations = [
'manufacturer' => ['name'],
'company' => ['name'],
'category' => ['name'],
'depreciation' => ['name'],
'manufacturer' => ['name'],
'company' => ['name'],
'category' => ['name'],
'depreciation' => ['name'],
];
/**
@ -425,7 +425,7 @@ class License extends Depreciable
public static function assetcount()
{
return LicenseSeat::whereNull('deleted_at')
->count();
->count();
}
@ -441,8 +441,8 @@ class License extends Depreciable
public function totalSeatsByLicenseID()
{
return LicenseSeat::where('license_id', '=', $this->id)
->whereNull('deleted_at')
->count();
->whereNull('deleted_at')
->count();
}
/**
@ -486,11 +486,12 @@ class License extends Depreciable
public static function availassetcount()
{
return LicenseSeat::whereNull('assigned_to')
->whereNull('asset_id')
->whereNull('deleted_at')
->count();
->whereNull('asset_id')
->whereNull('deleted_at')
->count();
}
/**
* Returns the number of total available seats for this license
*
@ -533,7 +534,7 @@ class License extends Depreciable
{
return $this->licenseSeatsRelation()->where(function ($query) {
$query->whereNotNull('assigned_to')
->orWhereNotNull('asset_id');
->orWhereNotNull('asset_id');
});
}
@ -621,13 +622,13 @@ class License extends Depreciable
public function freeSeat()
{
return $this->licenseseats()
->whereNull('deleted_at')
->where(function ($query) {
$query->whereNull('assigned_to')
->whereNull('asset_id');
})
->orderBy('id', 'asc')
->first();
->whereNull('deleted_at')
->where(function ($query) {
$query->whereNull('assigned_to')
->whereNull('asset_id');
})
->orderBy('id', 'asc')
->first();
}
@ -657,11 +658,11 @@ class License extends Depreciable
$days = (is_null($days)) ? 60 : $days;
return self::whereNotNull('expiration_date')
->whereNull('deleted_at')
->whereRaw(DB::raw('DATE_SUB(`expiration_date`,INTERVAL '.$days.' DAY) <= DATE(NOW()) '))
->where('expiration_date', '>', date('Y-m-d'))
->orderBy('expiration_date', 'ASC')
->get();
->whereNull('deleted_at')
->whereRaw(DB::raw('DATE_SUB(`expiration_date`,INTERVAL '.$days.' DAY) <= DATE(NOW()) '))
->where('expiration_date', '>', date('Y-m-d'))
->orderBy('expiration_date', 'ASC')
->get();
}
/**
@ -705,4 +706,4 @@ class License extends Depreciable
return $query->leftJoin('companies as companies', 'licenses.company_id', '=', 'companies.id')->select('licenses.*')
->orderBy('companies.name', $order);
}
}
}

View file

@ -78,24 +78,7 @@ class Supplier extends SnipeModel
{
return $this->hasMany(Asset::class)->whereNull('deleted_at')->selectRaw('supplier_id, count(*) as count')->groupBy('supplier_id');
}
/**
* Sets the license seat count attribute
*
* @todo I don't see the licenseSeatsRelation here?
*
* @author A. Gianotto <snipe@snipe.net>
* @since [v1.0]
* @return \Illuminate\Database\Eloquent\Relations\Relation
*/
public function getLicenseSeatsCountAttribute()
{
if ($this->licenseSeatsRelation->first()) {
return $this->licenseSeatsRelation->first()->count;
}
return 0;
}
/**
* Establishes the supplier -> assets relationship

View file

@ -65,6 +65,7 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
'avatar',
'gravatar',
'vip',
'autoassign_licenses',
];
protected $casts = [
@ -76,6 +77,7 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
'created_at' => 'datetime',
'updated_at' => 'datetime',
'deleted_at' => 'datetime',
'autoassign_licenses' => 'boolean',
];
/**
@ -95,6 +97,7 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
'location_id' => 'exists:locations,id|nullable',
'start_date' => 'nullable|date_format:Y-m-d',
'end_date' => 'nullable|date_format:Y-m-d|after_or_equal:start_date',
'autoassign_licenses' => 'boolean',
];
/**

View file

@ -33,7 +33,7 @@ class LicensePresenter extends Presenter
'field' => 'name',
'searchable' => true,
'sortable' => true,
'title' => trans('admin/licenses/table.title'),
'title' => trans('general.name'),
'formatter' => 'licensesLinkFormatter',
], [
'field' => 'product_key',

View file

@ -294,6 +294,15 @@ class UserPresenter extends Presenter
'visible' => true,
'formatter' => 'trueFalseFormatter',
],
[
'field' => 'autoassign_licenses',
'searchable' => false,
'sortable' => true,
'switchable' => true,
'title' => trans('general.autoassign_licenses'),
'visible' => false,
'formatter' => 'trueFalseFormatter',
],
[
'field' => 'created_by',
'searchable' => false,

View file

@ -1,8 +1,8 @@
<?php
return array(
'about_licenses_title' => 'About Licenses',
'about_licenses' => 'Licenses are used to track software. They have a specified number of seats that can be checked out to individuals',
'about_licenses_title' => 'About Licenses',
'about_licenses' => 'Licenses are used to track software. They have a specified number of seats that can be checked out to individuals',
'checkin' => 'Checkin License Seat',
'checkout_history' => 'Checkout History',
'checkout' => 'Checkout License Seat',
@ -18,4 +18,30 @@ return array(
'software_licenses' => 'Software Licenses',
'user' => 'User',
'view' => 'View License',
'delete_disabled' => 'This license cannot be deleted yet because some seats are still checked out.',
'bulk' =>
[
'checkin_all' => [
'button' => 'Checkin All Seats',
'modal' => 'This will action checkin one seat. | This action will checkin all :checkedout_seats_count seats for this license.',
'enabled_tooltip' => 'Checkin ALL seats for this license from both users and assets',
'disabled_tooltip' => 'This is disabled because there are no seats currently checked out',
'success' => 'License successfully checked in! | All licenses were successfully checked in!',
'log_msg' => 'Checked in via bulk license checkout in license GUI',
],
'checkout_all' => [
'button' => 'Checkout All Seats',
'modal' => 'This action will checkout one seat to the first available user. | This action will checkout all :available_seats_count seats to the first available users. A user is considered available for this seat if they do not already have this license checked out to them, and the Auto-Assign License property is enabled on their user account.',
'enabled_tooltip' => 'Checkout ALL seats (or as many as are available) to ALL users',
'disabled_tooltip' => 'This is disabled because there are no seats currently available',
'success' => 'License successfully checked out! | :count licenses were successfully checked out!',
'error_no_seats' => 'There are no remaining seats left for this license.',
'warn_not_enough_seats' => ':count users were assigned this license, but we ran out of available license seats.',
'warn_no_avail_users' => 'Nothing to do. There are no users who do not already have this license assigned to them.',
'log_msg' => 'Checked out via bulk license checkout in license GUI',
],
],
);

View file

@ -439,4 +439,12 @@ return [
'setup_migration_output' => 'Migration output:',
'setup_migration_create_user' => 'Next: Create User',
'importer_generic_error' => 'Your file import is complete, but we did receive an error. This is usually caused by third-party API throttling from a notification webhook (such as Slack) and would not have interfered with the import itself, but you should confirm this.',
'confirm' => 'Confirm',
'autoassign_licenses' => 'Auto-Assign Licenses',
'autoassign_licenses_help' => 'Allow user to be have licenses assigned via the bulk-assign license UI or cli tools.',
'autoassign_licenses_help_long' => 'This allows a user to be have licenses assigned via the bulk-assign license UI or cli tools. (For example, you might not want contractors to be auto-assigned a license you would provide to only staff members. You can still individually assign licenses to those users, but they will not be included in the Checkout License to All Users functions.)',
'no_autoassign_licenses_help' => 'Do not include user for bulk-assigning through the license UI or cli tools.',
'modal_confirm_generic' => 'Are you sure?',
'cannot_be_deleted' => 'This item cannot be deleted',
];

View file

@ -21,7 +21,7 @@
<h2 class="box-title">{{ trans('admin/custom_fields/general.fieldsets') }}</h2>
<div class="box-tools pull-right">
@can('create', \App\Models\CustomFieldset::class)
<a href="{{ route('fieldsets.create') }}" class="btn btn-sm btn-primary" data-toggle="tooltip" title="{{ trans('admin/custom_fields/general.create_fieldset_title') }}">{{ trans('admin/custom_fields/general.create_fieldset') }}</a>
<a href="{{ route('fieldsets.create') }}" class="btn btn-sm btn-primary" data-tooltip="true" title="{{ trans('admin/custom_fields/general.create_fieldset_title') }}">{{ trans('admin/custom_fields/general.create_fieldset') }}</a>
@endcan
</div>
</div><!-- /.box-header -->
@ -111,7 +111,7 @@
<h2 class="box-title">{{ trans('admin/custom_fields/general.custom_fields') }}</h2>
<div class="box-tools pull-right">
@can('create', \App\Models\CustomField::class)
<a href="{{ route('fields.create') }}" class="btn btn-sm btn-primary" data-toggle="tooltip" title="{{ trans('admin/custom_fields/general.create_field_title') }}">{{ trans('admin/custom_fields/general.create_field') }}</a>
<a href="{{ route('fields.create') }}" class="btn btn-sm btn-primary" data-tooltip="true" title="{{ trans('admin/custom_fields/general.create_field_title') }}">{{ trans('admin/custom_fields/general.create_field') }}</a>
@endcan
</div>

View file

@ -77,7 +77,7 @@
<tbody class="permissions-group">
<tr class="header-row permissions-row">
<td class="col-md-5 tooltip-base permissions-item"
data-toggle="tooltip"
data-tooltip="true"
data-placement="right"
title="{{ $localPermission['note'] }}">
@unless (empty($localPermission['label']))
@ -100,7 +100,7 @@
<tbody class="permission-group">
<tr class="header-row permissions-row">
<td class="col-md-5 tooltip-base permissions-item header-name"
data-toggle="tooltip"
data-tooltip="true"
data-placement="right"
title="{{ $localPermission['note'] }}">
<h2>{{ $area }}</h2>
@ -122,7 +122,7 @@
<tr class="permissions-row">
<td
class="col-md-5 tooltip-base permissions-item"
data-toggle="tooltip"
data-tooltip="true"
data-placement="right"
title="{{ $this_permission['note'] }}">
{{ $this_permission['label'] }}

View file

@ -456,7 +456,7 @@
</div>
<div class="col-md-6{{ (($field->format=='URL') && ($asset->{$field->db_column_name()}!='')) ? ' ellipsis': '' }}">
@if ($field->field_encrypted=='1')
<i class="fas fa-lock" data-toggle="tooltip" data-placement="top" title="{{ trans('admin/custom_fields/general.value_encrypted') }}"></i>
<i class="fas fa-lock" data-tooltip="true" data-placement="top" title="{{ trans('admin/custom_fields/general.value_encrypted') }}"></i>
@endif
@if ($field->isFieldDecryptable($asset->{$field->db_column_name()} ))

View file

@ -974,7 +974,7 @@
$(function () {
$('[data-toggle="tooltip"]').tooltip();
$('[data-tooltip="true"]').tooltip();
$('[data-toggle="popover"]').popover();
$('.select2 span').addClass('needsclick');
$('.select2 span').removeAttr('title');

View file

@ -10,7 +10,7 @@
{{-- Page content --}}
@section('content')
<div class="row">
<div class="col-md-12">
<div class="col-md-9">
<!-- Custom Tabs -->
<div class="nav-tabs-custom">
@ -56,21 +56,7 @@
<span class="hidden-xs hidden-sm">{{ trans('general.history') }}</span>
</a>
</li>
@can('update', $license)
<li class="dropdown pull-right">
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
<i class="fas fa-cog" aria-hidden="true"></i> {{ trans('button.actions') }}
<span class="caret"></span>
</a>
<ul class="dropdown-menu">
<li><a href="{{ route('licenses.edit', $license->id) }}">{{ trans('admin/licenses/general.edit') }}</a></li>
<li><a href="{{ route('clone/license', $license->id) }}">{{ trans('admin/licenses/general.clone') }}</a></li>
</ul>
</li>
@endcan
@can('update', \App\Models\License::class)
<li class="pull-right"><a href="#" data-toggle="modal" data-target="#uploadFileModal">
<i class="fas fa-paperclip" aria-hidden="true"></i> {{ trans('button.upload') }}</a>
@ -332,7 +318,7 @@
</strong>
</div>
<div class="col-md-9">
{!! $license->maintained ? '<i class="fas fa-check text-success" aria-hidden="true"></i> '.trans('general.yes') : '<i class="fas fa-times text-danger" aria-hidden="true"></i> '.trans('general.no') !!}
{!! $license->maintained ? '<i class="fas fa-check fa-fw text-success" aria-hidden="true"></i> '.trans('general.yes') : '<i class="fas fa-times fa-fw text-danger" aria-hidden="true"></i> '.trans('general.no') !!}
</div>
</div>
@ -358,7 +344,7 @@
</strong>
</div>
<div class="col-md-9">
{!! $license->reassignable ? '<i class="fas fa-check text-success" aria-hidden="true"></i> '.trans('general.yes') : '<i class="fas fa-times text-danger" aria-hidden="true"></i> '.trans('general.no') !!}
{!! $license->reassignable ? '<i class="fas fa-check fa-fw text-success" aria-hidden="true"></i> '.trans('general.yes') : '<i class="fas fa-times fa-fw text-danger" aria-hidden="true"></i> '.trans('general.no') !!}
</div>
</div>
@ -378,8 +364,10 @@
</div> <!-- end row-striped -->
</div>
</div>
</div> <!-- end tab-pane -->
</div>
</div> <!-- end tab-pane -->
@ -550,13 +538,100 @@
</table>
</div>
</div> <!-- /.col-md-12-->
</div> <!-- /.row-->
</div> <!-- /.tab-pane -->
</div> <!-- /.tab-content -->
</div> <!-- nav-tabs-custom -->
</div> <!-- /.col -->
<div class="col-md-3">
@can('update', $license)
<a href="{{ route('licenses.edit', $license->id) }}" class="btn btn-block btn-primary" style="margin-bottom: 10px;">{{ trans('admin/licenses/general.edit') }}</a>
<a href="{{ route('clone/license', $license->id) }}" class="btn btn-block btn-primary" style="margin-bottom: 10px;">{{ trans('admin/licenses/general.clone') }}</a>
@endcan
@can('checkout', $license)
@if ($license->availCount()->count() > 0)
<a href="{{ route('licenses.checkout', $license->id) }}" class="btn-block btn bg-maroon" style="margin-bottom: 10px;">
{{ trans('general.checkout') }}
</a>
<a href="#" class="btn-block btn bg-maroon" style="margin-bottom: 10px;" data-toggle="modal" data-tooltip="true" title="{{ trans('admin/licenses/general.bulk.checkout_all.enabled_tooltip') }}" data-target="#checkoutFromAllModal">
{{ trans('admin/licenses/general.bulk.checkout_all.button') }}
</a>
@else
<a href="{{ route('licenses.checkout', $license->id) }}" class="btn btn-block bg-maroon disabled" style="margin-bottom: 10px;">
{{ trans('general.checkout') }}
</a>
<span data-tooltip="true" title=" {{ trans('admin/licenses/general.bulk.checkout_all.disabled_tooltip') }}">
<a href="#" class="btn btn-block bg-maroon disabled" style="margin-bottom: 10px;" data-tooltip="true" title="{{ trans('general.checkout') }}">
{{ trans('admin/licenses/general.bulk.checkout_all.button') }}
</a>
</span>
@endif
@endcan
@can('checkin', $license)
@if (($license->seats - $license->availCount()->count()) > 0 )
<a href="#" class="btn btn-block bg-purple" style="margin-bottom: 25px;" data-toggle="modal" data-tooltip="true" data-target="#checkinFromAllModal" data-content="{{ trans('general.sure_to_delete') }} data-title="{{ trans('general.delete') }}" onClick="return false;">
{{ trans('admin/licenses/general.bulk.checkin_all.button') }}
</a>
@else
<span data-tooltip="true" title=" {{ trans('admin/licenses/general.bulk.checkin_all.disabled_tooltip') }}">
<a href="#" class="btn btn-block bg-purple disabled" style="margin-bottom: 25px;">
{{ trans('admin/licenses/general.bulk.checkin_all.button') }}
</a>
</span>
@endif
@endcan
@can('delete', $license)
@if ($license->availCount()->count() == $license->seats)
<button class="btn btn-block btn-danger delete-asset" data-toggle="modal" data-title="{{ trans('general.delete') }}" data-content="{{ trans('general.delete_confirm', ['item' => $license->name]) }}" data-target="#dataConfirmModal">
{{ trans('general.delete') }}
</button>
@else
<span data-tooltip="true" title=" {{ trans('admin/licenses/general.delete_disabled') }}">
<a href="#" class="btn btn-block btn-danger disabled">
{{ trans('general.delete') }}
</a>
</span>
@endif
@endcan
</div>
</div> <!-- /.row -->
@can('checkin', \App\Models\License::class)
@include ('modals.confirm-action',
[
'modal_name' => 'checkinFromAllModal',
'route' => route('licenses.bulkcheckin', $license->id),
'title' => trans('general.modal_confirm_generic'),
'body' => trans_choice('admin/licenses/general.bulk.checkin_all.modal', 2, ['checkedout_seats_count' => $checkedout_seats_count])
])
@endcan
@can('checkout', \App\Models\License::class)
@include ('modals.confirm-action',
[
'modal_name' => 'checkoutFromAllModal',
'route' => route('licenses.bulkcheckout', $license->id),
'title' => trans('general.modal_confirm_generic'),
'body' => trans_choice('admin/licenses/general.bulk.checkout_all.modal', 2, ['available_seats_count' => $available_seats_count])
])
@endcan
@can('update', \App\Models\License::class)
@include ('modals.upload-file', ['item_type' => 'license', 'item_id' => $license->id])
@endcan
@ -565,5 +640,15 @@
@section('moar_scripts')
<script>
$('#dataConfirmModal').on('show.bs.modal', function (event) {
var content = $(event.relatedTarget).data('content');
var title = $(event.relatedTarget).data('title');
$(this).find(".modal-body").text(content);
$(this).find(".modal-header").text(title);
});
</script>
@include ('partials.bootstrap-table')
@stop

View file

@ -0,0 +1,27 @@
<!-- Modal -->
<div class="modal fade" id="{{ $modal_name }}" tabindex="-1" role="dialog" aria-labelledby="{{ $modal_name }}Label" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title" id="{{ $modal_name }}Label">{{ $title }}</h4>
</div>
<form action="{{ $route }}" method="POST" class="form-horizontal">
<input type="hidden" name="_token" value="{{ csrf_token() }}" />
<div class="modal-body">
<div class="row">
<div class="col-md-12">
{{ $body }}
</div>
</div>
</div> <!-- /.modal-body-->
<div class="modal-footer">
<a href="#" class="pull-left" data-dismiss="modal">{{ trans('button.cancel') }}</a>
<button type="submit" class="btn btn-primary">{{ trans('general.confirm') }}</button>
</div>
</form>
</div>
</div>
</div>

View file

@ -4,7 +4,7 @@
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h2 class="modal-title" id="uploadFileModalLabel">{{ trans('general.file_upload') }}</h4>
<h4 class="modal-title" id="uploadFileModalLabel">{{ trans('general.file_upload') }}</h4>
</div>
{{ Form::open([
'method' => 'POST',

View file

@ -77,7 +77,7 @@
@if ($field->field_encrypted)
<div class="col-md-1 col-sm-1 text-left">
<i class="fas fa-lock" data-toggle="tooltip" data-placement="top" title="{{ trans('admin/custom_fields/general.value_encrypted') }}"></i>
<i class="fas fa-lock" data-tooltip="true" data-placement="top" title="{{ trans('admin/custom_fields/general.value_encrypted') }}"></i>
</div>
@endif

View file

@ -94,7 +94,7 @@
exportTypes: ['xlsx', 'excel', 'csv', 'pdf','json', 'xml', 'txt', 'sql', 'doc' ],
onLoadSuccess: function () {
$('[data-toggle="tooltip"]').tooltip(); // Needed to attach tooltips after ajax call
$('[data-tooltip="true"]').tooltip(); // Needed to attach tooltips after ajax call
}
});
@ -215,7 +215,7 @@
text_help = '';
}
return '<nobr><a href="{{ config('app.url') }}/' + destination + '/' + value.id + '" data-toggle="tooltip" title="'+ status_meta[value.status_meta] + '"> <i class="fa ' + icon_style + ' text-' + text_color + '"></i> ' + value.name + ' ' + text_help + ' </a> </nobr>';
return '<nobr><a href="{{ config('app.url') }}/' + destination + '/' + value.id + '" data-tooltip="true" title="'+ status_meta[value.status_meta] + '"> <i class="fa ' + icon_style + ' text-' + text_color + '"></i> ' + value.name + ' ' + text_help + ' </a> </nobr>';
} else if ((value) && (value.name)) {
// Add some overrides for any funny urls we have
@ -270,20 +270,20 @@
if ((row.available_actions) && (row.available_actions.delete === true)) {
actions += '<a href="{{ config('app.url') }}/' + dest + '/' + row.id + '" '
+ ' class="btn btn-danger btn-sm delete-asset" data-toggle="tooltip" '
+ ' class="btn btn-danger btn-sm delete-asset" data-tooltip="true" '
+ ' data-toggle="modal" '
+ ' data-content="{{ trans('general.sure_to_delete') }} ' + row.name + '?" '
+ ' data-title="{{ trans('general.delete') }}" onClick="return false;">'
+ '<i class="fas fa-trash" aria-hidden="true"></i><span class="sr-only">Delete</span></a>&nbsp;';
} else {
actions += '<a class="btn btn-danger btn-sm delete-asset disabled" onClick="return false;"><i class="fas fa-trash"></i></a>&nbsp;';
actions += '<span data-tooltip="true" title="{{ trans('general.cannot_be_deleted') }}"><a class="btn btn-danger btn-sm delete-asset disabled" onClick="return false;"><i class="fas fa-trash"></i></a></span>&nbsp;';
}
if ((row.available_actions) && (row.available_actions.restore === true)) {
actions += '<form style="display: inline;" method="POST" action="{{ config('app.url') }}/' + dest + '/' + row.id + '/restore"> ';
actions += '@csrf';
actions += '<button class="btn btn-sm btn-warning" data-toggle="tooltip" title="{{ trans('general.restore') }}"><i class="fas fa-retweet"></i></button>&nbsp;';
actions += '<button class="btn btn-sm btn-warning" data-tooltip="true" title="{{ trans('general.restore') }}"><i class="fas fa-retweet"></i></button>&nbsp;';
}
actions +='</nobr>';
@ -364,9 +364,9 @@
function licenseSeatInOutFormatter(value, row) {
// The user is allowed to check the license seat out and it's available
if ((row.available_actions.checkout == true) && (row.user_can_checkout == true) && ((!row.asset_id) && (!row.assigned_to))) {
return '<a href="{{ config('app.url') }}/licenses/' + row.license_id + '/checkout/'+row.id+'" class="btn btn-sm bg-maroon" data-toggle="tooltip" title="{{ trans('general.checkout_tooltip') }}">{{ trans('general.checkout') }}</a>';
return '<a href="{{ config('app.url') }}/licenses/' + row.license_id + '/checkout/'+row.id+'" class="btn btn-sm bg-maroon" data-tooltip="true" title="{{ trans('general.checkout_tooltip') }}">{{ trans('general.checkout') }}</a>';
} else {
return '<a href="{{ config('app.url') }}/licenses/' + row.id + '/checkin" class="btn btn-sm bg-purple" data-toggle="tooltip" title="Check in this license seat.">{{ trans('general.checkin') }}</a>';
return '<a href="{{ config('app.url') }}/licenses/' + row.id + '/checkin" class="btn btn-sm bg-purple" data-tooltip="true" title="Check in this license seat.">{{ trans('general.checkin') }}</a>';
}
}
@ -376,18 +376,18 @@
// The user is allowed to check items out, AND the item is deployable
if ((row.available_actions.checkout == true) && (row.user_can_checkout == true) && ((!row.asset_id) && (!row.assigned_to))) {
return '<a href="{{ config('app.url') }}/' + destination + '/' + row.id + '/checkout" class="btn btn-sm bg-maroon" data-toggle="tooltip" title="{{ trans('general.checkout_tooltip') }}">{{ trans('general.checkout') }}</a>';
return '<a href="{{ config('app.url') }}/' + destination + '/' + row.id + '/checkout" class="btn btn-sm bg-maroon" data-tooltip="true" title="{{ trans('general.checkout_tooltip') }}">{{ trans('general.checkout') }}</a>';
// The user is allowed to check items out, but the item is not deployable
} else if (((row.user_can_checkout == false)) && (row.available_actions.checkout == true) && (!row.assigned_to)) {
return '<div data-toggle="tooltip" title="This item has a status label that is undeployable and cannot be checked out at this time."><a class="btn btn-sm bg-maroon disabled">{{ trans('general.checkout') }}</a></div>';
return '<span data-tooltip="true" title="This item has a status label that is undeployable and cannot be checked out at this time."><a class="btn btn-sm bg-maroon disabled">{{ trans('general.checkout') }}</a></span>';
// The user is allowed to check items in
} else if (row.available_actions.checkin == true) {
if (row.assigned_to) {
return '<a href="{{ config('app.url') }}/' + destination + '/' + row.id + '/checkin" class="btn btn-sm bg-purple" data-toggle="tooltip" title="Check this item in so it is available for re-imaging, re-issue, etc.">{{ trans('general.checkin') }}</a>';
return '<a href="{{ config('app.url') }}/' + destination + '/' + row.id + '/checkin" class="btn btn-sm bg-purple" data-tooltip="true" title="Check this item in so it is available for re-imaging, re-issue, etc.">{{ trans('general.checkin') }}</a>';
} else if (row.assigned_pivot_id) {
return '<a href="{{ config('app.url') }}/' + destination + '/' + row.assigned_pivot_id + '/checkin" class="btn btn-sm bg-purple" data-toggle="tooltip" title="Check this item in so it is available for re-imaging, re-issue, etc.">{{ trans('general.checkin') }}</a>';
return '<a href="{{ config('app.url') }}/' + destination + '/' + row.assigned_pivot_id + '/checkin" class="btn btn-sm bg-purple" data-tooltip="true" title="Check this item in so it is available for re-imaging, re-issue, etc.">{{ trans('general.checkin') }}</a>';
}
}
@ -401,11 +401,11 @@
// This is only used by the requestable assets section
function assetRequestActionsFormatter (row, value) {
if (value.assigned_to_self == true){
return '<button class="btn btn-danger btn-sm disabled" data-toggle="tooltip" title="Cancel this item request">{{ trans('button.cancel') }}</button>';
return '<button class="btn btn-danger btn-sm disabled" data-tooltip="true" title="Cancel this item request">{{ trans('button.cancel') }}</button>';
} else if (value.available_actions.cancel == true) {
return '<form action="{{ config('app.url') }}/account/request-asset/'+ value.id + '" method="POST">@csrf<button class="btn btn-danger btn-sm" data-toggle="tooltip" title="Cancel this item request">{{ trans('button.cancel') }}</button></form>';
return '<form action="{{ config('app.url') }}/account/request-asset/'+ value.id + '" method="POST">@csrf<button class="btn btn-danger btn-sm" data-tooltip="true" title="Cancel this item request">{{ trans('button.cancel') }}</button></form>';
} else if (value.available_actions.request == true) {
return '<form action="{{ config('app.url') }}/account/request-asset/'+ value.id + '" method="POST">@csrf<button class="btn btn-primary btn-sm" data-toggle="tooltip" title="Request this item">{{ trans('button.request') }}</button></form>';
return '<form action="{{ config('app.url') }}/account/request-asset/'+ value.id + '" method="POST">@csrf<button class="btn btn-primary btn-sm" data-tooltip="true" title="Request this item">{{ trans('button.request') }}</button></form>';
}
}
@ -537,7 +537,7 @@
if ((row) && (row!=undefined)) {
return '<a href="{{ config('app.url') }}/locations/' + row.id + '">' + row.name + '</a>';
} else if (value.rtd_location) {
return '<a href="{{ config('app.url') }}/locations/' + value.rtd_location.id + '" data-toggle="tooltip" title="Default Location">' + value.rtd_location.name + '</a>';
return '<a href="{{ config('app.url') }}/locations/' + value.rtd_location.id + '" data-tooltip="true" title="Default Location">' + value.rtd_location.name + '</a>';
}
}
@ -779,7 +779,7 @@
// This is necessary to make the bootstrap tooltips work inside of the
// wenzhixin/bootstrap-table formatters
$('#table').on('post-body.bs.table', function () {
$('[data-toggle="tooltip"]').tooltip({
$('[data-tooltip="true"]').tooltip({
container: 'body'
});

View file

@ -6,7 +6,7 @@
<input class="form-control col-md-3" type="text" name="min_amt" id="min_amt" aria-label="min_amt" value="{{ old('min_amt', $item->min_amt) }}" />
</div>
<div class="col-md-7" style="margin-left: -15px;">
<a href="#" data-toggle="tooltip" title="{{ trans('general.min_amt_help') }}"><i class="fas fa-info-circle" aria-hidden="true"></i>
<a href="#" data-tooltip="true" title="{{ trans('general.min_amt_help') }}"><i class="fas fa-info-circle" aria-hidden="true"></i>
<span class="sr-only">{{ trans('general.min_amt_help') }}</span>
</a>

View file

@ -4,7 +4,7 @@
<tbody class="permissions-group">
<tr class="header-row permissions-row">
<td class="col-md-5 tooltip-base permissions-item"
data-toggle="tooltip"
data-tooltip="true"
data-placement="right"
title="{{ $localPermission['note'] }}"
>
@ -76,7 +76,7 @@
@if ($permission['display'])
<td
class="col-md-5 tooltip-base permissions-item"
data-toggle="tooltip"
data-tooltip="true"
data-placement="right"
title="{{ $permission['note'] }}"
>

View file

@ -119,6 +119,29 @@
</div>
</div> <!--/form-group-->
<!-- activated -->
<div class="form-group">
<div class="col-sm-3 control-label">
{{ trans('general.autoassign_licenses') }}
</div>
<div class="col-sm-9">
<label for="no_change_autoassign_licenses" class="form-control">
{{ Form::radio('autoassign_licenses', '', true, ['id' => 'no_change_autoassign_licenses', 'aria-label'=>'no_change_autoassign_licenses']) }}
{{ trans('general.do_not_change') }}
</label>
<label for="autoassign_licenses" class="form-control">
{{ Form::radio('autoassign_licenses', '1', old('autoassign_licenses'), ['id' => 'autoassign_licenses', 'aria-label'=>'autoassign_licenses']) }}
{{ trans('general.autoassign_licenses_help')}}
</label>
<label for="dont_autoassign_licenses" class="form-control">
{{ Form::radio('autoassign_licenses', '0', old('autoassign_licenses'), ['id' => 'dont_autoassign_licenses', 'aria-label'=>'dont_autoassign_licenses']) }}
{{ trans('general.no_autoassign_licenses_help')}}
</label>
</div>
</div> <!--/form-group-->
<!-- activated -->
<div class="form-group">
<div class="col-sm-3 control-label">

View file

@ -370,6 +370,20 @@
</div>
</div>
<!-- Auto assign checkbox -->
<div class="form-group">
<div class="col-md-7 col-md-offset-3">
<label class="form-control" for="autoassign_licenses">
<input type="checkbox" value="1" name="autoassign_licenses" {{ (old('autoassign_licenses', $user->autoassign_licenses)) == '1' ? " checked='checked'" : '' }} aria-label="autoassign_licenses">
{{ trans('general.autoassign_licenses') }}
</label>
<p class="help-block">{{ trans('general.autoassign_licenses_help_long') }}</p>
</div>
</div>
<!-- remote checkbox -->
<div class="form-group">
@ -383,15 +397,6 @@
</div>
</div>
<!-- Auto Assign checkbox -->
<div class="form-group">
<div class="col-md-7 col-md-offset-3">
<label for="autoassign_licenses" class="form-control">
<input type="checkbox" value="1" name="autoassign_licenses" {{ (old('autoassign_licenses', $user->autoassign_licenses)) == '1' ? ' checked="checked"' : '' }} aria-label="autoassign_licenses">
{{ trans('admin/users/general.auto_assign_label') }}
</label>
</div>
</div>
<!-- Location -->
@include ('partials.forms.edit.location-select', ['translated_name' => trans('general.location'), 'fieldname' => 'location_id'])
@ -444,8 +449,8 @@
<!-- Country -->
<div class="form-group{{ $errors->has('country') ? ' has-error' : '' }}">
<label class="col-md-3 control-label" for="country">{{ trans('general.country') }}</label>
<div class="col-md-6">
{!! Form::countries('country', old('country', $user->country), 'col-md-6 select2') !!}
<div class="col-md-9">
{!! Form::countries('country', old('country', $user->country), 'col-md-12 select2') !!}
{!! $errors->first('country', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
</div>
</div>

View file

@ -122,7 +122,8 @@
@endcan
@can('update', \App\Models\User::class)
<li class="pull-right"><a href="#" data-toggle="modal" data-target="#uploadFileModal">
<li class="pull-right">
<a href="#" data-toggle="modal" data-target="#uploadFileModal">
<span class="hidden-xs"><i class="fas fa-paperclip" aria-hidden="true"></i></span>
<span class="hidden-lg hidden-md hidden-xl"><i class="fas fa-paperclip fa-2x" aria-hidden="true"></i></span>
<span class="hidden-xs hidden-sm">{{ trans('button.upload') }}</span>
@ -519,23 +520,23 @@
</div>
@endif
<!-- login enabled -->
<!-- vip -->
<div class="row">
<div class="col-md-3">
{{ trans('admin/users/general.vip_label') }}
</div>
<div class="col-md-9">
{!! ($user->vip=='1') ? '<i class="fas fa-check text-success" aria-hidden="true"></i> '.trans('general.yes') : '<i class="fas fa-times text-danger" aria-hidden="true"></i> '.trans('general.no') !!}
{!! ($user->vip=='1') ? '<i class="fas fa-check fa-fw fa-fw text-success" aria-hidden="true"></i> '.trans('general.yes') : '<i class="fas fa-times fa-fw text-danger" aria-hidden="true"></i> '.trans('general.no') !!}
</div>
</div>
<!-- login enabled -->
<!-- remote -->
<div class="row">
<div class="col-md-3">
{{ trans('admin/users/general.remote') }}
</div>
<div class="col-md-9">
{!! ($user->remote=='1') ? '<i class="fas fa-check text-success" aria-hidden="true"></i> '.trans('general.yes') : '<i class="fas fa-times text-danger" aria-hidden="true"></i> '.trans('general.no') !!}
{!! ($user->remote=='1') ? '<i class="fas fa-check fa-fw text-success" aria-hidden="true"></i> '.trans('general.yes') : '<i class="fas fa-times fa-fw text-danger" aria-hidden="true"></i> '.trans('general.no') !!}
</div>
</div>
@ -545,17 +546,28 @@
{{ trans('general.login_enabled') }}
</div>
<div class="col-md-9">
{!! ($user->activated=='1') ? '<i class="fas fa-check text-success" aria-hidden="true"></i> '.trans('general.yes') : '<i class="fas fa-times text-danger" aria-hidden="true"></i> '.trans('general.no') !!}
{!! ($user->activated=='1') ? '<i class="fas fa-check fa-fw text-success" aria-hidden="true"></i> '.trans('general.yes') : '<i class="fas fa-times fa-fw text-danger" aria-hidden="true"></i> '.trans('general.no') !!}
</div>
</div>
<!-- LDAP -->
<!-- auto assign license -->
<div class="row">
<div class="col-md-3">
{{ trans('general.autoassign_licenses') }}
</div>
<div class="col-md-9">
{!! ($user->autoassign_licenses=='1') ? '<i class="fas fa-check fa-fw text-success" aria-hidden="true"></i> '.trans('general.yes') : '<i class="fas fa-times fa-fw text-danger" aria-hidden="true"></i> '.trans('general.no') !!}
</div>
</div>
<!-- LDAP -->
<div class="row">
<div class="col-md-3">
LDAP
</div>
<div class="col-md-9">
{!! ($user->ldap_import=='1') ? '<i class="fas fa-check text-success" aria-hidden="true"></i> '.trans('general.yes') : '<i class="fas fa-times text-danger" aria-hidden="true"></i> '.trans('general.no') !!}
{!! ($user->ldap_import=='1') ? '<i class="fas fa-check fa-fw text-success" aria-hidden="true"></i> '.trans('general.yes') : '<i class="fas fa-times fa-fw text-danger" aria-hidden="true"></i> '.trans('general.no') !!}
</div>
</div>
@ -569,7 +581,7 @@
</div>
<div class="col-md-9">
{!! ($user->two_factor_active()) ? '<i class="fas fa-check text-success" aria-hidden="true"></i> '.trans('general.yes') : '<i class="fas fa-times text-danger" aria-hidden="true"></i> '.trans('general.no') !!}
{!! ($user->two_factor_active()) ? '<i class="fas fa-check fa-fw text-success" aria-hidden="true"></i> '.trans('general.yes') : '<i class="fas fa-times fa-fw text-danger" aria-hidden="true"></i> '.trans('general.no') !!}
</div>
</div>
@ -580,7 +592,7 @@
{{ trans('admin/users/general.two_factor_enrolled') }}
</div>
<div class="col-md-9" id="two_factor_reset_toggle">
{!! ($user->two_factor_active_and_enrolled()) ? '<i class="fas fa-check text-success" aria-hidden="true"></i> '.trans('general.yes') : '<i class="fas fa-times text-danger" aria-hidden="true"></i> '.trans('general.no') !!}
{!! ($user->two_factor_active_and_enrolled()) ? '<i class="fas fa-check fa-fw text-success" aria-hidden="true"></i> '.trans('general.yes') : '<i class="fas fa-times fa-fw text-danger" aria-hidden="true"></i> '.trans('general.no') !!}
</div>
</div>
@ -590,11 +602,11 @@
<!-- 2FA reset -->
<div class="row">
<div class="col-md-3">
</div>
<div class="col-md-9" style="margin-top: 10px;">
<div class="col-md-9">
<a class="btn btn-default btn-sm pull-left" id="two_factor_reset" style="margin-right: 10px;">
<a class="btn btn-default btn-sm" id="two_factor_reset" style="margin-right: 10px; margin-top: 10px;">
{{ trans('admin/settings/general.two_factor_reset') }}
</a>
<span id="two_factor_reseticon">
@ -1031,9 +1043,9 @@ $(function () {
dataType: 'json',
success: function (data) {
$("#two_factor_reset_toggle").html('').html('<i class="fas fa-times text-danger" aria-hidden="true"></i> {{ trans('general.no') }}');
$("#two_factor_reset_toggle").html('').html('<span class="text-danger"><i class="fas fa-times" aria-hidden="true"></i> {{ trans('general.no') }}</span>');
$("#two_factor_reseticon").html('');
$("#two_factor_resetstatus").html('<i class="fas fa-check text-success"></i>' + data.message);
$("#two_factor_resetstatus").html('<span class="text-success"><i class="fas fa-check"></i> ' + data.message + '</span>');
},

View file

@ -25,10 +25,21 @@ Route::group(['prefix' => 'licenses', 'middleware' => ['auth']], function () {
[Licenses\LicenseCheckinController::class, 'store']
)->name('licenses.checkin.save');
Route::post(
'{licenseId}/bulkcheckin',
[Licenses\LicenseCheckinController::class, 'bulkCheckin']
)->name('licenses.bulkcheckin');
Route::post(
'{licenseId}/bulkcheckout',
[Licenses\LicenseCheckoutController::class, 'bulkCheckout']
)->name('licenses.bulkcheckout');
Route::post(
'{licenseId}/upload',
[Licenses\LicenseFilesController::class, 'store']
)->name('upload/license');
Route::delete(
'{licenseId}/deletefile/{fileId}',
[Licenses\LicenseFilesController::class, 'destroy']