3
0
mirror of https://github.com/snipe/snipe-it.git synced 2025-10-29 11:21:21 +00:00

Compare commits

...

44 Commits

Author SHA1 Message Date
snipe
32a2eed5ec Fixed #18075 - make require_serial boolean in API transformer 2025-10-27 13:19:37 +00:00
snipe
5697054e98
Merge pull request #18099 from grokability/fix-cjk-for-acceptance-translated-strings
Fixed #18097 - check for CJK in field labels as well as content
2025-10-27 12:41:59 +00:00
snipe
def5969e1c Fixed #18097 - check for CJK in field labels as well as content 2025-10-27 12:34:30 +00:00
snipe
6d76e7b2d4 Added dumb pverride for reports :( 2025-10-27 12:21:16 +00:00
snipe
f052c8b44c
Merge pull request #18076 from uberbrady/move_traits_into_directories
Moved Traits into its directory and modify the FCO's to point to them
2025-10-27 11:43:31 +00:00
snipe
06eab5f8a4
Merge pull request #18093 from Godmartinz/fix-warranty-part-of-expiring-asset-query
Fixed expiring warranties not being included in the expiring alerts notification
2025-10-27 11:41:51 +00:00
snipe
ee4abbcbaa Updated dev assets 2025-10-27 11:12:13 +00:00
snipe
dcc82d742f Fixed RB-20430 - 500 on LDAP if baseDN is not set 2025-10-27 11:09:24 +00:00
snipe
19cb2089d7
Merge pull request #18098 from grokability/dependabot/github_actions/develop/actions/upload-artifact-5
Bump actions/upload-artifact from 4 to 5
2025-10-27 10:47:59 +00:00
snipe
04923b06b0
Merge pull request #18078 from grokability/groups-ui-improvements
Groups UI improvements, ability to add users from the group edit screen
2025-10-27 10:47:11 +00:00
dependabot[bot]
e16755d491
Bump actions/upload-artifact from 4 to 5
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4 to 5.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-27 08:19:26 +00:00
snipe
742b0769a4 Use translation string 2025-10-26 12:10:08 +00:00
snipe
df68dca9dc Warn if user has individual permission overrides 2025-10-25 18:57:17 +01:00
snipe
4a5bf78d58
Merge branch 'develop' into groups-ui-improvements 2025-10-25 18:31:22 +01:00
snipe
7947237489 Double check the admin status when toggling the superadmin 2025-10-25 18:29:52 +01:00
snipe
1115205164 Normalize the JS 2025-10-25 18:20:22 +01:00
snipe
d5d01136c4 Fixed js errors 2025-10-25 17:57:59 +01:00
snipe
3d47277614 Added cursor style 2025-10-25 17:57:44 +01:00
snipe
b937bea04f Working, but there’s a bit of a jitter I need to fix 2025-10-25 15:59:47 +01:00
snipe
60099aa989 FAFOing on disclosure arrows being remembered 2025-10-25 14:56:01 +01:00
Godfrey M
99549ce805 rewrite query for expired warranties on assets, concat queries" 2025-10-23 11:01:51 -07:00
Godfrey M
e2019a13ab rewrite expired assets collection query 2025-10-23 10:49:58 -07:00
snipe
8f4a1f5801 Moved JS and styles into js and css files 2025-10-23 13:24:26 +01:00
snipe
891bec9cdb Styling fixes 2025-10-23 13:06:45 +01:00
Godfrey M
c5252ea583 skip in one more spot 2025-10-22 12:23:14 -07:00
Godfrey M
82d553c180 skip test if sqllite 2025-10-22 12:19:13 -07:00
Godfrey M
71e34355b9 remove unwanted changes 2025-10-22 11:51:00 -07:00
Godfrey M
2bad8c72e4 fixes warranty part of expiring alerts query 2025-10-22 11:43:54 -07:00
Godfrey M
6134ca01ac Merge remote-tracking branch 'origin/develop' into develop 2025-10-22 10:48:05 -07:00
snipe
be8193ebff Fixed inherit permissions 2025-10-22 15:00:04 +01:00
snipe
430ee46645 Small tweaks to inherit js 2025-10-22 13:41:59 +01:00
snipe
76fbbf29e8 Replace generate text with icon button 2025-10-22 13:37:45 +01:00
snipe
3108159d95 Jitter CSS tweaks 2025-10-22 12:37:39 +01:00
snipe
f282a1ead7 Removed duplicated permissions js code 2025-10-22 12:03:55 +01:00
snipe
c3b5c4dfae Moved the logic into the permissions partial, added translations 2025-10-21 22:10:09 +01:00
Godfrey M
b4696ef11e added alert_email to send conditional in listener 2025-10-21 13:11:21 -07:00
snipe
294ffb72a4 Translations!!! 2025-10-21 20:36:09 +01:00
snipe
8c534d29d3 WTF tower?? 2025-10-21 19:36:28 +01:00
snipe
d6cb262f9d Bumped version 2025-10-21 19:22:36 +01:00
snipe
5211e2ae20 Some UI refinement 2025-10-21 19:22:36 +01:00
snipe
90832fd1ad Checked check 2025-10-21 19:22:36 +01:00
snipe
889cbc69e1 Starter improvements - needs testing 2025-10-21 19:22:36 +01:00
snipe
15948370d4 Updated assets 2025-10-21 19:22:24 +01:00
Brady Wetherington
9e68497b63 Moved Traits into directory and modify the users to point to them 2025-10-21 16:45:58 +01:00
39 changed files with 1282 additions and 726 deletions

View File

@ -82,7 +82,7 @@ jobs:
- name: Upload Laravel logs as artifacts
if: always()
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v5
with:
name: laravel-logs-php-${{ matrix.php-version }}-run-${{ github.run_attempt }}
path: |

View File

@ -81,7 +81,7 @@ jobs:
- name: Upload Laravel logs as artifacts
if: always()
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v5
with:
name: laravel-logs-php-${{ matrix.php-version }}-run-${{ github.run_attempt }}
path: |

View File

@ -67,7 +67,7 @@ jobs:
- name: Upload Laravel logs as artifacts
if: always()
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v5
with:
name: laravel-logs-php-${{ matrix.php-version }}-run-${{ github.run_attempt }}
path: |

View File

@ -65,6 +65,7 @@ class GroupsController extends Controller
$group->notes = $request->input('notes');
if ($group->save()) {
$group->users()->sync($request->input('associated_users'));
return redirect()->route('groups.index')->with('success', trans('admin/groups/message.success.create'));
}
@ -88,7 +89,10 @@ class GroupsController extends Controller
$groupPermissions = [];
}
$selected_array = Helper::selectedPermissionsArray($permissions, $groupPermissions);
return view('groups.edit', compact('group', 'permissions', 'selected_array', 'groupPermissions'));
$associated_users = $group->users()->get();
//dd($associated_users->toArray());
return view('groups.edit', compact('group', 'permissions', 'selected_array', 'groupPermissions'))->with('associated_users', $associated_users);
}
/**
@ -105,8 +109,10 @@ class GroupsController extends Controller
$group->permissions = json_encode($request->input('permission'));
$group->notes = $request->input('notes');
if (! config('app.lock_passwords')) {
if ($group->save()) {
$group->users()->sync($request->input('associated_users'));
return redirect()->route('groups.index')->with('success', trans('admin/groups/message.success.update'));
}

View File

@ -68,7 +68,7 @@ class AssetModelsTransformer
'default_fieldset_values' => $default_field_values,
'eol' => ($assetmodel->eol > 0) ? $assetmodel->eol.' months' : 'None',
'requestable' => ($assetmodel->requestable == '1') ? true : false,
'require_serial' => $assetmodel->require_serial,
'require_serial' => ($assetmodel->require_serial == '1') ? true : false,
'notes' => Helper::parseEscapedMarkedownInline($assetmodel->notes),
'created_by' => ($assetmodel->adminuser) ? [
'id' => (int) $assetmodel->adminuser->id,

View File

@ -6,6 +6,7 @@ use App\Helpers\Helper;
use App\Models\Traits\Acceptable;
use App\Models\Traits\CompanyableTrait;
use App\Models\Traits\HasUploads;
use App\Models\Traits\Loggable;
use App\Models\Traits\Searchable;
use App\Presenters\Presentable;
use Illuminate\Database\Eloquent\Factories\HasFactory;

View File

@ -9,6 +9,8 @@ use App\Http\Traits\UniqueUndeletedTrait;
use App\Models\Traits\Acceptable;
use App\Models\Traits\CompanyableTrait;
use App\Models\Traits\HasUploads;
use App\Models\Traits\Loggable;
use App\Models\Traits\Requestable;
use App\Models\Traits\Searchable;
use App\Presenters\AssetPresenter;
use App\Presenters\Presentable;
@ -937,25 +939,37 @@ class Asset extends Depreciable
*/
public static function getExpiringWarrantyOrEol($days = 30)
{
return self::where('archived', '=', '0')
$now = now();
$end = now()->addDays($days);
$expired_assets = self::query()
->where('archived', '=', '0')
->NotArchived()
->whereNull('deleted_at')
->where(function ($query) use ($days) {
// Check for manual asset EOL first
$query->where(function ($query) use ($days) {
$query->whereNotNull('asset_eol_date')
->whereBetween('asset_eol_date', [Carbon::now(), Carbon::now()->addDays($days)]);
// Otherwise use the warranty months + purchase date + threshold
})->orWhere(function ($query) use ($days) {
$query->whereNotNull('purchase_date')
->whereNotNull('warranty_months')
->whereBetween('purchase_date', [Carbon::now(), Carbon::now()->addMonths('assets.warranty_months')->addDays($days)]);
});
})
->orderBy('asset_eol_date', 'ASC')
->orderBy('purchase_date', 'ASC')
->whereNotNull('asset_eol_date')
->whereBetween('asset_eol_date', [$now, $end])
->get();
$assets_with_warranties = self::query()
->where('archived', '=', '0')
->NotArchived()
->whereNull('deleted_at')
->whereNotNull('purchase_date')
->whereNotNull('warranty_months')
->get();
$expired_warranties = $assets_with_warranties->filter(function ($asset) use ($now, $end) {
$expiration_window = Carbon::parse($asset->purchase_date)->addMonths((int) $asset->warranty_months);
return $expiration_window->betweenIncluded($now, $end);
});
return $expired_assets->concat($expired_warranties)
->unique('id')
->sortBy([
['asset_eol_date', 'ASC'],
['purchase_date', 'ASC']
])
->values();
}

View File

@ -2,16 +2,18 @@
namespace App\Models;
use App\Http\Traits\TwoColumnUniqueUndeletedTrait;
use App\Models\Traits\HasUploads;
use App\Models\Traits\Loggable;
use App\Models\Traits\Requestable;
use App\Models\Traits\Searchable;
use App\Presenters\AssetModelPresenter;
use App\Presenters\Presentable;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Facades\Storage;
use Watson\Validating\ValidatingTrait;
use \App\Presenters\AssetModelPresenter;
use App\Http\Traits\TwoColumnUniqueUndeletedTrait;
/**
* Model for Asset Models. Asset Models contain higher level

View File

@ -190,6 +190,11 @@ class CheckoutAcceptance extends Model
}
$pdf->Ln();
// Check for CJK in the translation string for date. (This is a good proxy for the rest of the document)
Helper::hasRtl(trans('general.date')) ? $pdf->setRTL(true) : $pdf->setRTL(false);
Helper::isCjk(trans('general.date')) ? $pdf->SetFont('cid0cs', '', 9) : $pdf->SetFont('dejavusans', '', 8, '', true);
$pdf->writeHTML(trans('general.date') . ': ' . Helper::getFormattedDateObject(now(), 'datetime', false), true, 0, true, 0, '');
if ($data['company_name'] != null) {
@ -224,7 +229,6 @@ class CheckoutAcceptance extends Model
foreach ($eula_lines as $eula_line) {
Helper::hasRtl($eula_line) ? $pdf->setRTL(true) : $pdf->setRTL(false);
Helper::isCjk($eula_line) ? $pdf->SetFont('cid0cs', '', 9) : $pdf->SetFont('dejavusans', '', 8, '', true);
$pdf->writeHTML(Helper::parseEscapedMarkedown($eula_line), true, 0, true, 0, '');
}
$pdf->Ln();
@ -239,8 +243,11 @@ class CheckoutAcceptance extends Model
$pdf->Ln();
}
Helper::hasRtl(trans('general.notes')) ? $pdf->setRTL(true) : $pdf->setRTL(false);
Helper::isCjk(trans('general.notes')) ? $pdf->SetFont('cid0cs', '', 9) : $pdf->SetFont('dejavusans', '', 8, '', true);
if ($data['note'] != null) {
Helper::isCjk($data['note']) ? $pdf->SetFont('cid0cs', '', 9) : $pdf->SetFont('dejavusans', '', 8, '', true);
Helper::isCjk(trans('general.notes')) ? $pdf->SetFont('cid0cs', '', 9) : $pdf->SetFont('dejavusans', '', 8, '', true);
$pdf->writeHTML(trans('general.notes') . ': ' . e($data['note']), true, 0, true, 0, '');
$pdf->Ln();
}

View File

@ -5,6 +5,7 @@ namespace App\Models;
use App\Helpers\Helper;
use App\Models\Traits\CompanyableTrait;
use App\Models\Traits\HasUploads;
use App\Models\Traits\Loggable;
use App\Models\Traits\Searchable;
use App\Presenters\Presentable;
use Illuminate\Database\Eloquent\Factories\HasFactory;

View File

@ -6,6 +6,7 @@ use App\Helpers\Helper;
use App\Models\Traits\Acceptable;
use App\Models\Traits\CompanyableTrait;
use App\Models\Traits\HasUploads;
use App\Models\Traits\Loggable;
use App\Models\Traits\Searchable;
use App\Presenters\ConsumablePresenter;
use App\Presenters\Presentable;

View File

@ -220,7 +220,7 @@ class Ldap extends Model
Log::debug('Filter query: '.$filterQuery);
// only try this if we have an Admin username set; otherwise use the 'legacy' method
if ($settings->ldap_uname) {
if (($settings->ldap_uname) && ($baseDn)) {
// in the fallowing call, we pick a slow-failure of 0 because we might need to fall through to 'legacy'
$fast_bind = self::findAndBindMultiOU($baseDn, $filterQuery, $password, 0);
if ($fast_bind) {

View File

@ -5,6 +5,7 @@ namespace App\Models;
use App\Helpers\Helper;
use App\Models\Traits\CompanyableTrait;
use App\Models\Traits\HasUploads;
use App\Models\Traits\Loggable;
use App\Models\Traits\Searchable;
use App\Presenters\Presentable;
use Carbon\Carbon;

View File

@ -4,6 +4,7 @@ namespace App\Models;
use App\Models\Traits\Acceptable;
use App\Models\Traits\CompanyableChildTrait;
use App\Models\Traits\Loggable;
use App\Notifications\CheckinLicenseNotification;
use App\Notifications\CheckoutLicenseNotification;
use App\Presenters\Presentable;

View File

@ -5,6 +5,7 @@ namespace App\Models;
use App\Http\Traits\UniqueUndeletedTrait;
use App\Models\Traits\CompanyableTrait;
use App\Models\Traits\HasUploads;
use App\Models\Traits\Loggable;
use App\Models\Traits\Searchable;
use App\Presenters\Presentable;
use Illuminate\Database\Eloquent\Factories\HasFactory;

View File

@ -5,6 +5,7 @@ namespace App\Models;
use App\Helpers\Helper;
use App\Models\Traits\CompanyableChildTrait;
use App\Models\Traits\HasUploads;
use App\Models\Traits\Loggable;
use App\Models\Traits\Searchable;
use App\Presenters\Presentable;
use Illuminate\Database\Eloquent\Factories\HasFactory;

View File

@ -1,8 +1,14 @@
<?php
namespace App\Models;
namespace App\Models\Traits;
use App\Models\Actionlog;
use App\Models\Asset;
use App\Models\License;
use App\Models\LicenseSeat;
use App\Models\Location;
use App\Models\Setting;
use App\Models\User;
use App\Notifications\AuditNotification;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Log;

View File

@ -1,8 +1,10 @@
<?php
namespace App\Models;
namespace App\Models\Traits;
use Illuminate\Support\Facades\Auth;
use App\Models\CheckoutRequest;
use App\Models\User;
// $asset->requests
// $asset->isRequestedBy($user)

View File

@ -5,6 +5,7 @@ namespace App\Models;
use App\Http\Traits\UniqueUndeletedTrait;
use App\Models\Traits\CompanyableTrait;
use App\Models\Traits\HasUploads;
use App\Models\Traits\Loggable;
use App\Models\Traits\Searchable;
use App\Presenters\Presentable;
use App\Presenters\UserPresenter;
@ -224,6 +225,24 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
return false;
}
public function hasIndividualPermissions() {
if (is_object($this->permissions)) {
$permissions = json_decode(json_encode($this->permissions), true);
}
if (is_string($this->permissions)) {
$permissions = json_decode($this->permissions, true);
}
foreach ($permissions as $permission) {
if ($permission != 0) {
return true;
}
}
return false;
}
/**
* Internally check the user permission for the given section
*

View File

@ -9,11 +9,9 @@
return [
'Global' => [
'Superuser' => [
[
'permission' => 'superuser',
'label' => 'Super User',
'note' => 'Determines whether the user has full access to all aspects of the admin. This setting overrides any more specific permissions throughout the system. ',
'display' => true,
],
],
@ -21,17 +19,13 @@ return [
'Admin' => [
[
'permission' => 'admin',
'label' => '',
'note' => 'Determines whether the user has access to most aspects of the admin. ',
'display' => true,
],
],
'CSV Import' => [
'Import' => [
[
'permission' => 'import',
'label' => '',
'note' => 'This will allow users to import even if access to users, assets, etc is denied elsewhere.',
'display' => true,
],
],
@ -39,8 +33,6 @@ return [
'Reports' => [
[
'permission' => 'reports.view',
'label' => 'View',
'note' => 'Determines whether the user has the ability to view reports.',
'display' => true,
],
],
@ -48,68 +40,48 @@ return [
'Assets' => [
[
'permission' => 'assets.view',
'label' => 'View ',
'note' => '',
'display' => true,
],
[
'permission' => 'assets.create',
'label' => 'Create ',
'note' => '',
'display' => true,
],
[
'permission' => 'assets.edit',
'label' => 'Edit ',
'note' => '',
'display' => true,
],
[
'permission' => 'assets.delete',
'label' => 'Delete ',
'note' => '',
'display' => true,
],
[
'permission' => 'assets.checkout',
'label' => 'Checkout ',
'note' => '',
'display' => false,
],
[
'permission' => 'assets.checkin',
'label' => 'Checkin ',
'note' => '',
'display' => true,
],
[
'permission' => 'assets.checkout',
'label' => 'Checkout ',
'note' => '',
'display' => true,
],
[
'permission' => 'assets.audit',
'label' => 'Audit ',
'note' => 'Allows the user to mark an asset as physically inventoried.',
'display' => true,
],
[
'permission' => 'assets.view.requestable',
'label' => 'View Requestable Assets',
'note' => '',
'display' => true,
],
[
'permission' => 'assets.view.encrypted_custom_fields',
'label' => 'View and Modify Encrypted Custom Fields',
'note' => '',
'display' => true,
],
@ -118,44 +90,30 @@ return [
'Accessories' => [
[
'permission' => 'accessories.view',
'label' => 'View ',
'note' => '',
'display' => true,
],
[
'permission' => 'accessories.create',
'label' => 'Create ',
'note' => '',
'display' => true,
],
[
'permission' => 'accessories.edit',
'label' => 'Edit ',
'note' => '',
'display' => true,
],
[
'permission' => 'accessories.delete',
'label' => 'Delete ',
'note' => '',
'display' => true,
],
[
'permission' => 'accessories.checkout',
'label' => 'Checkout ',
'note' => '',
'display' => true,
],
[
'permission' => 'accessories.checkin',
'label' => 'Checkin ',
'note' => '',
'display' => true,
],
[
'permission' => 'accessories.files',
'label' => 'View and Modify Accessory Files',
'note' => '',
'display' => true,
],
@ -164,38 +122,26 @@ return [
'Consumables' => [
[
'permission' => 'consumables.view',
'label' => 'View',
'note' => '',
'display' => true,
],
[
'permission' => 'consumables.create',
'label' => 'Create ',
'note' => '',
'display' => true,
],
[
'permission' => 'consumables.edit',
'label' => 'Edit ',
'note' => '',
'display' => true,
],
[
'permission' => 'consumables.delete',
'label' => 'Delete ',
'note' => '',
'display' => true,
],
[
'permission' => 'consumables.checkout',
'label' => 'Checkout ',
'note' => '',
'display' => true,
],
[
'permission' => 'consumables.files',
'label' => 'View and Modify Consumable Files',
'note' => '',
'display' => true,
],
],
@ -204,50 +150,34 @@ return [
'Licenses' => [
[
'permission' => 'licenses.view',
'label' => 'View',
'note' => '',
'display' => true,
],
[
'permission' => 'licenses.create',
'label' => 'Create ',
'note' => '',
'display' => true,
],
[
'permission' => 'licenses.edit',
'label' => 'Edit ',
'note' => '',
'display' => true,
],
[
'permission' => 'licenses.delete',
'label' => 'Delete ',
'note' => '',
'display' => true,
],
[
'permission' => 'licenses.checkout',
'label' => 'Checkout ',
'note' => '',
'display' => true,
],
[
'permission' => 'licenses.checkin',
'label' => 'Checkin ',
'note' => '',
'display' => true,
],
[
'permission' => 'licenses.keys',
'label' => 'View License Keys',
'note' => '',
'display' => true,
],
[
'permission' => 'licenses.files',
'label' => 'View and Modify License Files',
'note' => '',
'display' => true,
],
],
@ -256,44 +186,30 @@ return [
'Components' => [
[
'permission' => 'components.view',
'label' => 'View',
'note' => '',
'display' => true,
],
[
'permission' => 'components.create',
'label' => 'Create ',
'note' => '',
'display' => true,
],
[
'permission' => 'components.edit',
'label' => 'Edit ',
'note' => '',
'display' => true,
],
[
'permission' => 'components.delete',
'label' => 'Delete ',
'note' => '',
'display' => true,
],
[
'permission' => 'components.checkout',
'label' => 'Checkout ',
'note' => '',
'display' => true,
],
[
'permission' => 'components.checkin',
'label' => 'Checkin ',
'note' => '',
'display' => true,
],
[
'permission' => 'components.files',
'label' => 'View and Modify Component Files',
'note' => '',
'display' => true,
],
@ -302,26 +218,18 @@ return [
'Kits' => [
[
'permission' => 'kits.view',
'label' => 'View ',
'note' => 'These are predefined kits that can be used to quickly checkout assets, licenses, etc.',
'display' => true,
],
[
'permission' => 'kits.create',
'label' => 'Create ',
'note' => '',
'display' => true,
],
[
'permission' => 'kits.edit',
'label' => 'Edit ',
'note' => '',
'display' => true,
],
[
'permission' => 'kits.delete',
'label' => 'Delete ',
'note' => '',
'display' => true,
],
],
@ -329,26 +237,18 @@ return [
'Users' => [
[
'permission' => 'users.view',
'label' => 'View ',
'note' => '',
'display' => true,
],
[
'permission' => 'users.create',
'label' => 'Create Users',
'note' => '',
'display' => true,
],
[
'permission' => 'users.edit',
'label' => 'Edit Users',
'note' => '',
'display' => true,
],
[
'permission' => 'users.delete',
'label' => 'Delete Users',
'note' => '',
'display' => true,
],
@ -357,26 +257,18 @@ return [
'Models' => [
[
'permission' => 'models.view',
'label' => 'View ',
'note' => '',
'display' => true,
],
[
'permission' => 'models.create',
'label' => 'Create ',
'note' => '',
'display' => true,
],
[
'permission' => 'models.edit',
'label' => 'Edit ',
'note' => '',
'display' => true,
],
[
'permission' => 'models.delete',
'label' => 'Delete ',
'note' => '',
'display' => true,
],
@ -385,26 +277,18 @@ return [
'Categories' => [
[
'permission' => 'categories.view',
'label' => 'View ',
'note' => '',
'display' => true,
],
[
'permission' => 'categories.create',
'label' => 'Create ',
'note' => '',
'display' => true,
],
[
'permission' => 'categories.edit',
'label' => 'Edit ',
'note' => '',
'display' => true,
],
[
'permission' => 'categories.delete',
'label' => 'Delete ',
'note' => '',
'display' => true,
],
],
@ -412,26 +296,18 @@ return [
'Departments' => [
[
'permission' => 'departments.view',
'label' => 'View ',
'note' => '',
'display' => true,
],
[
'permission' => 'departments.create',
'label' => 'Create ',
'note' => '',
'display' => true,
],
[
'permission' => 'departments.edit',
'label' => 'Edit ',
'note' => '',
'display' => true,
],
[
'permission' => 'departments.delete',
'label' => 'Delete ',
'note' => '',
'display' => true,
],
],
@ -439,26 +315,18 @@ return [
'Status Labels' => [
[
'permission' => 'statuslabels.view',
'label' => 'View ',
'note' => '',
'display' => true,
],
[
'permission' => 'statuslabels.create',
'label' => 'Create ',
'note' => '',
'display' => true,
],
[
'permission' => 'statuslabels.edit',
'label' => 'Edit ',
'note' => '',
'display' => true,
],
[
'permission' => 'statuslabels.delete',
'label' => 'Delete ',
'note' => '',
'display' => true,
],
],
@ -466,26 +334,18 @@ return [
'Custom Fields' => [
[
'permission' => 'customfields.view',
'label' => 'View',
'note' => '',
'display' => true,
],
[
'permission' => 'customfields.create',
'label' => 'Create',
'note' => '',
'display' => true,
],
[
'permission' => 'customfields.edit',
'label' => 'Edit',
'note' => '',
'display' => true,
],
[
'permission' => 'customfields.delete',
'label' => 'Delete',
'note' => '',
'display' => true,
],
],
@ -493,26 +353,18 @@ return [
'Suppliers' => [
[
'permission' => 'suppliers.view',
'label' => 'View ',
'note' => '',
'display' => true,
],
[
'permission' => 'suppliers.create',
'label' => 'Create ',
'note' => '',
'display' => true,
],
[
'permission' => 'suppliers.edit',
'label' => 'Edit ',
'note' => '',
'display' => true,
],
[
'permission' => 'suppliers.delete',
'label' => 'Delete ',
'note' => '',
'display' => true,
],
],
@ -521,26 +373,18 @@ return [
'Manufacturers' => [
[
'permission' => 'manufacturers.view',
'label' => 'View ',
'note' => '',
'display' => true,
],
[
'permission' => 'manufacturers.create',
'label' => 'Create ',
'note' => '',
'display' => true,
],
[
'permission' => 'manufacturers.edit',
'label' => 'Edit ',
'note' => '',
'display' => true,
],
[
'permission' => 'manufacturers.delete',
'label' => 'Delete ',
'note' => '',
'display' => true,
],
],
@ -548,26 +392,18 @@ return [
'Depreciations' => [
[
'permission' => 'depreciations.view',
'label' => 'View ',
'note' => '',
'display' => true,
],
[
'permission' => 'depreciations.create',
'label' => 'Create ',
'note' => '',
'display' => true,
],
[
'permission' => 'depreciations.edit',
'label' => 'Edit ',
'note' => '',
'display' => true,
],
[
'permission' => 'depreciations.delete',
'label' => 'Delete ',
'note' => '',
'display' => true,
],
],
@ -575,26 +411,18 @@ return [
'Locations' => [
[
'permission' => 'locations.view',
'label' => 'View ',
'note' => '',
'display' => true,
],
[
'permission' => 'locations.create',
'label' => 'Create ',
'note' => '',
'display' => true,
],
[
'permission' => 'locations.edit',
'label' => 'Edit ',
'note' => '',
'display' => true,
],
[
'permission' => 'locations.delete',
'label' => 'Delete ',
'note' => '',
'display' => true,
],
],
@ -602,66 +430,46 @@ return [
'Companies' => [
[
'permission' => 'companies.view',
'label' => 'View ',
'note' => '',
'display' => true,
],
[
'permission' => 'companies.create',
'label' => 'Create ',
'note' => '',
'display' => true,
],
[
'permission' => 'companies.edit',
'label' => 'Edit ',
'note' => '',
'display' => true,
],
[
'permission' => 'companies.delete',
'label' => 'Delete ',
'note' => '',
'display' => true,
],
],
'Self' => [
'User (Self) Accounts' => [
[
'permission' => 'self.two_factor',
'label' => 'Two-Factor Authentication',
'note' => 'The user may disable/enable two-factor authentication themselves if two-factor is enabled and set to selective.',
'display' => true,
],
[
'permission' => 'self.api',
'label' => 'Create API Keys',
'note' => 'The user create personal API keys to utilize the REST API.',
'display' => true,
],
[
'permission' => 'self.edit_location',
'label' => 'Profile Edit Location',
'note' => 'The user may update their own location in their profile. Note that this is not affected by any additional Users permissions you grant to this user or group.',
'display' => true,
],
[
'permission' => 'self.checkout_assets',
'label' => 'Self-Checkout',
'note' => 'This user may check out assets that are marked for self-checkout.',
'display' => true,
],
[
'permission' => 'self.view_purchase_cost',
'label' => 'View Purchase-Cost Column',
'note' => 'This user can see the purchase cost column of items assigned to them.',
'display' => true,
],

View File

@ -1539,6 +1539,59 @@ This just hides the padding on the right side of the mark tag for a less weird v
mark {
padding-right: 0px;
}
/**
Radio toggle styles for permission settings and check/uncheck all
*/
.radio-toggle-wrapper {
display: flex;
padding: 2px;
background-color: #e9e9e9;
margin-bottom: 3px;
border-radius: 4px;
border: 1px #d6d6d6 solid;
}
.radio-slider-inputs {
flex-grow: 1;
}
.radio-slider-inputs input[type=radio] {
display: none;
}
.radio-slider-inputs label {
display: block;
margin-bottom: 0px;
padding: 6px 8px;
color: #fff;
font-weight: bold;
text-align: center;
transition: all 0.4s 0s ease;
cursor: pointer;
}
.radio-slider-inputs label {
color: #9a9999;
border-radius: 4px;
border: 1px transparent solid;
}
.radio-slider-inputs .allow:checked + label {
background-color: green;
color: white;
border-radius: 4px;
border: 1px transparent solid;
}
.radio-slider-inputs .inherit:checked + label {
background-color: rgba(255, 204, 51, 0.11);
color: #9a9999;
border-radius: 4px;
border: 1px white solid;
}
.radio-slider-inputs .deny:checked + label {
background-color: #a94442;
color: white;
border-radius: 4px;
border: 1px transparent solid;
}
.remember-toggle {
cursor: pointer;
}
/*# sourceMappingURL=app.css.map*/

File diff suppressed because one or more lines are too long

View File

@ -1163,6 +1163,59 @@ This just hides the padding on the right side of the mark tag for a less weird v
mark {
padding-right: 0px;
}
/**
Radio toggle styles for permission settings and check/uncheck all
*/
.radio-toggle-wrapper {
display: flex;
padding: 2px;
background-color: #e9e9e9;
margin-bottom: 3px;
border-radius: 4px;
border: 1px #d6d6d6 solid;
}
.radio-slider-inputs {
flex-grow: 1;
}
.radio-slider-inputs input[type=radio] {
display: none;
}
.radio-slider-inputs label {
display: block;
margin-bottom: 0px;
padding: 6px 8px;
color: #fff;
font-weight: bold;
text-align: center;
transition: all 0.4s 0s ease;
cursor: pointer;
}
.radio-slider-inputs label {
color: #9a9999;
border-radius: 4px;
border: 1px transparent solid;
}
.radio-slider-inputs .allow:checked + label {
background-color: green;
color: white;
border-radius: 4px;
border: 1px transparent solid;
}
.radio-slider-inputs .inherit:checked + label {
background-color: rgba(255, 204, 51, 0.11);
color: #9a9999;
border-radius: 4px;
border: 1px white solid;
}
.radio-slider-inputs .deny:checked + label {
background-color: #a94442;
color: white;
border-radius: 4px;
border: 1px transparent solid;
}
.remember-toggle {
cursor: pointer;
}
/*# sourceMappingURL=overrides.css.map*/

File diff suppressed because one or more lines are too long

View File

@ -22875,6 +22875,59 @@ This just hides the padding on the right side of the mark tag for a less weird v
mark {
padding-right: 0px;
}
/**
Radio toggle styles for permission settings and check/uncheck all
*/
.radio-toggle-wrapper {
display: flex;
padding: 2px;
background-color: #e9e9e9;
margin-bottom: 3px;
border-radius: 4px;
border: 1px #d6d6d6 solid;
}
.radio-slider-inputs {
flex-grow: 1;
}
.radio-slider-inputs input[type=radio] {
display: none;
}
.radio-slider-inputs label {
display: block;
margin-bottom: 0px;
padding: 6px 8px;
color: #fff;
font-weight: bold;
text-align: center;
transition: all 0.4s 0s ease;
cursor: pointer;
}
.radio-slider-inputs label {
color: #9a9999;
border-radius: 4px;
border: 1px transparent solid;
}
.radio-slider-inputs .allow:checked + label {
background-color: green;
color: white;
border-radius: 4px;
border: 1px transparent solid;
}
.radio-slider-inputs .inherit:checked + label {
background-color: rgba(255, 204, 51, 0.11);
color: #9a9999;
border-radius: 4px;
border: 1px white solid;
}
.radio-slider-inputs .deny:checked + label {
background-color: #a94442;
color: white;
border-radius: 4px;
border: 1px transparent solid;
}
.remember-toggle {
cursor: pointer;
}
/*# sourceMappingURL=app.css.map*/
@ -24525,6 +24578,59 @@ This just hides the padding on the right side of the mark tag for a less weird v
mark {
padding-right: 0px;
}
/**
Radio toggle styles for permission settings and check/uncheck all
*/
.radio-toggle-wrapper {
display: flex;
padding: 2px;
background-color: #e9e9e9;
margin-bottom: 3px;
border-radius: 4px;
border: 1px #d6d6d6 solid;
}
.radio-slider-inputs {
flex-grow: 1;
}
.radio-slider-inputs input[type=radio] {
display: none;
}
.radio-slider-inputs label {
display: block;
margin-bottom: 0px;
padding: 6px 8px;
color: #fff;
font-weight: bold;
text-align: center;
transition: all 0.4s 0s ease;
cursor: pointer;
}
.radio-slider-inputs label {
color: #9a9999;
border-radius: 4px;
border: 1px transparent solid;
}
.radio-slider-inputs .allow:checked + label {
background-color: green;
color: white;
border-radius: 4px;
border: 1px transparent solid;
}
.radio-slider-inputs .inherit:checked + label {
background-color: rgba(255, 204, 51, 0.11);
color: #9a9999;
border-radius: 4px;
border: 1px white solid;
}
.radio-slider-inputs .deny:checked + label {
background-color: #a94442;
color: white;
border-radius: 4px;
border: 1px transparent solid;
}
.remember-toggle {
cursor: pointer;
}
/*# sourceMappingURL=overrides.css.map*/

82
public/js/dist/all.js vendored
View File

@ -52820,6 +52820,88 @@ document.addEventListener('livewire:init', function () {
});
});
// Check/Uncheck all radio buttons in the permissions group
$('.header-row input:radio').change(function () {
value = $(this).attr('value');
area = $(this).data('checker-group');
$('.radiochecker-' + area + '[value=' + value + ']').prop('checked', true);
});
// Generic toggleable callouts with remember state
$(".remember-toggle").on("click", function () {
var toggleable_callout_id = $(this).attr('id');
var toggle_content_class = 'toggle-content-' + $(this).attr('id');
var toggle_arrow = '#toggle-arrow-' + toggleable_callout_id;
var toggle_cookie_name = 'toggle_state_' + toggleable_callout_id;
console.log('Callout ID: ' + toggleable_callout_id);
console.log('Content ID: ' + toggle_content_class);
console.log('Arrow ID: ' + toggle_arrow);
console.log('Cookie Name: ' + toggle_cookie_name);
$('.' + toggle_content_class).fadeToggle(100);
$(toggle_arrow).toggleClass('fa-caret-right fa-caret-down');
var toggle_open = $(toggle_arrow).hasClass('fa-caret-down');
console.log('Cookie will set open state to: ' + toggle_open);
document.cookie = toggle_cookie_name + "=" + toggle_open + ';path=/';
});
var all_cookies = document.cookie.split(';');
for (var i in all_cookies) {
var trimmed_cookie = all_cookies[i].trim(' ');
elems = all_cookies[i].split('=', 2);
// We have to do more here since we don't know the name of the selector
if (trimmed_cookie.startsWith('toggle_state_')) {
console.log(trimmed_cookie + ' matches toggle_state_');
var toggle_selector_name = elems[0].replace(' toggle_state_', '');
if (elems[1] == 'true') {
console.log('Selector name for cookie click trigger: ' + toggle_selector_name);
$('#' + toggle_selector_name + '.remember-toggle').trigger('click');
}
}
}
/**
* This handles the show/hide of superuser and admin specific permissions
* on the group edit and user edit pages
*/
if ($("#superuser_allow").is(':checked')) {
// Hide here instead of fadeout on pageload to prevent what looks like Flash Of Unstyled Content (FOUC)
$(".nonsuperuser").hide();
$(".nonsuperuser").attr('display', 'none');
}
$(".superuser").change(function () {
if ($(this).val() == '1') {
$(".nonsuperuser").fadeOut();
$(".nonsuperuser").attr('display', 'none');
$(".nonadmin").fadeOut();
$(".nonadmin").attr('display', 'none');
} else if ($(this).val() != '1') {
$(".nonsuperuser").fadeIn();
$(".nonsuperuser").attr('display', 'block');
// If the superuser button has been set to deny, we need to
// check that the admin button isn't set to allow, before we show non-admin stuff
if ($("#admin_allow").is(':checked')) {
// Hide here instead of fadeout on pageload to prevent what looks like Flash Of Unstyled Content (FOUC)
$(".nonadmin").hide();
$(".nonadmin").attr('display', 'none');
}
}
});
if ($("#admin_allow").is(':checked')) {
// Hide here instead of fadeout on pageload to prevent what looks like Flash Of Unstyled Content (FOUC)
$(".nonadmin").hide();
$(".nonadmin").attr('display', 'none');
}
$(".admin").change(function () {
if ($(this).val() == '1') {
$(".nonadmin").fadeOut();
$(".nonadmin").attr('display', 'none');
} else if ($(this).val() != '1') {
$(".nonadmin").fadeIn();
$(".nonadmin").attr('display', 'block');
}
});
/***/ }),
/***/ "./resources/assets/js/snipeit_modals.js":

File diff suppressed because one or more lines are too long

View File

@ -1,9 +1,9 @@
{
"/js/dist/all.js": "/js/dist/all.js?id=76d88f0f91b852f7eecbce357ab5858b",
"/js/dist/all.js": "/js/dist/all.js?id=e78128438f0b07a393dc7947ef453b5f",
"/css/dist/skins/skin-black-dark.css": "/css/dist/skins/skin-black-dark.css?id=42f97cd5b9ee7521b04a448e7fc16ac9",
"/css/dist/skins/_all-skins.css": "/css/dist/skins/_all-skins.css?id=3e8b8221c159b829a0edd562eb717563",
"/css/build/overrides.css": "/css/build/overrides.css?id=0269c1685972b15390f55bed0c75e203",
"/css/build/app.css": "/css/build/app.css?id=b0e6aaa03dfc3058014bfa6d52f5ae9b",
"/css/build/overrides.css": "/css/build/overrides.css?id=0e62c5b1f553ebbaefb3b0c5566ea921",
"/css/build/app.css": "/css/build/app.css?id=e48cebd888e758aec1a845fcf2737850",
"/css/build/AdminLTE.css": "/css/build/AdminLTE.css?id=ee0ed88465dd878588ed044eefb67723",
"/css/dist/skins/skin-yellow.css": "/css/dist/skins/skin-yellow.css?id=3d8a3d2035ea28aaad4a703c2646f515",
"/css/dist/skins/skin-yellow-dark.css": "/css/dist/skins/skin-yellow-dark.css?id=3979929a3423ff35b96b1fc84299fdf3",
@ -19,7 +19,7 @@
"/css/dist/skins/skin-blue.css": "/css/dist/skins/skin-blue.css?id=b2cd9f59d7e8587939ce27b2d3363d82",
"/css/dist/skins/skin-blue-dark.css": "/css/dist/skins/skin-blue-dark.css?id=7277edd636cf46aa7786a4449ce0ead7",
"/css/dist/skins/skin-black.css": "/css/dist/skins/skin-black.css?id=cbd06cc1d58197ccc81d4376bbaf0d28",
"/css/dist/all.css": "/css/dist/all.css?id=f4aa76120f4cbc790ee0bf4a519415d6",
"/css/dist/all.css": "/css/dist/all.css?id=cbb351c9106b4eaf0cb49a0ad9499e1e",
"/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",
"/js/select2/i18n/af.js": "/js/select2/i18n/af.js?id=4f6fcd73488ce79fae1b7a90aceaecde",

View File

@ -579,6 +579,8 @@ function htmlEntities(str) {
})(jQuery);
/**
* Universal Livewire Select2 integration
*
@ -610,3 +612,105 @@ document.addEventListener('livewire:init', () => {
});
});
});
// Check/Uncheck all radio buttons in the permissions group
$('.header-row input:radio').change(function() {
value = $(this).attr('value');
area = $(this).data('checker-group');
$('.radiochecker-'+area+'[value='+value+']').prop('checked', true);
});
// Generic toggleable callouts with remember state
$(".remember-toggle").on("click",function(){
var toggleable_callout_id = $(this).attr('id');
var toggle_content_class = 'toggle-content-'+$(this).attr('id');
var toggle_arrow = '#toggle-arrow-' + toggleable_callout_id;
var toggle_cookie_name='toggle_state_'+toggleable_callout_id;
console.log('Callout ID: ' + toggleable_callout_id);
console.log('Content ID: '+toggle_content_class);
console.log('Arrow ID: '+toggle_arrow);
console.log('Cookie Name: '+toggle_cookie_name);
$('.'+toggle_content_class).fadeToggle(100);
$(toggle_arrow).toggleClass('fa-caret-right fa-caret-down');
var toggle_open = $(toggle_arrow).hasClass('fa-caret-down');
console.log('Cookie will set open state to: '+toggle_open);
document.cookie=toggle_cookie_name+"="+toggle_open+';path=/';
});
var all_cookies = document.cookie.split(';')
for (var i in all_cookies) {
var trimmed_cookie = all_cookies[i].trim(' ')
elems = all_cookies[i].split('=', 2);
// We have to do more here since we don't know the name of the selector
if (trimmed_cookie.startsWith('toggle_state_')) {
console.log(trimmed_cookie + ' matches toggle_state_');
var toggle_selector_name = elems[0].replace(' toggle_state_','');
if (elems[1] == 'true') {
console.log('Selector name for cookie click trigger: '+toggle_selector_name);
$('#'+toggle_selector_name+'.remember-toggle').trigger('click')
}
}
}
/**
* This handles the show/hide of superuser and admin specific permissions
* on the group edit and user edit pages
*/
if ($("#superuser_allow").is(':checked')) {
// Hide here instead of fadeout on pageload to prevent what looks like Flash Of Unstyled Content (FOUC)
$(".nonsuperuser").hide();
$(".nonsuperuser").attr('display','none');
}
$(".superuser").change(function() {
if ($(this).val() == '1') {
$(".nonsuperuser").fadeOut();
$(".nonsuperuser").attr('display','none');
$(".nonadmin").fadeOut();
$(".nonadmin").attr('display','none');
} else if ($(this).val() != '1') {
$(".nonsuperuser").fadeIn();
$(".nonsuperuser").attr('display','block');
// If the superuser button has been set to deny, we need to
// check that the admin button isn't set to allow, before we show non-admin stuff
if ($("#admin_allow").is(':checked')) {
// Hide here instead of fadeout on pageload to prevent what looks like Flash Of Unstyled Content (FOUC)
$(".nonadmin").hide();
$(".nonadmin").attr('display','none');
}
}
});
if ($("#admin_allow").is(':checked')) {
// Hide here instead of fadeout on pageload to prevent what looks like Flash Of Unstyled Content (FOUC)
$(".nonadmin").hide();
$(".nonadmin").attr('display','none');
}
$(".admin").change(function() {
if ($(this).val() == '1') {
$(".nonadmin").fadeOut();
$(".nonadmin").attr('display','none');
} else if ($(this).val() != '1') {
$(".nonadmin").fadeIn();
$(".nonadmin").attr('display','block');
}
});

View File

@ -1303,4 +1303,66 @@ This just hides the padding on the right side of the mark tag for a less weird v
*/
mark {
padding-right: 0px;
}
/**
Radio toggle styles for permission settings and check/uncheck all
*/
.radio-toggle-wrapper {
display: flex;
padding: 2px;
background-color: #e9e9e9;
margin-bottom: 3px;
border-radius: 4px;
border: 1px #d6d6d6 solid;
}
.radio-slider-inputs {
flex-grow: 1;
}
.radio-slider-inputs input[type=radio] {
display: none;
}
.radio-slider-inputs label {
display: block;
margin-bottom: 0px;
padding: 6px 8px;
color: #fff;
font-weight: bold;
text-align: center;
transition : all .4s 0s ease;
cursor: pointer;
}
.radio-slider-inputs label {
color: #9a9999;
border-radius: 4px;
border: 1px transparent solid;
}
.radio-slider-inputs .allow:checked + label {
background-color: green;
color: white;
border-radius: 4px;
border: 1px transparent solid;
}
.radio-slider-inputs .inherit:checked + label {
background-color: rgba(255, 204, 51, 0.11);
color: #9a9999;
border-radius: 4px;
border: 1px white solid;
}
.radio-slider-inputs .deny:checked + label {
background-color: #a94442;
color: white;
border-radius: 4px;
border: 1px transparent solid;
}
.remember-toggle {
cursor: pointer;
}

View File

@ -53,4 +53,6 @@ return [
'all_assigned_list_generation' => 'Generated on:',
'email_user_creds_on_create' => 'Email this user their credentials?',
'department_manager' => 'Department Manager',
'generate_password' => 'Generate random password',
'individual_override' => 'This user has at least one individual permission set, which may override group permissions.',
];

View File

@ -0,0 +1,424 @@
<?php
return array(
/*
|--------------------------------------------------------------------------
| Permissions
|--------------------------------------------------------------------------
| The following language lines are used in the user permissions system.
| Each permission has a 'name' and a 'note' that describes
| the permission in detail.
|
| DO NOT edit the keys (left-hand side) of each permission as these are
| used throughout the system for translations.
|---------------------------------------------------------------------------
*/
"superuser" => [
'name' => 'Super User',
'note' => 'Determines whether the user has full access to all aspects of the admin. This setting overrides ALL more specific and restrictive permissions throughout the system. ',
],
'admin' => [
'name' => 'Admin Access',
'note' => 'Determines whether the user has access to most aspects of the system EXCEPT the System Admin Settings. These users will be able to manage users, locations, categories, etc, but ARE constrained by Full Multiple Company Support if it is enabled.',
],
'import' => [
'name' => 'CSV Import',
'note' => 'This will allow users to import even if access to users, assets, etc is denied elsewhere.',
],
'reports' => [
'name' => 'Reports Access',
'note' => 'Determines whether the user has access to the Reports section of the application.',
],
'assets' =>
[
'name' => 'Assets',
'note' => 'Grants access to the Assets section of the application.',
],
'assetsview' => [
'name' => 'View Assets',
],
'assetscreate' => [
'name' => 'Create New Assets',
],
'assetsedit' => [
'name' => 'Edit Assets',
],
'assetsdelete' => [
'name' => 'Delete Assets',
],
'assetscheckin' => [
'name' => 'Check In',
'note' => 'Check assets back into inventory that are currently checked out.',
],
'assetscheckout' => [
'name' => 'Check Out',
'note' => 'Assign assets in inventory by checking them out.',
],
'assetsaudit' => [
'name' => 'Audit Assets',
'note' => 'Allows the user to mark an asset as physically inventoried.',
],
'assetsviewrequestable' => [
'name' => 'View Requestable Assets',
'note' => 'Allows the user to view assets that are marked as requestable.',
],
'assetsviewencrypted-custom-fields' => [
'name' => 'View Encrypted Custom Fields',
'note' => 'Allows the user to view and modify encrypted custom fields on assets.',
],
'accessories' => [
'name' => 'Accessories',
'note' => 'Grants access to the Accessories section of the application.',
],
'accessoriesview' => [
'name' => 'View Accessories',
],
'accessoriescreate' => [
'name' => 'Create New Accessories',
],
'accessoriesedit' => [
'name' => 'Edit Accessories',
],
'accessoriesdelete' => [
'name' => 'Delete Accessories',
],
'accessoriescheckout' => [
'name' => 'Check Out Accessories',
'note' => 'Assign accessories in inventory by checking them out.',
],
'accessoriescheckin' => [
'name' => 'Check In Accessories',
'note' => 'Check accessories back into inventory that are currently checked out.',
],
'accessoriesfiles' => [
'name' => 'Manage Accessory Files',
'note' => 'Allows the user to upload, download, and delete files associated with accessories.',
],
'consumables' => [
'name' => 'Consumables',
'note' => 'Grants access to the Consumables section of the application.',
],
'consumablesview' => [
'name' => 'View Consumables',
],
'consumablescreate' => [
'name' => 'Create New Consumables',
],
'consumablesedit' => [
'name' => 'Edit Consumables',
],
'consumablesdelete' => [
'name' => 'Delete Consumables',
],
'consumablescheckout' => [
'name' => 'Check Out Consumables',
'note' => 'Assign consumables in inventory by checking them out.',
],
'consumablesfiles' => [
'name' => 'Manage Consumable Files',
'note' => 'Allows the user to upload, download, and delete files associated with consumables.',
],
'licenses' => [
'name' => 'Licenses',
'note' => 'Grants access to the Licenses section of the application.',
],
'licensesview' => [
'name' => 'View Licenses',
],
'licensescreate' => [
'name' => 'Create New Licenses',
],
'licensesedit' => [
'name' => 'Edit Licenses',
],
'licensesdelete' => [
'name' => 'Delete Licenses',
],
'licensescheckout' => [
'name' => 'Assign Licenses',
'note' => 'Allows the user to assign licenses to assets or users.',
],
'licensescheckin' => [
'name' => 'Unassign Licenses',
'note' => 'Allows the user to unassign licenses from assets or users.',
],
'licensesfiles' => [
'name' => 'Manage License Files',
'note' => 'Allows the user to upload, download, and delete files associated with licenses.',
],
'licenseskeys' => [
'name' => 'Manage License Keys',
'note' => 'Allows the user to view product keys associated with licenses.',
],
'components' => [
'name' => 'Components',
'note' => 'Grants access to the Components section of the application.',
],
'componentsview' => [
'name' => 'View Components',
],
'componentscreate' => [
'name' => 'Create New Components',
],
'componentsedit' => [
'name' => 'Edit Components',
],
'componentsdelete' => [
'name' => 'Delete Components',
],
'componentsfiles' => [
'name' => 'Manage Component Files',
'note' => 'Allows the user to upload, download, and delete files associated with components.',
],
'componentscheckout' => [
'name' => 'Check Out Components',
'note' => 'Assign components in inventory by checking them out.',
],
'componentscheckin' => [
'name' => 'Check In Components',
'note' => 'Check components back into inventory that are currently checked out.',
],
'kits' => [
'name' => 'Predefined Kits',
'note' => 'Grants access to the Predefined Kits section of the application.',
],
'kitsview' => [
'name' => 'View Predefined Kits',
],
'kitscreate' => [
'name' => 'Create New Predefined Kits',
],
'kitsedit' => [
'name' => 'Edit Predefined Kits',
],
'kitsdelete' => [
'name' => 'Delete Predefined Kits',
],
'users' => [
'name' => 'Users',
'note' => 'Grants access to the Users section of the application.',
],
'usersview' => [
'name' => 'View Users',
],
'userscreate' => [
'name' => 'Create New Users',
],
'usersedit' => [
'name' => 'Edit Users',
],
'usersdelete' => [
'name' => 'Delete Users',
],
'models' => [
'name' => 'Models',
'note' => 'Grants access to the Models section of the application.',
],
'modelsview' => [
'name' => 'View Models',
],
'modelscreate' => [
'name' => 'Create New Models',
],
'modelsedit' => [
'name' => 'Edit Models',
],
'modelsdelete' => [
'name' => 'Delete Models',
],
'categories' => [
'name' => 'Categories',
'note' => 'Grants access to the Categories section of the application.',
],
'categoriesview' => [
'name' => 'View Categories',
],
'categoriescreate' => [
'name' => 'Create New Categories',
],
'categoriesedit' => [
'name' => 'Edit Categories',
],
'categoriesdelete' => [
'name' => 'Delete Categories',
],
'departments' => [
'name' => 'Departments',
'note' => 'Grants access to the Departments section of the application.',
],
'departmentsview' => [
'name' => 'View Departments',
],
'departmentscreate' => [
'name' => 'Create New Departments',
],
'departmentsedit' => [
'name' => 'Edit Departments',
],
'departmentsdelete' => [
'name' => 'Delete Departments',
],
'locations' => [
'name' => 'Locations',
'note' => 'Grants access to the Locations section of the application.',
],
'locationsview' => [
'name' => 'View Locations',
],
'locationscreate' => [
'name' => 'Create New Locations',
],
'locationsedit' => [
'name' => 'Edit Locations',
],
'locationsdelete' => [
'name' => 'Delete Locations',
],
'status-labels' => [
'name' => 'Status Labels',
'note' => 'Grants access to the Status Labels section of the application used by Assets.',
],
'statuslabelsview' => [
'name' => 'View Status Labels',
],
'statuslabelscreate' => [
'name' => 'Create New Status Labels',
],
'statuslabelsedit' => [
'name' => 'Edit Status Labels',
],
'statuslabelsdelete' => [
'name' => 'Delete Status Labels',
],
'custom-fields' => [
'name' => 'Custom Fields',
'note' => 'Grants access to the Custom Fields section of the application used by Assets.',
],
'customfieldsview' => [
'name' => 'View Custom Fields',
],
'customfieldscreate' => [
'name' => 'Create New Custom Fields',
],
'customfieldsedit' => [
'name' => 'Edit Custom Fields',
],
'customfieldsdelete' => [
'name' => 'Delete Custom Fields',
],
'suppliers' => [
'name' => 'Suppliers',
'note' => 'Grants access to the Suppliers section of the application.',
],
'suppliersview' => [
'name' => 'View Suppliers',
],
'supplierscreate' => [
'name' => 'Create New Suppliers',
],
'suppliersedit' => [
'name' => 'Edit Suppliers',
],
'suppliersdelete' => [
'name' => 'Delete Suppliers',
],
'manufacturers' => [
'name' => 'Manufacturers',
'note' => 'Grants access to the Manufacturers section of the application.',
],
'manufacturersview' => [
'name' => 'View Manufacturers',
],
'manufacturerscreate' => [
'name' => 'Create New Manufacturers',
],
'manufacturersedit' => [
'name' => 'Edit Manufacturers',
],
'manufacturersdelete' => [
'name' => 'Delete Manufacturers',
],
'companies' => [
'name' => 'Companies',
'note' => 'Grants access to the Companies section of the application.',
],
'companiesview' => [
'name' => 'View Companies',
],
'companiescreate' => [
'name' => 'Create New Companies',
],
'companiesedit' => [
'name' => 'Edit Companies',
],
'companiesdelete' => [
'name' => 'Delete Companies',
],
'user-self-accounts' => [
'name' => 'User Self Accounts',
'note' => 'Grants non-admin users the ability to manage certain aspects of their own user accounts.',
],
'selftwo-factor' => [
'name' => 'Manage Two-Factor Authentication',
'note' => 'Allows users to enable, disable, and manage two-factor authentication for their own accounts.',
],
'selfapi' => [
'name' => 'Manage API Tokens',
'note' => 'Allows users to create, view, and revoke their own API tokens. User tokens will have the same permissions as the user who created them.',
],
'selfedit-location' => [
'name' => 'Edit Location',
'note' => 'Allows users to edit the location associated with their own user account.',
],
'selfcheckout-assets' => [
'name' => 'Self Check Out Assets',
'note' => 'Allows users to check out assets to themselves without admin intervention.',
],
'selfview-purchase-cost' => [
'name' => 'View Purchase Cost',
'note' => 'Allows users to view the purchase cost of items in their account view.',
],
'depreciations' => [
'name' => 'Depreciation Management',
'note' => 'Allows users to manage and view asset depreciation details.',
],
'depreciationsview' => [
'name' => 'View Depreciation Details',
],
'depreciationsedit' => [
'name' => 'Edit Depreciation Settings',
],
'depreciationsdelete' => [
'name' => 'Delete Depreciation Records',
],
'depreciationscreate' => [
'name' => 'Create Depreciation Records',
],
'grant_all' => 'Grant all permissions for :area',
'deny_all' => 'Deny all permissions for :area',
'inherit_all' => 'Inherit all permissions for :area from permission groups',
'grant' => 'Grant Permission for :area',
'deny' => 'Deny Permission for :area',
'inherit' => 'Inherit Permission for :area from permission groups',
'use_groups' => 'We strongly suggest using Permission Groups instead of assigning individual permissions for easier management.'
);

View File

@ -3,67 +3,30 @@
'updateText' => trans('admin/groups/titles.update'),
'item' => $group,
'formAction' => ($group !== null && $group->id !== null) ? route('groups.update', ['group' => $group->id]) : route('groups.store'),
'container_classes' => 'col-lg-6 col-lg-offset-3 col-md-10 col-md-offset-1 col-sm-12 col-sm-offset-0',
'topSubmit' => 'true',
])
@section('content')
<style>
.form-horizontal .control-label {
padding-top: 0px;
}
input[type='text'][disabled], input[disabled], textarea[disabled], input[readonly], textarea[readonly], .form-control[disabled], .form-control[readonly], fieldset[disabled] .form-control {
background-color: white;
color: #555555;
cursor:text;
}
table.permissions {
display:flex;
flex-direction: column;
}
.permissions.table > thead, .permissions.table > tbody {
margin: 15px;
margin-top: 0px;
}
.permissions.table > tbody {
border: 1px solid;
}
.header-row {
border-bottom: 1px solid #ccc;
}
.permissions-row {
display: flex;
justify-content: space-between;
align-items: center;
}
.table > tbody > tr > td.permissions-item {
padding: 1px;
padding-left: 8px;
}
.header-name {
cursor: pointer;
}
</style>
@parent
@stop
@section('inputFields')
<!-- Name -->
<div class="form-group {{ $errors->has('name') ? ' has-error' : '' }}">
<label for="name" class="col-md-2 control-label">{{ trans('admin/groups/titles.group_name') }}</label>
<div class="col-md-9 required">
<label for="name" class="col-md-3 control-label">{{ trans('admin/groups/titles.group_name') }}</label>
<div class="col-md-8 required">
<input class="form-control" type="text" name="name" id="name" value="{{ old('name', $group->name) }}" required />
{!! $errors->first('name', '<span class="alert-msg" aria-hidden="true"><i class="fas fa-times" aria-hidden="true"></i> :message</span>') !!}
</div>
</div>
<div class="form-group{!! $errors->has('notes') ? ' has-error' : '' !!}">
<label for="notes" class="col-md-2 control-label">{{ trans('general.notes') }}</label>
<div class="col-md-9">
<label for="notes" class="col-md-3 control-label">{{ trans('general.notes') }}</label>
<div class="col-md-8">
<x-input.textarea
name="notes"
id="notes"
@ -77,163 +40,41 @@
</div>
</div>
<div class="col-md-12">
<table class="table table-striped permissions">
<thead>
<tr class="permissions-row">
<th class="col-md-5">{{ trans('admin/groups/titles.permission')}}</th>
<th class="col-md-1">{{ trans('admin/groups/titles.grant')}}</th>
<th class="col-md-1">{{ trans('admin/groups/titles.deny')}}</th>
</tr>
</thead>
@foreach ($permissions as $area => $area_permission)
<!-- handle superadmin and reports, and anything else with only one option -->
<?php $localPermission = $area_permission[0]; ?>
@if (count($area_permission) == 1)
<tbody class="permissions-group">
<tr class="header-row permissions-row">
<td class="col-md-5 tooltip-base permissions-item"
data-tooltip="true"
data-placement="right"
title="{{ $localPermission['note'] }}">
@unless (empty($localPermission['label']))
<h2>{{ $area . ': ' . $localPermission['label'] }}</h2>
@else
<h2>{{ $area }}</h2>
@endunless
</td>
<td class="col-md-1 permissions-item">
<label for="{{ 'permission['.$localPermission['permission'].']' }}" style="form-control"><span class="sr-only">{{ trans('admin/groups/titles.allow')}} {{ 'permission['.$localPermission['permission'].']' }}</span></label>
<input
value="1"
aria-label="permission[{{ $localPermission['permission'] }}]"
@checked(array_key_exists($localPermission['permission'], $groupPermissions) && $groupPermissions[$localPermission['permission']] == '1')
name="permission[{{ $localPermission['permission'] }}]"
type="radio"
>
</td>
<td class="col-md-1 permissions-item">
<label for="{{ 'permission['.$localPermission['permission'].']' }}"><span class="sr-only">{{ trans('admin/groups/titles.deny')}} {{ 'permission['.$localPermission['permission'].']' }}</span></label>
<input
value="0"
aria-label="permission[{{ $localPermission['permission'] }}]"
@checked(array_key_exists($localPermission['permission'], $groupPermissions) && $groupPermissions[$localPermission['permission']] == '0')
name="permission[{{ $localPermission['permission'] }}]"
type="radio"
>
</td>
</tr>
</tbody>
@else
<tbody class="permission-group">
<tr class="header-row permissions-row">
<td class="col-md-5 tooltip-base permissions-item header-name"
data-tooltip="true"
data-placement="right"
title="{{ $localPermission['note'] }}">
<h2>{{ $area }}</h2>
<div class="form-group{{ $errors->has('associated_users') ? ' has-error' : '' }}">
<label for="associated_users[]" class="col-md-3 control-label">
{{ trans('general.users') }}
</label>
</td>
<td class="col-md-1 permissions-item" style="vertical-align: bottom">
<label for="{{ $area }}"><span class="sr-only">{{ trans('admin/groups/titles.allow')}} {{ $area }}</span></label>
<input
value="1"
data-checker-group="{{ str_slug($area) }}"
aria-label="{{ $area }}"
name="{{ $area }}"
type="radio"
>
</td>
<td class="col-md-1 permissions-item">
<label for="{{ $area }}"><span class="sr-only">{{ trans('admin/groups/titles.deny')}} {{ $area }}</span></label>
<input
value="0"
data-checker-group="{{ str_slug($area) }}"
aria-label="{{ $area }}"
name="{{ $area }}"
type="radio"
>
</td>
</tr>
<div class="col-md-7">
<select class="js-data-ajax"
data-endpoint="users"
data-placeholder="{{ trans('general.select_user') }}"
name="associated_users[]"
style="width: 100%"
id="associated_users[]"
aria-label="associated_users[]" multiple>
@foreach ($area_permission as $index => $this_permission)
@if ($this_permission['display'])
<tr class="permissions-row">
<td
class="col-md-5 tooltip-base permissions-item"
data-tooltip="true"
data-placement="right"
title="{{ $this_permission['note'] }}">
{{ $this_permission['label'] }}
</td>
<td class="col-md-1 permissions-item">
<label for="{{ 'permission['.$this_permission['permission'].']' }}"><span class="sr-only">{{ trans('admin/groups/titles.allow')}} {{ 'permission['.$this_permission['permission'].']' }}</span></label>
<input
class="radiochecker-{{ str_slug($area) }}"
aria-label="permission[{{ $this_permission['permission'] }}]"
@checked(array_key_exists($this_permission['permission'], $groupPermissions) && $groupPermissions[$this_permission['permission']] == '1')
name="permission[{{ $this_permission['permission'] }}]"
type="radio"
value="1"
>
</td>
<td class="col-md-1 permissions-item">
<label for="{{ 'permission['.$this_permission['permission'].']' }}"><span class="sr-only">{{ trans('admin/groups/titles.deny')}} {{ 'permission['.$this_permission['permission'].']' }}</span></label>
<input
class="radiochecker-{{ str_slug($area) }}"
aria-label="permission[{{ $this_permission['permission'] }}]"
@checked(array_key_exists($this_permission['permission'], $groupPermissions) && $groupPermissions[$this_permission['permission']] == '0')
name="permission[{{ $this_permission['permission'] }}]"
type="radio"
value="0"
>
</td>
<option value="" role="option">{{ trans('general.select_user') }}</option>
@if(isset($associated_users))
@foreach($associated_users as $associated_user)
<option value="{{ $associated_user->id }}" selected="selected" role="option" aria-selected="true"
role="option">
{{ $associated_user->present()->fullName }} ({{ $associated_user->username }})
</option>
@endforeach
@endif
</select>
</div>
</tr>
@endif
@endforeach
@endif
</tbody>
@endforeach
</table>
{!! $errors->first('associated_users', '<div class="col-md-8 col-md-offset-3"><span class="alert-msg" aria-hidden="true"><i class="fas fa-times" aria-hidden="true"></i> :message</span></div>') !!}
</div>
@stop
@section('moar_scripts')
<script nonce="{{ csrf_token() }}">
$(document).ready(function(){
$('.tooltip-base').tooltip({container: 'body'});
$(".superuser").change(function() {
var perms = $(this).val();
if (perms =='1') {
$("#nonadmin").hide();
} else {
$("#nonadmin").show();
}
});
// Check/Uncheck all radio buttons in the group
$('tr.header-row input:radio').change(function() {
value = $(this).attr('value');
area = $(this).data('checker-group');
$('.radiochecker-'+area+'[value='+value+']').prop('checked', true);
});
$('.header-name').click(function() {
$(this).parent().nextUntil('tr.header-row').slideToggle(500);
});
});
</script>
<div class="col-md-12">
@include ('partials.forms.edit.permissions-base', ['use_inherit' => false])
</div>
@stop

View File

@ -24,7 +24,7 @@
<!-- row -->
<div class="row">
<!-- col-md-8 -->
<div class="col-lg-8 col-lg-offset-2 col-md-10 col-md-offset-1 col-sm-12 col-sm-offset-0">
<div class="{{ isset($container_classes) ? $container_classes : 'col-lg-8 col-lg-offset-2 col-md-10 col-md-offset-1 col-sm-12 col-sm-offset-0'}}">
<form id="create-form" class="form-horizontal" method="post" action="{{ (isset($formAction)) ? $formAction : \Request::url() }}" autocomplete="off" role="form" enctype="multipart/form-data">

View File

@ -59,9 +59,14 @@
<div class="col-md-3 col-xs-12">
<label class="control-label" for="modal-password">{{ trans('admin/users/table.password') }}:</label>
</div>
<div class="col-md-8 col-xs-12 " style="margin-bottom:5px;">
<div class="col-md-7 col-xs-12">
<input type='password' name="password" id='modal-password' class="form-control" required>
<a href="#" class="left" id="modal-genPassword">Generate</a>
<div id="modal-generated-password"></div>
</div>
<div class="col-md-1">
<a href="#" class="btn btn-default btn-sm" id="modal-genPassword" data-tooltip="true" title="{{ trans('admin/users/general.generate_password') }}">
<i class="fa-solid fa-wand-magic-sparkles"></i>
</a>
<div id="modal-generated-password"></div>
</div>
</div>
@ -72,9 +77,8 @@
<div class="col-md-3 col-xs-12 ">
<label class="control-label" for="modal-password_confirmation">{{ trans('admin/users/table.password_confirm') }}:</label>
</div>
<div class="col-md-8 col-xs-12">
<div class="col-md-7 col-xs-12">
<input class="form-control" type='password' name="password_confirmation" id='modal-password_confirmation' required>
</div>
</div>
</div>

View File

@ -294,6 +294,28 @@
@endcan
@can('create', \App\Models\Groups::class)
// Groups table buttons
window.groupButtons = () => ({
btnAdd: {
text: '{{ trans('general.create') }}',
icon: 'fa fa-plus',
event () {
window.location.href = '{{ route('groups.create') }}';
},
attributes: {
class: 'btn-info',
title: '{{ trans('general.create') }}',
@if ($snipeSettings->shortcuts_enabled == 1)
accesskey: 'n'
@endif
}
},
}); // End Groups table buttons
@endcan
// Asset table buttons
window.assetButtons = () => ({
@can('create', \App\Models\Asset::class)

View File

@ -1,202 +1,200 @@
@foreach ($permissions as $area => $permissionsArray)
@if (count($permissionsArray) == 1)
<?php $localPermission = $permissionsArray[0]; ?>
<tbody class="permissions-group">
<tr class="header-row permissions-row">
<td class="col-md-5 tooltip-base permissions-item"
data-tooltip="true"
data-placement="right"
title="{{ $localPermission['note'] }}"
@foreach ($permissions as $main_section => $main_section_permission)
<!-- handle superadmin and reports, and anything else with only one option -->
@php
// Ugh, this sucks, but we need to special case reports to map to reports.view
$sectionPermission = $main_section_permission[0];
if ((str_slug($main_section)) == 'reports') {
$section_name = 'reports.view';
} else {
$section_name = str_slug($main_section);
}
@endphp
<div class="form-group {{ ($sectionPermission['permission']!='superuser') ? ' nonsuperuser' : '' }}{{ ( ($sectionPermission['permission']!='superuser') && ($sectionPermission['permission']!='admin')) ? ' nonadmin' : '' }}">
<!-- start callout legend for major sections -->
<div class="callout callout-legend col-md-12">
<!-- start left column with area name and note -->
<div class="col-md-10">
<h4 id="{{ str_slug($sectionPermission['permission'])}}" class="{{ (count($main_section_permission) > 1) ? 'remember-toggle': '' }}">
@if (count($main_section_permission) > 1)
<x-icon type="caret-down" class="fa-fw" id="toggle-arrow-{{ str_slug($sectionPermission['permission'])}}" />
@endif
{{ trans('permissions.'.str_slug($main_section).'.name') }}
</h4>
@if (\Lang::has('permissions.'.str_slug($main_section).'.note'))
<p>{{ trans('permissions.'.str_slug($main_section).'.note') }}</p>
@endif
</div>
<!-- end left column with area name and note -->
<!-- Handle the checkall ALLOW and DENY radios in the right column -->
<div class="col-md-2 text-right header-row">
<div class="radio-toggle-wrapper">
<!-- start .radio-slider-inputs allow -->
<div class="radio-slider-inputs" data-tooltip="true" title="{{ (count($main_section_permission) > 1) ? trans('permissions.grant_all', ['area' => $main_section]) : trans('permissions.grant', ['area' => $main_section]) }}">
<input
class="form-control {{ str_slug($main_section) }} allow"
data-checker-group="{{ str_slug($main_section) }}"
aria-label="{{ str_slug($main_section) }}"
name="permission[{{ $section_name }}]"
@checked(array_key_exists($section_name, $groupPermissions) && $groupPermissions[$section_name] == '1')
type="radio"
value="1"
{{-- Disable the superuser and admin allow if the user is not a superuser --}}
@if (((str_slug($main_section) == 'admin') && (!auth()->user()->hasAccess('admin'))) || ((str_slug($main_section) == 'superuser') && (!auth()->user()->isSuperUser())))
disabled
@endif
id="{{ str_slug($main_section) }}_allow"
>
<label class="allow" for="{{ str_slug($main_section) }}_allow">
<i class="fa-solid fa-square-check"></i>
</label>
</div>
<!-- end .radio-slider-inputs allow -->
<!-- start .radio-slider-inputs inherit if used -->
@if ($use_inherit)
<div class="radio-slider-inputs" data-tooltip="true" title="{{ (count($main_section_permission) > 1) ? trans('permissions.inherit_all', ['area' => $main_section]) : trans('permissions.inherit', ['area' => $main_section]) }}">
<input
class="form-control {{ str_slug($main_section) }} inherit"
data-checker-group="{{ str_slug($main_section) }}"
aria-label="{{ str_slug($main_section) }}"
name="permission[{{ str_slug($main_section) }}]"
@checked((array_key_exists(str_slug($main_section), $groupPermissions) && $groupPermissions[str_slug($main_section)] == '0') || (!array_key_exists(str_slug($main_section), $groupPermissions)))
type="radio"
value="0"
{{-- Disable the superuser and admin allow if the user is not a superuser --}}
@if (((str_slug($main_section) == 'admin') && (!auth()->user()->hasAccess('admin'))) || ((str_slug($main_section) == 'superuser') && (!auth()->user()->isSuperUser())))
disabled
@endif
id="{{ str_slug($main_section) }}_inherit"
>
<label class="inherit" for="{{ str_slug($main_section) }}_inherit">
<i class="fa-solid fa-layer-group"></i>
</label>
</div>
@endif
<!-- end .radio-slider-inputs inherit if used -->
<!-- start .radio-slider-inputs deny -->
<div class="radio-slider-inputs" data-tooltip="true" title="{{ (count($main_section_permission) > 1) ? trans('permissions.deny_all', ['area' => $main_section]) : trans('permissions.deny', ['area' => $main_section]) }}">
<input
class="form-control {{ str_slug($main_section) }} deny"
data-checker-group="{{ str_slug($main_section) }}"
aria-label="{{ str_slug($main_section) }}"
name="permission[{{ str_slug($main_section) }}]"
@checked(array_key_exists(str_slug($main_section), $groupPermissions) && $groupPermissions[str_slug($main_section)] == '-1')
type="radio"
value="-1"
{{-- Disable the superuser and admin allow if the user is not a superuser --}}
@if (((str_slug($main_section) == 'admin') && (!auth()->user()->hasAccess('admin'))) || ((str_slug($main_section) == 'superuser') && (!auth()->user()->isSuperUser())))
disabled
@endif
id="{{ str_slug($main_section) }}_deny"
>
<label class="deny" for="{{ str_slug($main_section) }}_deny">
<i class="fa-solid fa-square-xmark"></i>
</label>
</div>
<!-- end .radio-slider-inputs deny -->
</div> <!-- end .radio-toggle-wrapper -->
</div> <!-- end right column radios -->
</div> <!-- end callout legend for major sections -->
</div> <!-- end form row -->
<!-- now handle sub-permissions if they exist -->
@if (count($main_section_permission) > 2)
<div
class="toggle-content-{{ str_slug($sectionPermission['permission']) }} {{ str_slug($sectionPermission['permission']) }}
{{ ($sectionPermission['permission']!='superuser') ? ' nonsuperuser' : '' }}{{ ( ($sectionPermission['permission']!='superuser') && ($sectionPermission['permission']!='admin')) ? ' nonadmin' : '' }}"
>
@unless (empty($localPermission['label']))
<h2>{{ $area . ': ' . $localPermission['label'] }}</h2>
@else
<h2>{{ $area }}</h2>
@endunless
</td>
<td class="col-md-1 permissions-item">
<label class="sr-only" for="{{ 'permission['.$localPermission['permission'].']' }}">{{ 'permission['.$localPermission['permission'].']' }}</label>
@if (($localPermission['permission'] == 'superuser') && (!Auth::user()->isSuperUser()))
<input
disabled="disabled"
aria-label="permission[{{ $localPermission['permission'] }}]"
@checked($userPermissions[$localPermission['permission']] == '1')
name="permission[{{ $localPermission['permission'] }}]"
type="radio"
value="1"
/>
@elseif (($localPermission['permission'] == 'admin') && (!Auth::user()->hasAccess('admin')))
<input
disabled="disabled"
aria-label="permission[{{ $localPermission['permission'] }}]"
@checked($userPermissions[$localPermission['permission']] == '1')
name="permission[{{ $localPermission['permission'] }}]"
type="radio"
value="1"
/>
@else
<input
aria-label="permission[{{ $localPermission['permission'] }}]"
@checked($userPermissions[$localPermission['permission']] == '1')
name="permission[{{ $localPermission['permission'] }}]"
type="radio"
value="1"
/>
@endif
@foreach ($main_section_permission as $index => $this_permission)
@if ($this_permission['display'])
</td>
<td class="col-md-1 permissions-item">
<label class="sr-only" for="{{ 'permission['.$localPermission['permission'].']' }}">{{ 'permission['.$localPermission['permission'].']' }}</label>
@if (($localPermission['permission'] == 'superuser') && (!Auth::user()->isSuperUser()))
<input
disabled="disabled"
aria-label="permission[{{ $localPermission['permission'] }}]"
@checked($userPermissions[$localPermission['permission']] == '-1')
name="permission[{{ $localPermission['permission'] }}]"
type="radio"
value="-1"
/>
@elseif (($localPermission['permission'] == 'admin') && (!Auth::user()->hasAccess('admin')))
<input
disabled="disabled"
aria-label="permission[{{ $localPermission['permission'] }}]"
@checked($userPermissions[$localPermission['permission']] == '-1')
name="permission[{{ $localPermission['permission'] }}]"
type="radio"
value="-1"
/>
@else
<input
aria-label="permission[{{ $localPermission['permission'] }}]"
@checked($userPermissions[$localPermission['permission']] == '-1')
name="permission[{{ $localPermission['permission'] }}]"
type="radio"
value="-1"
/>
@endif
</td>
<td class="col-md-1 permissions-item">
<label class="sr-only" for="{{ 'permission['.$localPermission['permission'].']' }}">
{{ 'permission['.$localPermission['permission'].']' }}</label>
@if (($localPermission['permission'] == 'superuser') && (!Auth::user()->isSuperUser()))
<input
disabled="disabled"
aria-label="permission[{{ $localPermission['permission'] }}]"
@checked($userPermissions[$localPermission['permission']] == '0')
name="permission[{{ $localPermission['permission'] }}]"
type="radio"
value="0"
/>
@elseif (($localPermission['permission'] == 'admin') && (!Auth::user()->hasAccess('admin')))
<input
disabled="disabled"
aria-label="permission[{{ $localPermission['permission'] }}]"
@checked($userPermissions[$localPermission['permission']] == '0')
name="permission[{{ $localPermission['permission'] }}]"
type="radio"
value="0"
/>
@else
<input
aria-label="permission[{{ $localPermission['permission'] }}]"
@checked($userPermissions[$localPermission['permission']] == '0')
name="permission[{{ $localPermission['permission'] }}]"
type="radio"
value="0"
/>
@endif
</td>
</tr>
</tbody>
@php
$section_translation = trans('permissions.'.str_slug($this_permission['permission']).'.name');
@endphp
@else <!-- count($permissionsArray) == 1-->
<tbody class="permissions-group">
<tr class="header-row permissions-row">
<td class="col-md-5 header-name">
<h2> {{ $area }}</h2>
</td>
<td class="col-md-1 permissions-item">
<label for="{{ $area }}" class="sr-only">{{ $area }}</label>
<input
value="1"
data-checker-group="{{ str_slug($area) }}"
aria-label="{{ $area }}"
name="{{ $area }}"
type="radio"
/>
</td>
<td class="col-md-1 permissions-item">
<label for="{{ $area }}" class="sr-only">{{ $area }}</label>
<input
value="-1"
data-checker-group="{{ str_slug($area) }}"
aria-label="{{ $area }}"
name="{{ $area }}"
type="radio"
/>
</td>
<td class="col-md-1 permissions-item">
<label for="{{ $area }}" class="sr-only">{{ $area }}</label>
<input
value="0"
data-checker-group="{{ str_slug($area) }}"
aria-label="{{ $area }}"
name="{{ $area }}"
type="radio"
/>
</td>
</tr>
<div class="form-group" style="border-bottom: 1px solid #eee; padding-right: 13px;">
<div class="col-md-10">
<strong>{{ $section_translation }}</strong>
@if (\Lang::has('permissions.'.str_slug($this_permission['permission']).'.note'))
<p>{{ trans('permissions.'.str_slug($this_permission['permission']).'.note') }}</p>
@endif
</div>
@foreach ($permissionsArray as $index => $permission)
<tr class="permissions-row">
@if ($permission['display'])
<td
class="col-md-5 tooltip-base permissions-item"
data-tooltip="true"
data-placement="right"
title="{{ $permission['note'] }}"
>
{{ $permission['label'] }}
</td>
<td class="col-md-1 permissions-item">
<label class="sr-only" for="{{ 'permission['.$permission['permission'].']' }}">{{ 'permission['.$permission['permission'].']' }}</label>
<input
value="1"
class="radiochecker-{{ str_slug($area) }}"
aria-label="permission[{{ $permission['permission'] }}]"
@checked($userPermissions[$permission['permission']] == '1')
@disabled(($permission['permission'] == 'superuser') && (!Auth::user()->isSuperUser()))
name="permission[{{ $permission['permission'] }}]"
type="radio"
/>
</td>
<td class="col-md-1 permissions-item">
<input
value="-1"
class="radiochecker-{{ str_slug($area) }}"
aria-label="permission[{{ $permission['permission'] }}]"
@checked($userPermissions[$permission['permission']] == '-1')
@disabled(($permission['permission'] == 'superuser') && (!Auth::user()->isSuperUser()))
name="permission[{{ $permission['permission'] }}]"
type="radio"
/>
</td>
<td class="col-md-1 permissions-item">
<input
value="0"
class="radiochecker-{{ str_slug($area) }}"
aria-label="permission[{{ $permission['permission'] }}]"
@checked($userPermissions[$permission['permission']] =='0')
@disabled(($permission['permission'] == 'superuser') && (!Auth::user()->isSuperUser()))
name="permission[{{ $permission['permission'] }}]"
type="radio"
/>
</td>
@endif
</tr>
@endforeach
</tbody>
<div class="form-group col-md-2 text-right">
<div class="radio-toggle-wrapper">
<div class="radio-slider-inputs" data-tooltip="true" title="{{ trans('permissions.grant', ['area' => $section_translation]) }}">
<input
class="form-control allow radiochecker-{{ str_slug($main_section) }}"
aria-label="permission[{{ $this_permission['permission'] }}]"
@checked(array_key_exists($this_permission['permission'], $groupPermissions) && $groupPermissions[$this_permission['permission']] == '1')
name="permission[{{ $this_permission['permission'] }}]"
type="radio"
id="{{ str_slug($this_permission['permission']) }}_allow"
value="1"
>
<label for="{{ str_slug($this_permission['permission']) }}_allow" class="allow">
<i class="fa-solid fa-square-check"></i>
</label>
</div>
@if ($use_inherit)
<div class="radio-slider-inputs" data-tooltip="true" title="{{ trans('permissions.inherit', ['area' => $section_translation]) }}">
<input
class="form-control inherit radiochecker-{{ str_slug($main_section) }}"
aria-label="permission[{{ $this_permission['permission'] }}]"
@checked(array_key_exists($this_permission['permission'], $groupPermissions) && $groupPermissions[$this_permission['permission']] == '0')
name="permission[{{ $this_permission['permission'] }}]"
type="radio"
id="{{ str_slug($this_permission['permission']) }}_inherit"
value="0"
>
<label for="{{ str_slug($this_permission['permission']) }}_inherit" class="inherit">
<i class="fa-solid fa-layer-group"></i>
</label>
</div>
@endif
<div class="radio-slider-inputs" data-tooltip="true" title="{{ trans('permissions.deny', ['area' => $section_translation]) }}">
<input
class="form-control deny radiochecker-{{ str_slug($main_section) }}"
aria-label="permission[{{ $this_permission['permission'] }}]"
@checked(array_key_exists($this_permission['permission'], $groupPermissions) && $groupPermissions[$this_permission['permission']] == '-1')
name="permission[{{ $this_permission['permission'] }}]"
type="radio"
value="-1"
id="{{ str_slug($this_permission['permission']) }}_deny"
>
<label for="{{ str_slug($this_permission['permission']) }}_deny">
<i class="fa-solid fa-square-xmark"></i>
</label>
</div>
</div>
</div>
</div>
@endif
@endforeach
</div>
@endif
@endforeach

View File

@ -29,38 +29,7 @@
color: #555555;
cursor:text;
}
table.permissions {
display:flex;
flex-direction: column;
}
.permissions.table > thead, .permissions.table > tbody {
margin: 15px;
margin-top: 0px;
}
.permissions.table > tbody {
border: 1px solid;
}
.header-row {
border-bottom: 1px solid #ccc;
}
.permissions-row {
display: flex;
justify-content: space-between;
align-items: center;
}
.table > tbody > tr > td.permissions-item {
padding: 1px;
padding-left: 8px;
}
.header-name {
cursor: pointer;
}
</style>
@ -176,10 +145,12 @@
</div>
<div class="col-md-2">
<div class="col-md-1 pull-left">
@if (Gate::allows('editableOnDemo') && (Gate::allows('canEditAuthFields', $user)) && ($user->ldap_import!='1'))
<a href="#" class="left" id="genPassword">{{ trans('general.generate') }}</a>
<a href="#" class="text-left btn btn-default btn-sm" id="genPassword" data-tooltip="true" title="{{ trans('admin/users/general.generate_password') }}">
<i class="fa-solid fa-wand-magic-sparkles"></i>
</a>
@endif
</div>
</div>
@ -320,18 +291,16 @@
<div class="col-md-12">
<fieldset name="optional-details">
<fieldset name="optional_details">
<x-form-legend>
<a id="optional_user_info">
<x-icon type="caret-right" id="optional_user_info_icon" />
<h4 id="optional_details" class="remember-toggle optional_details">
<x-icon type="caret-right" class="fa-fw" id="toggle-arrow-optional_details" />
{{ trans('admin/hardware/form.optional_infos') }}
</a>
</h4>
</x-form-legend>
<div id="optional_user_details" class="col-md-12" style="display:none">
<div class="col-md-12 toggle-content-optional_details" style="display:none">
<!-- everything here should be what is considered optional -->
<br>
@ -663,27 +632,24 @@
@can('admin')
<div class="tab-pane" id="permissions">
<div class="col-md-12">
@if (!Auth::user()->isSuperUser())
<p class="alert alert-warning">{{ trans('admin/users/general.superadmin_permission_warning') }}</p>
@endif
@if (!Auth::user()->isSuperUser())
<p class="alert alert-warning">{{ trans('admin/users/general.superadmin_permission_warning') }}</p>
@endif
@if (!Auth::user()->hasAccess('admin'))
<p class="alert alert-warning">{{ trans('admin/users/general.admin_permission_warning') }}</p>
@endif
<p class="alert alert-info">
{{ trans('permissions.use_groups') }}
</p>
<div class="col-md-12">
@include('partials.forms.edit.permissions-base', ['use_inherit' => true, 'groupPermissions' => $userPermissions])
</div>
@if (!Auth::user()->hasAccess('admin'))
<p class="alert alert-warning">{{ trans('admin/users/general.admin_permission_warning') }}</p>
@endif
</div>
<table class="table table-striped permissions">
<thead>
<tr class="permissions-row">
<th class="col-md-5">{{ trans('admin/groups/titles.permission') }}</th>
<th class="col-md-1">{{ trans('admin/groups/titles.grant') }}</th>
<th class="col-md-1">{{ trans('admin/groups/titles.deny') }}</th>
<th class="col-md-1">{{ trans('admin/users/table.inherit') }}</th>
</tr>
</thead>
@include('partials.forms.edit.permissions-base')
</table>
</div><!-- /.tab-pane -->
@endcan
</div><!-- /.tab-content -->
@ -731,34 +697,15 @@ $(document).ready(function() {
@endif
});
// Check/Uncheck all radio buttons in the group
$('tr.header-row input:radio').change(function() {
value = $(this).attr('value');
area = $(this).data('checker-group');
$('.radiochecker-'+area+'[value='+value+']').prop('checked', true);
});
$('.header-name').click(function() {
$(this).parent().nextUntil('tr.header-row').slideToggle(500);
});
$('.tooltip-base').tooltip({container: 'body'})
$(".superuser").change(function() {
var perms = $(this).val();
if (perms =='1') {
$("#nonadmin").hide();
} else {
$("#nonadmin").show();
}
});
$('#genPassword').pGenerator({
'bind': 'click',
'passwordElement': '#password',
'displayElement': '#generated-password',
'passwordLength': {{ ($settings->pwd_secure_min + 5) }},
'passwordLength': {{ ($settings->pwd_secure_min + 9) }},
'uppercase': true,
'lowercase': true,
'numbers': true,
@ -768,23 +715,6 @@ $(document).ready(function() {
}
});
$("#optional_user_info").on("click",function(){
$('#optional_user_details').fadeToggle(100);
$('#optional_user_info_icon').toggleClass('fa-caret-right fa-caret-down');
var optional_user_info_open = $('#optional_user_info_icon').hasClass('fa-caret-down');
document.cookie = "optional_user_info_open="+optional_user_info_open+'; path=/';
});
var all_cookies = document.cookie.split(';')
for(var i in all_cookies) {
var trimmed_cookie = all_cookies[i].trim(' ')
if (trimmed_cookie.startsWith('optional_user_info_open=')) {
elems = all_cookies[i].split('=', 2)
if (elems[1] == 'true') {
$('#optional_user_info').trigger('click')
}
}
}
$("#two_factor_reset").click(function(){
$("#two_factor_resetrow").removeClass('success');
@ -816,6 +746,8 @@ $(document).ready(function() {
});
});
</script>

View File

@ -426,17 +426,19 @@
<div class="col-md-9">
@if ($user->groups->count() > 0)
@foreach ($user->groups as $group)
@can('superadmin')
<a href="{{ route('groups.show', $group->id) }}" class="label label-default">{{ $group->name }}</a>
@else
{{ $group->name }}
@endcan
@endforeach
@else
--
@endif
@if ($user->hasIndividualPermissions())
<span class="text-warning"><x-icon type="warning" /> {{ trans('admin/users/general.individual_override') }}</span>
@endif
</div>
</div>