Merge branch 'snipeit_v7_laravel10' into snipeit_v7_laravel10_livewire3

This commit is contained in:
Brady Wetherington 2023-08-31 13:11:37 +01:00
commit aec33e7c8d
65 changed files with 330 additions and 86 deletions

73
.github/workflows/tests.yml vendored Normal file
View file

@ -0,0 +1,73 @@
name: Tests
on:
push:
branches:
- master
- develop
pull_request:
jobs:
tests:
runs-on: ubuntu-latest
services:
mysql:
image: mysql:5.7
env:
MYSQL_ALLOW_EMPTY_PASSWORD: yes
MYSQL_DATABASE: snipeit
ports:
- 33306:3306
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
strategy:
fail-fast: false
matrix:
php-version:
- "7.4"
- "8.0"
- "8.1.1"
name: PHP ${{ matrix.php-version }}
steps:
- uses: shivammathur/setup-php@v2
with:
php-version: "${{ matrix.php-version }}"
coverage: none
- uses: actions/checkout@v3
- name: Get Composer Cache Directory
id: composer-cache
run: |
echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
- uses: actions/cache@v3
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-${{ matrix.php-version }}-composer-${{ hashFiles('**/composer.lock') }}
restore-keys: |
${{ runner.os }}-composer-
- name: Copy .env
run: |
cp -v .env.testing.example .env
cp -v .env.testing.example .env.testing
- name: Install Dependencies
run: composer install -q --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist
- name: Generate key
run: php artisan key:generate
- name: Directory Permissions
run: chmod -R 777 storage bootstrap/cache
- name: Execute tests (Unit and Feature tests) via PHPUnit
env:
DB_CONNECTION: mysql
DB_DATABASE: snipeit
DB_PORT: ${{ job.services.mysql.ports[3306] }}
DB_USERNAME: root
run: php artisan test --parallel

View file

@ -75,7 +75,6 @@ class UsersController extends Controller
])->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');
$users = Company::scopeCompanyables($users);
if ($request->filled('activated')) {
@ -271,6 +270,8 @@ class UsersController extends Controller
} elseif (($request->filled('all')) && ($request->input('all') == 'true')) {
$users = $users->withTrashed();
}
$users = Company::scopeCompanyables($users);
$total = $users->count();
$users = $users->skip($offset)->take($limit)->get();

View file

@ -286,6 +286,7 @@ class AssetModelsController extends Controller
return view('models/edit')
->with('depreciation_list', Helper::depreciationList())
->with('item', $model)
->with('model_id', $model_to_clone->id)
->with('clone_model', $model_to_clone);
}

View file

@ -82,7 +82,6 @@ class Asset extends Depreciable
'location_id' => 'integer',
'rtd_company_id' => 'integer',
'supplier_id' => 'integer',
'byod' => 'boolean',
'created_at' => 'datetime',
'updated_at' => 'datetime',
'deleted_at' => 'datetime',
@ -105,6 +104,7 @@ class Asset extends Depreciable
'purchase_cost' => 'numeric|nullable|gte:0',
'supplier_id' => 'exists:suppliers,id|nullable',
'asset_eol_date' => 'date|max:10|min:10|nullable',
'byod' => 'boolean',
];
/**

View file

@ -69,15 +69,12 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
];
protected $casts = [
'activated' => 'boolean',
'manager_id' => 'integer',
'location_id' => 'integer',
'company_id' => 'integer',
'vip' => 'boolean',
'created_at' => 'datetime',
'updated_at' => 'datetime',
'deleted_at' => 'datetime',
'autoassign_licenses' => 'boolean',
];
/**
@ -103,6 +100,9 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
'state' => 'min:2|max:191|nullable',
'country' => 'min:2|max:191|nullable',
'zip' => 'max:10|nullable',
'vip' => 'boolean',
'remote' => 'boolean',
'activated' => 'boolean',
];
/**

View file

@ -69,7 +69,7 @@ return [
'mysql' => [
'driver' => 'mysql',
'host' => env('DB_HOST', 'localhost'),
'port' => env('DB_PORT', '3306'),
'port' => env('DB_PORT', 3306),
'database' => env('DB_DATABASE', 'forge'),
'username' => env('DB_USERNAME', 'forge'),
'password' => env('DB_PASSWORD', ''),

View file

@ -1,10 +1,10 @@
<?php
return array (
'app_version' => 'v6.1.2',
'full_app_version' => 'v6.1.2 - build 10938-g32747cafd',
'build_version' => '10938',
'app_version' => 'v6.2.0-pre',
'full_app_version' => 'v6.2.0-pre - build 11391-g319cb2305',
'build_version' => '11391',
'prerelease_version' => '',
'hash_version' => 'g32747cafd',
'full_hash' => 'v6.1.2-89-g32747cafd',
'hash_version' => 'g319cb2305',
'full_hash' => 'v6.2.0-pre-451-g319cb2305',
'branch' => 'develop',
);

14
package-lock.json generated
View file

@ -5,7 +5,7 @@
"packages": {
"": {
"dependencies": {
"@fortawesome/fontawesome-free": "^6.4.0",
"@fortawesome/fontawesome-free": "^6.4.2",
"acorn": "^8.9.0",
"acorn-import-assertions": "^1.9.0",
"admin-lte": "^2.4.18",
@ -25,7 +25,7 @@
"jquery-ui-bundle": "^1.12.1",
"jquery.iframe-transport": "^1.0.0",
"jspdf-autotable": "^3.5.30",
"less": "^4.1.2",
"less": "^4.2.0",
"less-loader": "^6.0",
"list.js": "^1.5.0",
"morris.js": "github:morrisjs/morris.js",
@ -1809,9 +1809,10 @@
}
},
"node_modules/@fortawesome/fontawesome-free": {
"version": "6.4.0",
"version": "6.4.2",
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-6.4.2.tgz",
"integrity": "sha512-m5cPn3e2+FDCOgi1mz0RexTUvvQibBebOUlUlW0+YrMjDTPkiJ6VTKukA1GRsvRw+12KyJndNjj0O4AgTxm2Pg==",
"hasInstallScript": true,
"license": "(CC-BY-4.0 AND OFL-1.1 AND MIT)",
"engines": {
"node": ">=6"
}
@ -7435,8 +7436,9 @@
}
},
"node_modules/less": {
"version": "4.1.3",
"license": "Apache-2.0",
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/less/-/less-4.2.0.tgz",
"integrity": "sha512-P3b3HJDBtSzsXUl0im2L7gTO5Ubg8mEN6G8qoTS77iXxXX4Hvu4Qj540PZDvQ8V6DmX6iXo98k7Md0Cm1PrLaA==",
"dependencies": {
"copy-anything": "^2.0.1",
"parse-node-version": "^1.0.1",

View file

@ -24,7 +24,7 @@
"vue-template-compiler": "2.4.4"
},
"dependencies": {
"@fortawesome/fontawesome-free": "^6.4.0",
"@fortawesome/fontawesome-free": "^6.4.2",
"acorn": "^8.9.0",
"acorn-import-assertions": "^1.9.0",
"admin-lte": "^2.4.18",
@ -44,7 +44,7 @@
"jquery-ui-bundle": "^1.12.1",
"jquery.iframe-transport": "^1.0.0",
"jspdf-autotable": "^3.5.30",
"less": "^4.1.2",
"less": "^4.2.0",
"less-loader": "^6.0",
"list.js": "^1.5.0",
"morris.js": "github:morrisjs/morris.js",

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
public/js/dist/all.js vendored

Binary file not shown.

Binary file not shown.

View file

@ -1,51 +1,51 @@
{
"/js/build/app.js": "/js/build/app.js?id=75701cda1dcce0fdc67ea42761c97e98",
"/css/dist/skins/skin-blue.css": "/css/dist/skins/skin-blue.css?id=f677207c6cf9678eb539abecb408c374",
"/css/build/overrides.css": "/css/build/overrides.css?id=5166569ede5a36802eadeea982686ca6",
"/css/build/app.css": "/css/build/app.css?id=b612c48e78fece2e1e8042ae24cc5f1e",
"/css/build/AdminLTE.css": "/css/build/AdminLTE.css?id=4ea0068716c1bb2434d87a16d51b98c9",
"/css/dist/skins/skin-orange.css": "/css/dist/skins/skin-orange.css?id=6f0563e726c2fe4fab4026daaa5bfdf2",
"/css/dist/skins/skin-orange-dark.css": "/css/dist/skins/skin-orange-dark.css?id=e6e53eef152bba01a4c666a4d8b01117",
"/css/dist/skins/skin-blue-dark.css": "/css/dist/skins/skin-blue-dark.css?id=07273f6ca3c698a39e8fc2075af4fa07",
"/css/dist/skins/skin-yellow-dark.css": "/css/dist/skins/skin-yellow-dark.css?id=c1f33574ecb9d3e69d9b8fe5bd68e101",
"/css/dist/skins/skin-yellow.css": "/css/dist/skins/skin-yellow.css?id=7b315b9612b8fde8f9c5b0ddb6bba690",
"/css/dist/skins/skin-purple-dark.css": "/css/dist/skins/skin-purple-dark.css?id=7d92dea45d94be7e1d4e427c728d335d",
"/css/dist/skins/skin-purple.css": "/css/dist/skins/skin-purple.css?id=6fe68325d5356197672c27bc77cedcb4",
"/css/dist/skins/skin-red-dark.css": "/css/dist/skins/skin-red-dark.css?id=8ca888bbc050d9680cbb65021382acba",
"/css/dist/skins/skin-black-dark.css": "/css/dist/skins/skin-black-dark.css?id=bdfc704731682c67645a2248b0b8d2d7",
"/css/dist/skins/skin-black.css": "/css/dist/skins/skin-black.css?id=76482123f6c70e866d6b971ba91de7bb",
"/css/dist/skins/skin-green-dark.css": "/css/dist/skins/skin-green-dark.css?id=e36e83c2aa3c3afdbb8ebe2c0309e91d",
"/css/dist/skins/skin-green.css": "/css/dist/skins/skin-green.css?id=0a82a6ae6bb4e58fe62d162c4fb50397",
"/css/dist/skins/skin-contrast.css": "/css/dist/skins/skin-contrast.css?id=da6c7997d9de2f8329142399f0ce50da",
"/css/dist/skins/skin-red.css": "/css/dist/skins/skin-red.css?id=44bf834f2110504a793dadec132a5898",
"/css/dist/all.css": "/css/dist/all.css?id=e907c22c9a9fd1a4c5421f28125338ba",
"/js/build/app.js": "/js/build/app.js?id=cb74c1cf7b4e1b135fe76d57a7f26045",
"/css/dist/skins/skin-blue.css": "/css/dist/skins/skin-blue.css?id=392cc93cfc0be0349bab9697669dd091",
"/css/build/overrides.css": "/css/build/overrides.css?id=eb013ebb79d92e25ce24b0c0b53185e4",
"/css/build/app.css": "/css/build/app.css?id=ac51a0600b419996e705675b6fcf1a8b",
"/css/build/AdminLTE.css": "/css/build/AdminLTE.css?id=a67bd93bed52e6a29967fe472de66d6c",
"/css/dist/skins/skin-orange.css": "/css/dist/skins/skin-orange.css?id=268041e902b019730c23ee3875838005",
"/css/dist/skins/skin-orange-dark.css": "/css/dist/skins/skin-orange-dark.css?id=d409d9b1a3b69247df8b98941ba06e33",
"/css/dist/skins/skin-blue-dark.css": "/css/dist/skins/skin-blue-dark.css?id=4a9e8c5e7b09506fa3e3a3f42849e07f",
"/css/dist/skins/skin-yellow-dark.css": "/css/dist/skins/skin-yellow-dark.css?id=21fef066e0bb1b02fd83fcb6694fad5f",
"/css/dist/skins/skin-yellow.css": "/css/dist/skins/skin-yellow.css?id=fc7adb943668ac69fe4b646625a7571f",
"/css/dist/skins/skin-purple-dark.css": "/css/dist/skins/skin-purple-dark.css?id=9f944e8021781af1ce45d27765d1c0c2",
"/css/dist/skins/skin-purple.css": "/css/dist/skins/skin-purple.css?id=cf6c8c340420724b02d6e787ef9bded5",
"/css/dist/skins/skin-red-dark.css": "/css/dist/skins/skin-red-dark.css?id=7f0eb9e355b36b41c61c3af3b4d41143",
"/css/dist/skins/skin-black-dark.css": "/css/dist/skins/skin-black-dark.css?id=f4d95ad9d0944587549e35b6929b4b04",
"/css/dist/skins/skin-black.css": "/css/dist/skins/skin-black.css?id=1f33ca3d860461c1127ec465ab3ebb6b",
"/css/dist/skins/skin-green-dark.css": "/css/dist/skins/skin-green-dark.css?id=44f9320d0739f419c9246f7f39395b02",
"/css/dist/skins/skin-green.css": "/css/dist/skins/skin-green.css?id=b48f4d8af0e1ca5621c161e93951109f",
"/css/dist/skins/skin-contrast.css": "/css/dist/skins/skin-contrast.css?id=f0fbbb0ac729ea092578fb05ca615460",
"/css/dist/skins/skin-red.css": "/css/dist/skins/skin-red.css?id=b9a74ec0cd68f83e7480d5ae39919beb",
"/css/dist/all.css": "/css/dist/all.css?id=829410b57e28448fef5c57beda0861e3",
"/css/dist/signature-pad.css": "/css/dist/signature-pad.css?id=6a89d3cd901305e66ced1cf5f13147f7",
"/css/dist/signature-pad.min.css": "/css/dist/signature-pad.min.css?id=6a89d3cd901305e66ced1cf5f13147f7",
"/css/webfonts/fa-brands-400.ttf": "/css/webfonts/fa-brands-400.ttf?id=e2e2b1797606a266ed55549f5bb5a179",
"/css/webfonts/fa-brands-400.woff2": "/css/webfonts/fa-brands-400.woff2?id=fe912d1c4a7e0e1db87a64eb7e54c945",
"/css/webfonts/fa-regular-400.ttf": "/css/webfonts/fa-regular-400.ttf?id=31a6b5ecfc8d018d0e3a294f0c80e9e9",
"/css/webfonts/fa-regular-400.woff2": "/css/webfonts/fa-regular-400.woff2?id=bf8eabe300a00a3adb0293596987abc4",
"/css/webfonts/fa-solid-900.ttf": "/css/webfonts/fa-solid-900.ttf?id=cd687455c6d6c058e2e9f84f409e2965",
"/css/webfonts/fa-solid-900.woff2": "/css/webfonts/fa-solid-900.woff2?id=eea38615e7b5dbbaf88c263f2230cc32",
"/css/webfonts/fa-v4compatibility.ttf": "/css/webfonts/fa-v4compatibility.ttf?id=6ebbf5afc34f54463abc2b81ca637364",
"/css/webfonts/fa-v4compatibility.woff2": "/css/webfonts/fa-v4compatibility.woff2?id=67b8a78b7e80e805cfa4ee0421895ba4",
"/css/webfonts/fa-brands-400.ttf": "/css/webfonts/fa-brands-400.ttf?id=a656b2d865fe379d8851757e8e4001ef",
"/css/webfonts/fa-brands-400.woff2": "/css/webfonts/fa-brands-400.woff2?id=a6761c03f9c021aeb9754283755b660e",
"/css/webfonts/fa-regular-400.ttf": "/css/webfonts/fa-regular-400.ttf?id=75a44676b684c784508452a53867e8da",
"/css/webfonts/fa-regular-400.woff2": "/css/webfonts/fa-regular-400.woff2?id=c612044da7f7b81ab8f2cadf94964208",
"/css/webfonts/fa-solid-900.ttf": "/css/webfonts/fa-solid-900.ttf?id=3867ccc7ab681d3c27d1e97a792b46d3",
"/css/webfonts/fa-solid-900.woff2": "/css/webfonts/fa-solid-900.woff2?id=7f63d634454e771396bce3e09dfcdbc5",
"/css/webfonts/fa-v4compatibility.ttf": "/css/webfonts/fa-v4compatibility.ttf?id=70ad875b2378eb850254f01dec991ade",
"/css/webfonts/fa-v4compatibility.woff2": "/css/webfonts/fa-v4compatibility.woff2?id=d36941873b661076f146b0221f13497d",
"/css/dist/bootstrap-table.css": "/css/dist/bootstrap-table.css?id=281bcfe26549412d128f695234961081",
"/js/build/vendor.js": "/js/build/vendor.js?id=8ac1d250496313e93744790e5138305d",
"/js/dist/bootstrap-table.js": "/js/dist/bootstrap-table.js?id=df78f0c4cc93c29c02a41144590f6350",
"/js/dist/all.js": "/js/dist/all.js?id=2961f40174dda4743e62c8e4c8891b42",
"/css/dist/skins/skin-green.min.css": "/css/dist/skins/skin-green.min.css?id=0a82a6ae6bb4e58fe62d162c4fb50397",
"/css/dist/skins/skin-green-dark.min.css": "/css/dist/skins/skin-green-dark.min.css?id=e36e83c2aa3c3afdbb8ebe2c0309e91d",
"/css/dist/skins/skin-black.min.css": "/css/dist/skins/skin-black.min.css?id=76482123f6c70e866d6b971ba91de7bb",
"/css/dist/skins/skin-black-dark.min.css": "/css/dist/skins/skin-black-dark.min.css?id=bdfc704731682c67645a2248b0b8d2d7",
"/css/dist/skins/skin-blue.min.css": "/css/dist/skins/skin-blue.min.css?id=f677207c6cf9678eb539abecb408c374",
"/css/dist/skins/skin-blue-dark.min.css": "/css/dist/skins/skin-blue-dark.min.css?id=07273f6ca3c698a39e8fc2075af4fa07",
"/css/dist/skins/skin-yellow.min.css": "/css/dist/skins/skin-yellow.min.css?id=7b315b9612b8fde8f9c5b0ddb6bba690",
"/css/dist/skins/skin-yellow-dark.min.css": "/css/dist/skins/skin-yellow-dark.min.css?id=c1f33574ecb9d3e69d9b8fe5bd68e101",
"/css/dist/skins/skin-red.min.css": "/css/dist/skins/skin-red.min.css?id=44bf834f2110504a793dadec132a5898",
"/css/dist/skins/skin-red-dark.min.css": "/css/dist/skins/skin-red-dark.min.css?id=8ca888bbc050d9680cbb65021382acba",
"/css/dist/skins/skin-purple.min.css": "/css/dist/skins/skin-purple.min.css?id=6fe68325d5356197672c27bc77cedcb4",
"/css/dist/skins/skin-purple-dark.min.css": "/css/dist/skins/skin-purple-dark.min.css?id=7d92dea45d94be7e1d4e427c728d335d",
"/css/dist/skins/skin-orange.min.css": "/css/dist/skins/skin-orange.min.css?id=6f0563e726c2fe4fab4026daaa5bfdf2",
"/css/dist/skins/skin-orange-dark.min.css": "/css/dist/skins/skin-orange-dark.min.css?id=e6e53eef152bba01a4c666a4d8b01117",
"/css/dist/skins/skin-contrast.min.css": "/css/dist/skins/skin-contrast.min.css?id=da6c7997d9de2f8329142399f0ce50da"
"/js/dist/all.js": "/js/dist/all.js?id=b08a268604ce885176014b4f222d6b21",
"/css/dist/skins/skin-green.min.css": "/css/dist/skins/skin-green.min.css?id=b48f4d8af0e1ca5621c161e93951109f",
"/css/dist/skins/skin-green-dark.min.css": "/css/dist/skins/skin-green-dark.min.css?id=44f9320d0739f419c9246f7f39395b02",
"/css/dist/skins/skin-black.min.css": "/css/dist/skins/skin-black.min.css?id=1f33ca3d860461c1127ec465ab3ebb6b",
"/css/dist/skins/skin-black-dark.min.css": "/css/dist/skins/skin-black-dark.min.css?id=f4d95ad9d0944587549e35b6929b4b04",
"/css/dist/skins/skin-blue.min.css": "/css/dist/skins/skin-blue.min.css?id=392cc93cfc0be0349bab9697669dd091",
"/css/dist/skins/skin-blue-dark.min.css": "/css/dist/skins/skin-blue-dark.min.css?id=4a9e8c5e7b09506fa3e3a3f42849e07f",
"/css/dist/skins/skin-yellow.min.css": "/css/dist/skins/skin-yellow.min.css?id=fc7adb943668ac69fe4b646625a7571f",
"/css/dist/skins/skin-yellow-dark.min.css": "/css/dist/skins/skin-yellow-dark.min.css?id=21fef066e0bb1b02fd83fcb6694fad5f",
"/css/dist/skins/skin-red.min.css": "/css/dist/skins/skin-red.min.css?id=b9a74ec0cd68f83e7480d5ae39919beb",
"/css/dist/skins/skin-red-dark.min.css": "/css/dist/skins/skin-red-dark.min.css?id=7f0eb9e355b36b41c61c3af3b4d41143",
"/css/dist/skins/skin-purple.min.css": "/css/dist/skins/skin-purple.min.css?id=cf6c8c340420724b02d6e787ef9bded5",
"/css/dist/skins/skin-purple-dark.min.css": "/css/dist/skins/skin-purple-dark.min.css?id=9f944e8021781af1ce45d27765d1c0c2",
"/css/dist/skins/skin-orange.min.css": "/css/dist/skins/skin-orange.min.css?id=268041e902b019730c23ee3875838005",
"/css/dist/skins/skin-orange-dark.min.css": "/css/dist/skins/skin-orange-dark.min.css?id=d409d9b1a3b69247df8b98941ba06e33",
"/css/dist/skins/skin-contrast.min.css": "/css/dist/skins/skin-contrast.min.css?id=f0fbbb0ac729ea092578fb05ca615460"
}

View file

@ -15,15 +15,15 @@
<div class="modal-body">
<div class="row">
<div class="col-md-3">
<div class="col-md-12">
<label class="btn btn-default">
{{ trans('button.select_file') }}
<label class="btn btn-default btn-block">
{{ trans('button.select_files') }}
<input type="file" name="file[]" multiple="true" class="js-uploadFile" id="uploadFile" data-maxsize="{{ Helper::file_upload_max_size() }}" accept="image/*,.csv,.zip,.rar,.doc,.docx,.xls,.xlsx,.xml,.lic,.xlsx,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.ms-excel,text/plain,.pdf,application/rtf,application/json" style="display:none" required>
</label>
</div>
<div class="col-md-9">
<div class="col-md-12">
<span id="uploadFile-info"></span>
</div>
<div class="col-md-12">

View file

@ -34,7 +34,8 @@
</div>
<!-- Custom Fieldset -->
@livewire('custom-field-set-default-values-for-model',["model_id" => $item->id])
<!-- If $item->id is null we are cloning the model and we need the $model_id variable -->
@livewire('custom-field-set-default-values-for-model',["model_id" => $item->id ?? $model_id ?? null ])
@include ('partials.forms.edit.notes')
@include ('partials.forms.edit.requestable', ['requestable_text' => trans('admin/models/general.requestable')])

View file

@ -18,6 +18,15 @@
.checkbox label {
padding-right: 40px;
}
/*
Don't make the password field *look* readonly - this is for usability, so admins don't think they can't edit this field.
*/
.form-control[readonly] {
background-color: white;
color: #555555;
cursor:text;
}
</style>
@if ((!function_exists('ldap_connect')) || (!function_exists('ldap_set_option')) || (!function_exists('ldap_bind')))
@ -34,10 +43,12 @@
@endif
{{ Form::open(['method' => 'POST', 'files' => false, 'autocomplete' => 'false', 'class' => 'form-horizontal', 'role' => 'form']) }}
{{ Form::open(['method' => 'POST', 'files' => false, 'autocomplete' => 'off', 'class' => 'form-horizontal', 'role' => 'form']) }}
<!-- CSRF Token -->
{{csrf_field()}}
<input type="hidden" name="username" value="{{ Request::old('username', $user->username) }}">
<!-- this is a hack to prevent Chrome from trying to autocomplete fields -->
<input type="text" name="prevent_autofill" id="prevent_autofill" value="" style="display:none;" />
<input type="password" name="password_fake" id="password_fake" value="" style="display:none;" />
@ -54,7 +65,6 @@
</div>
<div class="box-body">
<div class="col-md-11 col-md-offset-1">
<!-- Enable LDAP -->
@ -230,7 +240,7 @@
{{ Form::label('ldap_uname', trans('admin/settings/general.ldap_uname')) }}
</div>
<div class="col-md-8">
{{ Form::text('ldap_uname', Request::old('ldap_uname', $setting->ldap_uname), ['class' => 'form-control','placeholder' => trans('general.example') .'binduser@example.com', $setting->demoMode]) }}
{{ Form::text('ldap_uname', Request::old('ldap_uname', $setting->ldap_uname), ['class' => 'form-control','autocomplete' => 'off', 'placeholder' => trans('general.example') .'binduser@example.com', $setting->demoMode]) }}
{!! $errors->first('ldap_uname', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
@if (config('app.lock_passwords')===true)
<p class="text-warning"><i class="fas fa-lock" aria-hidden="true"></i> {{ trans('general.feature_disabled') }}</p>
@ -244,7 +254,7 @@
{{ Form::label('ldap_pword', trans('admin/settings/general.ldap_pword')) }}
</div>
<div class="col-md-8">
{{ Form::password('ldap_pword', ['class' => 'form-control','placeholder' => trans('general.example') .' binduserpassword', $setting->demoMode]) }}
{{ Form::password('ldap_pword', ['class' => 'form-control', 'autocomplete' => 'off', 'onfocus' => "this.removeAttribute('readonly');", $setting->demoMode, ' readonly']) }}
{!! $errors->first('ldap_pword', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
@if (config('app.lock_passwords')===true)
<p class="text-warning"><i class="fas fa-lock" aria-hidden="true"></i> {{ trans('general.feature_disabled') }}</p>
@ -538,7 +548,7 @@
<input type="text" name="ldaptest_user" id="ldaptest_user" class="form-control" placeholder="LDAP username">
</div>
<div class="col-md-4">
<input type="password" name="ldaptest_password" id="ldaptest_password" class="form-control" placeholder="LDAP password">
<input type="password" name="ldaptest_password" id="ldaptest_password" class="form-control" placeholder="LDAP password" autocomplete="off" readonly onfocus="this.removeAttribute('readonly');">
</div>
<div class="col-md-3">
<a class="btn btn-default btn-sm" id="ldaptestlogin" style="margin-right: 10px;">{{ trans('admin/settings/general.ldap_test') }}</a>

View file

@ -0,0 +1,68 @@
<?php
namespace Tests\Feature\Api\Users;
use App\Models\User;
use Tests\Support\InteractsWithSettings;
use Tests\TestCase;
use Tests\Support\InteractsWithAuthentication;
class UpdateUserApiTest extends TestCase
{
use InteractsWithSettings;
use InteractsWithAuthentication;
public function testApiUsersCanBeActivatedWithNumber()
{
$admin = User::factory()->superuser()->create();
$user = User::factory()->create(['activated' => 0]);
$this->actingAsForApi($admin)
->patch(route('api.users.update', $user), [
'activated' => 1,
]);
$this->assertEquals(1, $user->refresh()->activated);
}
public function testApiUsersCanBeActivatedWithBooleanTrue()
{
$admin = User::factory()->superuser()->create();
$user = User::factory()->create(['activated' => false]);
$this->actingAsForApi($admin)
->patch(route('api.users.update', $user), [
'activated' => true,
]);
$this->assertEquals(1, $user->refresh()->activated);
}
public function testApiUsersCanBeDeactivatedWithNumber()
{
$admin = User::factory()->superuser()->create();
$user = User::factory()->create(['activated' => true]);
$this->actingAsForApi($admin)
->patch(route('api.users.update', $user), [
'activated' => 0,
]);
$this->assertEquals(0, $user->refresh()->activated);
}
public function testApiUsersCanBeDeactivatedWithBooleanFalse()
{
$admin = User::factory()->superuser()->create();
$user = User::factory()->create(['activated' => true]);
$this->actingAsForApi($admin)
->patch(route('api.users.update', $user), [
'activated' => false,
]);
$this->assertEquals(0, $user->refresh()->activated);
}
}

View file

@ -2,6 +2,7 @@
namespace Tests\Feature\Api\Users;
use App\Models\Company;
use App\Models\User;
use Laravel\Passport\Passport;
use Tests\Support\InteractsWithSettings;
@ -83,4 +84,67 @@ class UsersSearchTest extends TestCase
'Expected deleted user does not appear in results'
);
}
public function testUsersScopedToCompanyWhenMultipleFullCompanySupportEnabled()
{
$this->settings->enableMultipleFullCompanySupport();
$companyA = Company::factory()
->has(User::factory(['first_name' => 'Company A', 'last_name' => 'User']))
->create();
Company::factory()
->has(User::factory(['first_name' => 'Company B', 'last_name' => 'User']))
->create();
$response = $this->actingAsForApi(User::factory()->for($companyA)->viewUsers()->create())
->getJson(route('api.users.index'))
->assertOk();
$results = collect($response->json('rows'));
$this->assertTrue(
$results->pluck('name')->contains(fn($text) => str_contains($text, 'Company A')),
'User index does not contain expected user'
);
$this->assertFalse(
$results->pluck('name')->contains(fn($text) => str_contains($text, 'Company B')),
'User index contains unexpected user from another company'
);
}
public function testUsersScopedToCompanyDuringSearchWhenMultipleFullCompanySupportEnabled()
{
$this->settings->enableMultipleFullCompanySupport();
$companyA = Company::factory()
->has(User::factory(['first_name' => 'Company A', 'last_name' => 'User']))
->create();
Company::factory()
->has(User::factory(['first_name' => 'Company B', 'last_name' => 'User']))
->create();
$response = $this->actingAsForApi(User::factory()->for($companyA)->viewUsers()->create())
->getJson(route('api.users.index', [
'deleted' => 'false',
'company_id' => null,
'search' => 'user',
'order' => 'asc',
'offset' => '0',
'limit' => '20',
]))
->assertOk();
$results = collect($response->json('rows'));
$this->assertTrue(
$results->pluck('name')->contains(fn($text) => str_contains($text, 'Company A')),
'User index does not contain expected user'
);
$this->assertFalse(
$results->pluck('name')->contains(fn($text) => str_contains($text, 'Company B')),
'User index contains unexpected user from another company'
);
}
}

View file

@ -10,10 +10,10 @@ class UpdateUserTest extends TestCase
{
use InteractsWithSettings;
public function testUsersCanBeActivated()
public function testUsersCanBeActivatedWithNumber()
{
$admin = User::factory()->superuser()->create();
$user = User::factory()->create(['activated' => false]);
$user = User::factory()->create(['activated' => 0]);
$this->actingAs($admin)
->put(route('users.update', $user), [
@ -22,10 +22,25 @@ class UpdateUserTest extends TestCase
'activated' => 1,
]);
$this->assertTrue($user->refresh()->activated);
$this->assertEquals(1, $user->refresh()->activated);
}
public function testUsersCanBeDeactivated()
public function testUsersCanBeActivatedWithBooleanTrue()
{
$admin = User::factory()->superuser()->create();
$user = User::factory()->create(['activated' => false]);
$this->actingAs($admin)
->put(route('users.update', $user), [
'first_name' => $user->first_name,
'username' => $user->username,
'activated' => true,
]);
$this->assertEquals(1, $user->refresh()->activated);
}
public function testUsersCanBeDeactivatedWithNumber()
{
$admin = User::factory()->superuser()->create();
$user = User::factory()->create(['activated' => true]);
@ -34,12 +49,25 @@ class UpdateUserTest extends TestCase
->put(route('users.update', $user), [
'first_name' => $user->first_name,
'username' => $user->username,
// checkboxes that are not checked are
// not included in the request payload
// 'activated' => 0,
'activated' => 0,
]);
$this->assertFalse($user->refresh()->activated);
$this->assertEquals(0, $user->refresh()->activated);
}
public function testUsersCanBeDeactivatedWithBooleanFalse()
{
$admin = User::factory()->superuser()->create();
$user = User::factory()->create(['activated' => true]);
$this->actingAs($admin)
->put(route('users.update', $user), [
'first_name' => $user->first_name,
'username' => $user->username,
'activated' => false,
]);
$this->assertEquals(0, $user->refresh()->activated);
}
public function testUsersUpdatingThemselvesDoNotDeactivateTheirAccount()
@ -50,12 +78,8 @@ class UpdateUserTest extends TestCase
->put(route('users.update', $admin), [
'first_name' => $admin->first_name,
'username' => $admin->username,
// checkboxes that are disabled are not
// included in the request payload
// even if they are checked
// 'activated' => 0,
]);
$this->assertTrue($admin->refresh()->activated);
$this->assertEquals(1, $admin->refresh()->activated);
}
}