Merge remote-tracking branch 'origin/develop'
Some checks are pending
CodeQL Security Scan / CodeQL Security Scan (javascript) (push) Waiting to run
Codacy Security Scan / Codacy Security Scan (push) Waiting to run
Docker images (Alpine) / docker (push) Waiting to run
Docker images / docker (push) Waiting to run
Tests in MySQL / PHP ${{ matrix.php-version }} (8.1) (push) Waiting to run
Tests in MySQL / PHP ${{ matrix.php-version }} (8.2) (push) Waiting to run
Tests in MySQL / PHP ${{ matrix.php-version }} (8.3) (push) Waiting to run
Tests in SQLite / PHP ${{ matrix.php-version }} (8.1.1) (push) Waiting to run

This commit is contained in:
snipe 2024-10-10 12:32:19 +01:00
commit b296afe050
27 changed files with 1647 additions and 1060 deletions

View file

@ -7,6 +7,11 @@ use App\Helpers\StorageHelper;
use App\Http\Requests\ImageUploadRequest;
use App\Http\Requests\SettingsSamlRequest;
use App\Http\Requests\SetupUserRequest;
use App\Http\Requests\StoreLdapSettings;
use App\Http\Requests\StoreLocalizationSettings;
use App\Http\Requests\StoreNotificationSettings;
use App\Http\Requests\StoreLabelSettings;
use App\Http\Requests\StoreSecuritySettings;
use App\Models\CustomField;
use App\Models\Group;
use App\Models\Setting;
@ -273,20 +278,6 @@ class SettingsController extends Controller
return view('settings/index', compact('settings'));
}
/**
* Return the admin settings page.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
*
* @since [v1.0]
*/
public function getEdit() : View
{
$setting = Setting::getSettings();
return view('settings/general', compact('setting'));
}
/**
* Return a form to allow a super admin to update settings.
@ -486,7 +477,7 @@ class SettingsController extends Controller
*
* @since [v1.0]
*/
public function postSecurity(Request $request) : RedirectResponse
public function postSecurity(StoreSecuritySettings $request) : RedirectResponse
{
$this->validate($request, [
'pwd_secure_complexity' => 'array',
@ -556,7 +547,7 @@ class SettingsController extends Controller
*
* @since [v1.0]
*/
public function postLocalization(Request $request) : RedirectResponse
public function postLocalization(StoreLocalizationSettings $request) : RedirectResponse
{
if (is_null($setting = Setting::getSettings())) {
return redirect()->to('admin')->with('error', trans('admin/settings/message.update.error'));
@ -599,7 +590,7 @@ class SettingsController extends Controller
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v1.0]
*/
public function postAlerts(Request $request) : RedirectResponse
public function postAlerts(StoreNotificationSettings $request) : RedirectResponse
{
if (is_null($setting = Setting::getSettings())) {
return redirect()->to('admin')->with('error', trans('admin/settings/message.update.error'));
@ -780,7 +771,7 @@ class SettingsController extends Controller
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v4.0]
*/
public function postLabels(Request $request) : RedirectResponse
public function postLabels(StoreLabelSettings $request) : RedirectResponse
{
if (is_null($setting = Setting::getSettings())) {
return redirect()->to('admin')->with('error', trans('admin/settings/message.update.error'));
@ -859,26 +850,7 @@ class SettingsController extends Controller
{
$setting = Setting::getSettings();
$groups = Group::pluck('name', 'id');
/**
* This validator is only temporary (famous last words.) - @snipe
*/
$messages = [
'ldap_username_field.not_in' => '<code>sAMAccountName</code> (mixed case) will likely not work. You should use <code>samaccountname</code> (lowercase) instead. ',
'ldap_auth_filter_query.not_in' => '<code>uid=samaccountname</code> is probably not a valid auth filter. You probably want <code>uid=</code> ',
'ldap_filter.regex' => 'This value should probably not be wrapped in parentheses.',
];
$validator = Validator::make($setting->toArray(), [
'ldap_username_field' => 'not_in:sAMAccountName',
'ldap_auth_filter_query' => 'not_in:uid=samaccountname|required_if:ldap_enabled,1',
'ldap_filter' => 'nullable|regex:"^[^(]"|required_if:ldap_enabled,1',
], $messages);
return view('settings.ldap', compact('setting', 'groups'))->withErrors($validator);
return view('settings.ldap', compact('setting', 'groups'));
}
/**
@ -887,7 +859,7 @@ class SettingsController extends Controller
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v4.0]
*/
public function postLdapSettings(Request $request) : RedirectResponse
public function postLdapSettings(StoreLdapSettings $request) : RedirectResponse
{
if (is_null($setting = Setting::getSettings())) {
return redirect()->to('admin')->with('error', trans('admin/settings/message.update.error'));

View file

@ -0,0 +1,41 @@
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Gate;
class StoreLabelSettings extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool
{
return Gate::allows('superuser');
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
return [
'labels_per_page' => 'numeric',
'labels_width' => 'numeric',
'labels_height' => 'numeric',
'labels_pmargin_left' => 'numeric|nullable',
'labels_pmargin_right' => 'numeric|nullable',
'labels_pmargin_top' => 'numeric|nullable',
'labels_pmargin_bottom' => 'numeric|nullable',
'labels_display_bgutter' => 'numeric|nullable',
'labels_display_sgutter' => 'numeric|nullable',
'labels_fontsize' => 'numeric|min:5',
'labels_pagewidth' => 'numeric|nullable',
'labels_pageheight' => 'numeric|nullable',
'qr_text' => 'max:31|nullable',
];
}
}

View file

@ -0,0 +1,39 @@
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Gate;
class StoreLdapSettings extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool
{
return Gate::allows('superuser');
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
\Log::error('boop');
return [
'ldap_username_field' => 'not_in:sAMAccountName|required_if:ldap_enabled,1',
'ldap_auth_filter_query' => 'not_in:uid=samaccountname|required_if:ldap_enabled,1',
'ldap_filter' => 'nullable|regex:"^[^(]"|required_if:ldap_enabled,1',
'ldap_server' => 'nullable|required_if:ldap_enabled,1|starts_with:ldap://,ldaps://',
'ldap_uname' => 'nullable|required_if:ldap_enabled,1',
'ldap_pword' => 'nullable|required_if:ldap_enabled,1',
'ldap_basedn' => 'nullable|required_if:ldap_enabled,1',
'ldap_fname_field' => 'nullable|required_if:ldap_enabled,1',
'custom_forgot_pass_url' => 'nullable|url',
];
}
}

View file

@ -0,0 +1,30 @@
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Gate;
class StoreLocalizationSettings extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool
{
return Gate::allows('superuser');
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
return [
'default_currency' => 'required',
'locale' => 'required',
];
}
}

View file

@ -0,0 +1,37 @@
<?php
namespace App\Http\Requests;
use App\Models\Accessory;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Gate;
class StoreNotificationSettings extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool
{
return Gate::allows('superuser');
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
return [
'alert_email' => 'email_array|nullable',
'admin_cc_email' => 'email|nullable',
'alert_threshold' => 'numeric|nullable|gt:0',
'alert_interval' => 'numeric|nullable|gt:0',
'audit_warning_days' => 'numeric|nullable|gt:0',
'due_checkin_days' => 'numeric|nullable|gt:0',
'audit_interval' => 'numeric|nullable|gt:0',
];
}
}

View file

@ -0,0 +1,35 @@
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Gate;
class StoreSecuritySettings extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool
{
return Gate::allows('superuser');
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
return [
'pwd_secure_min' => 'numeric|required|min:8',
'custom_forgot_pass_url' => 'url|nullable',
'privacy_policy_link' => 'nullable|url',
'login_remote_user_enabled' => 'numeric|nullable',
'login_common_disabled' => 'numeric|nullable',
'login_remote_user_custom_logout_url' => 'string|nullable',
'login_remote_user_header_name' => 'string|nullable',
];
}
}

View file

@ -51,36 +51,7 @@ class Setting extends Model
*/
protected $rules = [
'brand' => 'required|min:1|numeric',
'qr_text' => 'max:31|nullable',
'alert_email' => 'email_array|nullable',
'admin_cc_email' => 'email|nullable',
'default_currency' => 'required',
'locale' => 'required',
'labels_per_page' => 'numeric',
'labels_width' => 'numeric',
'labels_height' => 'numeric',
'labels_pmargin_left' => 'numeric|nullable',
'labels_pmargin_right' => 'numeric|nullable',
'labels_pmargin_top' => 'numeric|nullable',
'labels_pmargin_bottom' => 'numeric|nullable',
'labels_display_bgutter' => 'numeric|nullable',
'labels_display_sgutter' => 'numeric|nullable',
'labels_fontsize' => 'numeric|min:5',
'labels_pagewidth' => 'numeric|nullable',
'labels_pageheight' => 'numeric|nullable',
'login_remote_user_enabled' => 'numeric|nullable',
'login_common_disabled' => 'numeric|nullable',
'login_remote_user_custom_logout_url' => 'string|nullable',
'login_remote_user_header_name' => 'string|nullable',
'thumbnail_max_h' => 'numeric|max:500|min:25',
'pwd_secure_min' => 'numeric|required|min:8',
'alert_threshold' => 'numeric|nullable',
'alert_interval' => 'numeric|nullable',
'audit_warning_days' => 'numeric|nullable',
'due_checkin_days' => 'numeric|nullable',
'audit_interval' => 'numeric|nullable',
'custom_forgot_pass_url' => 'url|nullable',
'privacy_policy_link' => 'nullable|url',
'google_client_id' => 'nullable|ends_with:apps.googleusercontent.com'
];

View file

@ -31,6 +31,7 @@ class ValidationServiceProvider extends ServiceProvider
Validator::extend('email_array', function ($attribute, $value, $parameters, $validator) {
$value = str_replace(' ', '', $value);
$array = explode(',', $value);
$email_to_validate = [];
foreach ($array as $email) { //loop over values
$email_to_validate['alert_email'][] = $email;
@ -38,7 +39,7 @@ class ValidationServiceProvider extends ServiceProvider
$rules = ['alert_email.*'=>'email'];
$messages = [
'alert_email.*'=>trans('validation.email_array'),
'alert_email.*' => trans('validation.custom.email_array'),
];
$validator = Validator::make($email_to_validate, $rules, $messages);

1297
composer.lock generated

File diff suppressed because it is too large Load diff

View file

@ -1432,10 +1432,10 @@ var require_module_cjs = __commonJS({
});
}
function cleanupElement(el) {
if (el._x_cleanups) {
while (el._x_cleanups.length)
el._x_cleanups.pop()();
}
var _a, _b;
(_a = el._x_effects) == null ? void 0 : _a.forEach(dequeueJob);
while ((_b = el._x_cleanups) == null ? void 0 : _b.length)
el._x_cleanups.pop()();
}
var observer = new MutationObserver(onMutate);
var currentlyObserving = false;
@ -1673,27 +1673,23 @@ var require_module_cjs = __commonJS({
magics[name] = callback;
}
function injectMagics(obj, el) {
let memoizedUtilities = getUtilities(el);
Object.entries(magics).forEach(([name, callback]) => {
let memoizedUtilities = null;
function getUtilities() {
if (memoizedUtilities) {
return memoizedUtilities;
} else {
let [utilities, cleanup] = getElementBoundUtilities(el);
memoizedUtilities = { interceptor, ...utilities };
onElRemoved(el, cleanup);
return memoizedUtilities;
}
}
Object.defineProperty(obj, `$${name}`, {
get() {
return callback(el, getUtilities());
return callback(el, memoizedUtilities);
},
enumerable: false
});
});
return obj;
}
function getUtilities(el) {
let [utilities, cleanup] = getElementBoundUtilities(el);
let utils = { interceptor, ...utilities };
onElRemoved(el, cleanup);
return utils;
}
function tryCatch(el, expression, callback, ...args) {
try {
return callback(...args);
@ -2067,8 +2063,8 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
}
function destroyTree(root, walker = walk) {
walker(root, (el) => {
cleanupAttributes(el);
cleanupElement(el);
cleanupAttributes(el);
});
}
function warnAboutMissingPlugins() {
@ -2648,34 +2644,37 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
}
return rawValue ? Boolean(rawValue) : null;
}
var booleanAttributes = /* @__PURE__ */ new Set([
"allowfullscreen",
"async",
"autofocus",
"autoplay",
"checked",
"controls",
"default",
"defer",
"disabled",
"formnovalidate",
"inert",
"ismap",
"itemscope",
"loop",
"multiple",
"muted",
"nomodule",
"novalidate",
"open",
"playsinline",
"readonly",
"required",
"reversed",
"selected",
"shadowrootclonable",
"shadowrootdelegatesfocus",
"shadowrootserializable"
]);
function isBooleanAttr(attrName) {
const booleanAttributes = [
"disabled",
"checked",
"required",
"readonly",
"open",
"selected",
"autofocus",
"itemscope",
"multiple",
"novalidate",
"allowfullscreen",
"allowpaymentrequest",
"formnovalidate",
"autoplay",
"controls",
"loop",
"muted",
"playsinline",
"default",
"ismap",
"reversed",
"async",
"defer",
"nomodule"
];
return booleanAttributes.includes(attrName);
return booleanAttributes.has(attrName);
}
function attributeShouldntBePreservedIfFalsy(name) {
return !["aria-pressed", "aria-checked", "aria-expanded", "aria-selected"].includes(name);
@ -2776,10 +2775,10 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
return stores[name];
}
stores[name] = value;
initInterceptors(stores[name]);
if (typeof value === "object" && value !== null && value.hasOwnProperty("init") && typeof value.init === "function") {
stores[name].init();
}
initInterceptors(stores[name]);
}
function getStores() {
return stores;
@ -3070,7 +3069,10 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
placeInDom(el._x_teleport, target2, modifiers);
});
};
cleanup(() => clone2.remove());
cleanup(() => mutateDom(() => {
clone2.remove();
destroyTree(clone2);
}));
});
var teleportContainerDuringClone = document.createElement("div");
function getTarget(expression) {
@ -3558,7 +3560,10 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
el._x_lookup = {};
effect3(() => loop(el, iteratorNames, evaluateItems, evaluateKey));
cleanup(() => {
Object.values(el._x_lookup).forEach((el2) => el2.remove());
Object.values(el._x_lookup).forEach((el2) => mutateDom(() => {
destroyTree(el2);
el2.remove();
}));
delete el._x_prevKeys;
delete el._x_lookup;
});
@ -3627,11 +3632,12 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
}
for (let i = 0; i < removes.length; i++) {
let key = removes[i];
if (!!lookup[key]._x_effects) {
lookup[key]._x_effects.forEach(dequeueJob);
}
lookup[key].remove();
lookup[key] = null;
if (!(key in lookup))
continue;
mutateDom(() => {
destroyTree(lookup[key]);
lookup[key].remove();
});
delete lookup[key];
}
for (let i = 0; i < moves.length; i++) {
@ -3752,12 +3758,10 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
});
el._x_currentIfEl = clone2;
el._x_undoIf = () => {
walk(clone2, (node) => {
if (!!node._x_effects) {
node._x_effects.forEach(dequeueJob);
}
mutateDom(() => {
destroyTree(clone2);
clone2.remove();
});
clone2.remove();
delete el._x_currentIfEl;
};
return clone2;
@ -3812,9 +3816,9 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
}
});
// ../alpine/packages/collapse/dist/module.cjs.js
// ../../../../usr/local/lib/node_modules/@alpinejs/collapse/dist/module.cjs.js
var require_module_cjs2 = __commonJS({
"../alpine/packages/collapse/dist/module.cjs.js"(exports, module) {
"../../../../usr/local/lib/node_modules/@alpinejs/collapse/dist/module.cjs.js"(exports, module) {
var __defProp2 = Object.defineProperty;
var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
var __getOwnPropNames2 = Object.getOwnPropertyNames;
@ -3887,7 +3891,7 @@ var require_module_cjs2 = __commonJS({
start: { height: current + "px" },
end: { height: full + "px" }
}, () => el._x_isShown = true, () => {
if (Math.abs(el.getBoundingClientRect().height - full) < 1) {
if (el.getBoundingClientRect().height == full) {
el.style.overflow = null;
}
});
@ -3933,9 +3937,9 @@ var require_module_cjs2 = __commonJS({
}
});
// ../alpine/packages/focus/dist/module.cjs.js
// ../../../../usr/local/lib/node_modules/@alpinejs/focus/dist/module.cjs.js
var require_module_cjs3 = __commonJS({
"../alpine/packages/focus/dist/module.cjs.js"(exports, module) {
"../../../../usr/local/lib/node_modules/@alpinejs/focus/dist/module.cjs.js"(exports, module) {
var __create2 = Object.create;
var __defProp2 = Object.defineProperty;
var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
@ -4935,9 +4939,9 @@ var require_module_cjs3 = __commonJS({
}
});
// ../alpine/packages/persist/dist/module.cjs.js
// ../../../../usr/local/lib/node_modules/@alpinejs/persist/dist/module.cjs.js
var require_module_cjs4 = __commonJS({
"../alpine/packages/persist/dist/module.cjs.js"(exports, module) {
"../../../../usr/local/lib/node_modules/@alpinejs/persist/dist/module.cjs.js"(exports, module) {
var __defProp2 = Object.defineProperty;
var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
var __getOwnPropNames2 = Object.getOwnPropertyNames;
@ -5024,9 +5028,9 @@ var require_module_cjs4 = __commonJS({
}
});
// ../alpine/packages/intersect/dist/module.cjs.js
// ../../../../usr/local/lib/node_modules/@alpinejs/intersect/dist/module.cjs.js
var require_module_cjs5 = __commonJS({
"../alpine/packages/intersect/dist/module.cjs.js"(exports, module) {
"../../../../usr/local/lib/node_modules/@alpinejs/intersect/dist/module.cjs.js"(exports, module) {
var __defProp2 = Object.defineProperty;
var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
var __getOwnPropNames2 = Object.getOwnPropertyNames;
@ -5106,8 +5110,80 @@ var require_module_cjs5 = __commonJS({
}
});
// ../alpine/packages/anchor/dist/module.cjs.js
// node_modules/@alpinejs/resize/dist/module.cjs.js
var require_module_cjs6 = __commonJS({
"node_modules/@alpinejs/resize/dist/module.cjs.js"(exports, module) {
var __defProp2 = Object.defineProperty;
var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
var __getOwnPropNames2 = Object.getOwnPropertyNames;
var __hasOwnProp2 = Object.prototype.hasOwnProperty;
var __export = (target, all2) => {
for (var name in all2)
__defProp2(target, name, { get: all2[name], enumerable: true });
};
var __copyProps2 = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames2(from))
if (!__hasOwnProp2.call(to, key) && key !== except)
__defProp2(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
var module_exports = {};
__export(module_exports, {
default: () => module_default,
resize: () => src_default
});
module.exports = __toCommonJS(module_exports);
function src_default(Alpine19) {
Alpine19.directive("resize", Alpine19.skipDuringClone((el, { value, expression, modifiers }, { evaluateLater, cleanup }) => {
let evaluator = evaluateLater(expression);
let evaluate = (width, height) => {
evaluator(() => {
}, { scope: { "$width": width, "$height": height } });
};
let off = modifiers.includes("document") ? onDocumentResize(evaluate) : onElResize(el, evaluate);
cleanup(() => off());
}));
}
function onElResize(el, callback) {
let observer = new ResizeObserver((entries) => {
let [width, height] = dimensions(entries);
callback(width, height);
});
observer.observe(el);
return () => observer.disconnect();
}
var documentResizeObserver;
var documentResizeObserverCallbacks = /* @__PURE__ */ new Set();
function onDocumentResize(callback) {
documentResizeObserverCallbacks.add(callback);
if (!documentResizeObserver) {
documentResizeObserver = new ResizeObserver((entries) => {
let [width, height] = dimensions(entries);
documentResizeObserverCallbacks.forEach((i) => i(width, height));
});
documentResizeObserver.observe(document.documentElement);
}
return () => {
documentResizeObserverCallbacks.delete(callback);
};
}
function dimensions(entries) {
let width, height;
for (let entry of entries) {
width = entry.borderBoxSize[0].inlineSize;
height = entry.borderBoxSize[0].blockSize;
}
return [width, height];
}
var module_default = src_default;
}
});
// ../alpine/packages/anchor/dist/module.cjs.js
var require_module_cjs7 = __commonJS({
"../alpine/packages/anchor/dist/module.cjs.js"(exports, module) {
var __defProp2 = Object.defineProperty;
var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
@ -6645,7 +6721,7 @@ var require_nprogress = __commonJS({
});
// ../alpine/packages/morph/dist/module.cjs.js
var require_module_cjs7 = __commonJS({
var require_module_cjs8 = __commonJS({
"../alpine/packages/morph/dist/module.cjs.js"(exports, module) {
var __defProp2 = Object.defineProperty;
var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
@ -6744,6 +6820,8 @@ var require_module_cjs7 = __commonJS({
let toAttributes = Array.from(to.attributes);
for (let i = domAttributes.length - 1; i >= 0; i--) {
let name = domAttributes[i].name;
if (name === "style")
continue;
if (!to.hasAttribute(name)) {
from2.removeAttribute(name);
}
@ -6751,6 +6829,8 @@ var require_module_cjs7 = __commonJS({
for (let i = toAttributes.length - 1; i >= 0; i--) {
let name = toAttributes[i].name;
let value = toAttributes[i].value;
if (name === "style")
continue;
if (from2.getAttribute(name) !== value) {
from2.setAttribute(name, value);
}
@ -7006,9 +7086,9 @@ var require_module_cjs7 = __commonJS({
}
});
// ../alpine/packages/mask/dist/module.cjs.js
var require_module_cjs8 = __commonJS({
"../alpine/packages/mask/dist/module.cjs.js"(exports, module) {
// ../../../../usr/local/lib/node_modules/@alpinejs/mask/dist/module.cjs.js
var require_module_cjs9 = __commonJS({
"../../../../usr/local/lib/node_modules/@alpinejs/mask/dist/module.cjs.js"(exports, module) {
var __defProp2 = Object.defineProperty;
var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
var __getOwnPropNames2 = Object.getOwnPropertyNames;
@ -8509,7 +8589,8 @@ var import_collapse = __toESM(require_module_cjs2());
var import_focus = __toESM(require_module_cjs3());
var import_persist2 = __toESM(require_module_cjs4());
var import_intersect = __toESM(require_module_cjs5());
var import_anchor = __toESM(require_module_cjs6());
var import_resize = __toESM(require_module_cjs6());
var import_anchor = __toESM(require_module_cjs7());
// js/plugins/navigate/history.js
var Snapshot = class {
@ -8660,7 +8741,7 @@ function extractDestinationFromLink(linkEl) {
return createUrlObjectFromString(linkEl.getAttribute("href"));
}
function createUrlObjectFromString(urlString) {
return new URL(urlString, document.baseURI);
return urlString !== null && new URL(urlString, document.baseURI);
}
function getUriStringFromUrlObject(urlObject) {
return urlObject.pathname + urlObject.search + urlObject.hash;
@ -8782,8 +8863,10 @@ function restoreScrollPositionOrScrollToTop() {
}
};
queueMicrotask(() => {
scroll(document.body);
document.querySelectorAll(["[x-navigate\\:scroll]", "[wire\\:scroll]"]).forEach(scroll);
queueMicrotask(() => {
scroll(document.body);
document.querySelectorAll(["[x-navigate\\:scroll]", "[wire\\:scroll]"]).forEach(scroll);
});
});
}
@ -9087,12 +9170,16 @@ function navigate_default(Alpine19) {
let shouldPrefetchOnHover = modifiers.includes("hover");
shouldPrefetchOnHover && whenThisLinkIsHoveredFor(el, 60, () => {
let destination = extractDestinationFromLink(el);
if (!destination)
return;
prefetchHtml(destination, (html, finalDestination) => {
storeThePrefetchedHtmlForWhenALinkIsClicked(html, destination, finalDestination);
});
});
whenThisLinkIsPressed(el, (whenItIsReleased) => {
let destination = extractDestinationFromLink(el);
if (!destination)
return;
prefetchHtml(destination, (html, finalDestination) => {
storeThePrefetchedHtmlForWhenALinkIsClicked(html, destination, finalDestination);
});
@ -9441,8 +9528,8 @@ function fromQueryString(search) {
}
// js/lifecycle.js
var import_morph = __toESM(require_module_cjs7());
var import_mask = __toESM(require_module_cjs8());
var import_morph = __toESM(require_module_cjs8());
var import_mask = __toESM(require_module_cjs9());
var import_alpinejs5 = __toESM(require_module_cjs());
function start() {
setTimeout(() => ensureLivewireScriptIsntMisplaced());
@ -9451,6 +9538,7 @@ function start() {
import_alpinejs5.default.plugin(import_morph.default);
import_alpinejs5.default.plugin(history2);
import_alpinejs5.default.plugin(import_intersect.default);
import_alpinejs5.default.plugin(import_resize.default);
import_alpinejs5.default.plugin(import_collapse.default);
import_alpinejs5.default.plugin(import_anchor.default);
import_alpinejs5.default.plugin(import_focus.default);

View file

@ -851,10 +851,9 @@
});
}
function cleanupElement(el) {
if (el._x_cleanups) {
while (el._x_cleanups.length)
el._x_cleanups.pop()();
}
el._x_effects?.forEach(dequeueJob);
while (el._x_cleanups?.length)
el._x_cleanups.pop()();
}
var observer = new MutationObserver(onMutate);
var currentlyObserving = false;
@ -1092,27 +1091,23 @@
magics[name] = callback;
}
function injectMagics(obj, el) {
let memoizedUtilities = getUtilities(el);
Object.entries(magics).forEach(([name, callback]) => {
let memoizedUtilities = null;
function getUtilities() {
if (memoizedUtilities) {
return memoizedUtilities;
} else {
let [utilities, cleanup2] = getElementBoundUtilities(el);
memoizedUtilities = { interceptor, ...utilities };
onElRemoved(el, cleanup2);
return memoizedUtilities;
}
}
Object.defineProperty(obj, `$${name}`, {
get() {
return callback(el, getUtilities());
return callback(el, memoizedUtilities);
},
enumerable: false
});
});
return obj;
}
function getUtilities(el) {
let [utilities, cleanup2] = getElementBoundUtilities(el);
let utils = { interceptor, ...utilities };
onElRemoved(el, cleanup2);
return utils;
}
function tryCatch(el, expression, callback, ...args) {
try {
return callback(...args);
@ -1486,8 +1481,8 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
}
function destroyTree(root, walker = walk) {
walker(root, (el) => {
cleanupAttributes(el);
cleanupElement(el);
cleanupAttributes(el);
});
}
function warnAboutMissingPlugins() {
@ -2067,34 +2062,37 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
}
return rawValue ? Boolean(rawValue) : null;
}
var booleanAttributes = /* @__PURE__ */ new Set([
"allowfullscreen",
"async",
"autofocus",
"autoplay",
"checked",
"controls",
"default",
"defer",
"disabled",
"formnovalidate",
"inert",
"ismap",
"itemscope",
"loop",
"multiple",
"muted",
"nomodule",
"novalidate",
"open",
"playsinline",
"readonly",
"required",
"reversed",
"selected",
"shadowrootclonable",
"shadowrootdelegatesfocus",
"shadowrootserializable"
]);
function isBooleanAttr(attrName) {
const booleanAttributes = [
"disabled",
"checked",
"required",
"readonly",
"open",
"selected",
"autofocus",
"itemscope",
"multiple",
"novalidate",
"allowfullscreen",
"allowpaymentrequest",
"formnovalidate",
"autoplay",
"controls",
"loop",
"muted",
"playsinline",
"default",
"ismap",
"reversed",
"async",
"defer",
"nomodule"
];
return booleanAttributes.includes(attrName);
return booleanAttributes.has(attrName);
}
function attributeShouldntBePreservedIfFalsy(name) {
return !["aria-pressed", "aria-checked", "aria-expanded", "aria-selected"].includes(name);
@ -2195,10 +2193,10 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
return stores[name];
}
stores[name] = value;
initInterceptors(stores[name]);
if (typeof value === "object" && value !== null && value.hasOwnProperty("init") && typeof value.init === "function") {
stores[name].init();
}
initInterceptors(stores[name]);
}
function getStores() {
return stores;
@ -3136,7 +3134,10 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
placeInDom(el._x_teleport, target2, modifiers);
});
};
cleanup2(() => clone2.remove());
cleanup2(() => mutateDom(() => {
clone2.remove();
destroyTree(clone2);
}));
});
var teleportContainerDuringClone = document.createElement("div");
function getTarget(expression) {
@ -3624,7 +3625,10 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
el._x_lookup = {};
effect3(() => loop(el, iteratorNames, evaluateItems, evaluateKey));
cleanup2(() => {
Object.values(el._x_lookup).forEach((el2) => el2.remove());
Object.values(el._x_lookup).forEach((el2) => mutateDom(() => {
destroyTree(el2);
el2.remove();
}));
delete el._x_prevKeys;
delete el._x_lookup;
});
@ -3693,11 +3697,12 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
}
for (let i = 0; i < removes.length; i++) {
let key = removes[i];
if (!!lookup[key]._x_effects) {
lookup[key]._x_effects.forEach(dequeueJob);
}
lookup[key].remove();
lookup[key] = null;
if (!(key in lookup))
continue;
mutateDom(() => {
destroyTree(lookup[key]);
lookup[key].remove();
});
delete lookup[key];
}
for (let i = 0; i < moves.length; i++) {
@ -3818,12 +3823,10 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
});
el._x_currentIfEl = clone2;
el._x_undoIf = () => {
walk(clone2, (node) => {
if (!!node._x_effects) {
node._x_effects.forEach(dequeueJob);
}
mutateDom(() => {
destroyTree(clone2);
clone2.remove();
});
clone2.remove();
delete el._x_currentIfEl;
};
return clone2;
@ -4762,7 +4765,7 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
}
};
// ../alpine/packages/collapse/dist/module.esm.js
// ../../../../usr/local/lib/node_modules/@alpinejs/collapse/dist/module.esm.js
function src_default2(Alpine3) {
Alpine3.directive("collapse", collapse);
collapse.inline = (el, { modifiers }) => {
@ -4812,7 +4815,7 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
start: { height: current + "px" },
end: { height: full + "px" }
}, () => el._x_isShown = true, () => {
if (Math.abs(el.getBoundingClientRect().height - full) < 1) {
if (el.getBoundingClientRect().height == full) {
el.style.overflow = null;
}
});
@ -4856,7 +4859,7 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
}
var module_default2 = src_default2;
// ../alpine/packages/focus/dist/module.esm.js
// ../../../../usr/local/lib/node_modules/@alpinejs/focus/dist/module.esm.js
var candidateSelectors = ["input", "select", "textarea", "a[href]", "button", "[tabindex]:not(slot)", "audio[controls]", "video[controls]", '[contenteditable]:not([contenteditable="false"])', "details>summary:first-of-type", "details"];
var candidateSelector = /* @__PURE__ */ candidateSelectors.join(",");
var NoElement = typeof Element === "undefined";
@ -5805,7 +5808,7 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
}
var module_default3 = src_default3;
// ../alpine/packages/persist/dist/module.esm.js
// ../../../../usr/local/lib/node_modules/@alpinejs/persist/dist/module.esm.js
function src_default4(Alpine3) {
let persist = () => {
let alias;
@ -5867,7 +5870,7 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
}
var module_default4 = src_default4;
// ../alpine/packages/intersect/dist/module.esm.js
// ../../../../usr/local/lib/node_modules/@alpinejs/intersect/dist/module.esm.js
function src_default5(Alpine3) {
Alpine3.directive("intersect", Alpine3.skipDuringClone((el, { value, expression, modifiers }, { evaluateLater: evaluateLater2, cleanup: cleanup2 }) => {
let evaluate3 = evaluateLater2(expression);
@ -5922,6 +5925,51 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
}
var module_default5 = src_default5;
// node_modules/@alpinejs/resize/dist/module.esm.js
function src_default6(Alpine3) {
Alpine3.directive("resize", Alpine3.skipDuringClone((el, { value, expression, modifiers }, { evaluateLater: evaluateLater2, cleanup: cleanup2 }) => {
let evaluator = evaluateLater2(expression);
let evaluate3 = (width, height) => {
evaluator(() => {
}, { scope: { "$width": width, "$height": height } });
};
let off = modifiers.includes("document") ? onDocumentResize(evaluate3) : onElResize(el, evaluate3);
cleanup2(() => off());
}));
}
function onElResize(el, callback) {
let observer2 = new ResizeObserver((entries) => {
let [width, height] = dimensions(entries);
callback(width, height);
});
observer2.observe(el);
return () => observer2.disconnect();
}
var documentResizeObserver;
var documentResizeObserverCallbacks = /* @__PURE__ */ new Set();
function onDocumentResize(callback) {
documentResizeObserverCallbacks.add(callback);
if (!documentResizeObserver) {
documentResizeObserver = new ResizeObserver((entries) => {
let [width, height] = dimensions(entries);
documentResizeObserverCallbacks.forEach((i) => i(width, height));
});
documentResizeObserver.observe(document.documentElement);
}
return () => {
documentResizeObserverCallbacks.delete(callback);
};
}
function dimensions(entries) {
let width, height;
for (let entry of entries) {
width = entry.borderBoxSize[0].inlineSize;
height = entry.borderBoxSize[0].blockSize;
}
return [width, height];
}
var module_default6 = src_default6;
// ../alpine/packages/anchor/dist/module.esm.js
var min = Math.min;
var max = Math.max;
@ -7096,7 +7144,7 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
platform: platformWithCache
});
};
function src_default6(Alpine3) {
function src_default7(Alpine3) {
Alpine3.magic("anchor", (el) => {
if (!el._x_anchor)
throw "Alpine: No x-anchor directive found on element using $anchor...";
@ -7154,7 +7202,7 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
let unstyled = modifiers.includes("no-style");
return { placement, offsetValue, unstyled };
}
var module_default6 = src_default6;
var module_default7 = src_default7;
// js/plugins/navigate/history.js
var Snapshot = class {
@ -7305,7 +7353,7 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
return createUrlObjectFromString(linkEl.getAttribute("href"));
}
function createUrlObjectFromString(urlString) {
return new URL(urlString, document.baseURI);
return urlString !== null && new URL(urlString, document.baseURI);
}
function getUriStringFromUrlObject(urlObject) {
return urlObject.pathname + urlObject.search + urlObject.hash;
@ -7426,8 +7474,10 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
}
};
queueMicrotask(() => {
scroll(document.body);
document.querySelectorAll(["[x-navigate\\:scroll]", "[wire\\:scroll]"]).forEach(scroll);
queueMicrotask(() => {
scroll(document.body);
document.querySelectorAll(["[x-navigate\\:scroll]", "[wire\\:scroll]"]).forEach(scroll);
});
});
}
@ -7730,12 +7780,16 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
let shouldPrefetchOnHover = modifiers.includes("hover");
shouldPrefetchOnHover && whenThisLinkIsHoveredFor(el, 60, () => {
let destination = extractDestinationFromLink(el);
if (!destination)
return;
prefetchHtml(destination, (html, finalDestination) => {
storeThePrefetchedHtmlForWhenALinkIsClicked(html, destination, finalDestination);
});
});
whenThisLinkIsPressed(el, (whenItIsReleased) => {
let destination = extractDestinationFromLink(el);
if (!destination)
return;
prefetchHtml(destination, (html, finalDestination) => {
storeThePrefetchedHtmlForWhenALinkIsClicked(html, destination, finalDestination);
});
@ -8158,6 +8212,8 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
let toAttributes = Array.from(to.attributes);
for (let i = domAttributes.length - 1; i >= 0; i--) {
let name = domAttributes[i].name;
if (name === "style")
continue;
if (!to.hasAttribute(name)) {
from2.removeAttribute(name);
}
@ -8165,6 +8221,8 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
for (let i = toAttributes.length - 1; i >= 0; i--) {
let name = toAttributes[i].name;
let value = toAttributes[i].value;
if (name === "style")
continue;
if (from2.getAttribute(name) !== value) {
from2.setAttribute(name, value);
}
@ -8413,13 +8471,13 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
to.setAttribute("id", fromId);
to.id = fromId;
}
function src_default7(Alpine3) {
function src_default8(Alpine3) {
Alpine3.morph = morph;
}
var module_default7 = src_default7;
var module_default8 = src_default8;
// ../alpine/packages/mask/dist/module.esm.js
function src_default8(Alpine3) {
// ../../../../usr/local/lib/node_modules/@alpinejs/mask/dist/module.esm.js
function src_default9(Alpine3) {
Alpine3.directive("mask", (el, { value, expression }, { effect: effect3, evaluateLater: evaluateLater2, cleanup: cleanup2 }) => {
let templateFn = () => expression;
let lastInputValue = "";
@ -8581,22 +8639,23 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
});
return template;
}
var module_default8 = src_default8;
var module_default9 = src_default9;
// js/lifecycle.js
function start2() {
setTimeout(() => ensureLivewireScriptIsntMisplaced());
dispatch(document, "livewire:init");
dispatch(document, "livewire:initializing");
module_default.plugin(module_default7);
module_default.plugin(module_default8);
module_default.plugin(history2);
module_default.plugin(module_default5);
module_default.plugin(module_default2);
module_default.plugin(module_default6);
module_default.plugin(module_default2);
module_default.plugin(module_default7);
module_default.plugin(module_default3);
module_default.plugin(module_default4);
module_default.plugin(navigate_default);
module_default.plugin(module_default8);
module_default.plugin(module_default9);
module_default.addRootSelector(() => "[wire\\:id]");
module_default.onAttributesAdded((el, attributes) => {
if (!Array.from(attributes).some((attribute) => matchesForLivewireDirective(attribute.name)))

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1,2 +1,2 @@
{"/livewire.js":"87e1046f"}
{"/livewire.js":"923613aa"}

View file

@ -385,5 +385,6 @@ return [
'restore_default_avatar_help' => '',
'due_checkin_days' => 'Due For Checkin Warning',
'due_checkin_days_help' => 'How many days before the expected checkin of an asset should it be listed in the "Due for checkin" page?',
'no_groups' => 'No groups have been created yet. Visit <code>Admin Settings > Permission Groups</code> to add one.',
];

View file

@ -173,6 +173,7 @@ return [
'ulid' => 'The :attribute field must be a valid ULID.',
'uuid' => 'The :attribute field must be a valid UUID.',
/*
|--------------------------------------------------------------------------
| Custom Validation Language Lines
@ -194,7 +195,7 @@ return [
'custom_field_not_found_on_model' => 'This field seems to exist, but is not available on this Asset Model\'s fieldset.',
// date_format validation with slightly less stupid messages. It duplicates a lot, but it gets the job done :(
// We use this because the default error message for date_format is reflects php Y-m-d, which non-PHP
// We use this because the default error message for date_format reflects php Y-m-d, which non-PHP
// people won't know how to format.
'purchase_date.date_format' => 'The :attribute must be a valid date in YYYY-MM-DD format',
'last_audit_date.date_format' => 'The :attribute must be a valid date in YYYY-MM-DD hh:mm:ss format',
@ -206,6 +207,13 @@ return [
'checkboxes' => ':attribute contains invalid options.',
'radio_buttons' => ':attribute is invalid.',
'invalid_value_in_field' => 'Invalid value included in this field',
'ldap_username_field' => [
'not_in' => '<code>sAMAccountName</code> (mixed case) will likely not work. You should use <code>samaccountname</code> (lowercase) instead.'
],
'ldap_auth_filter_query' => ['not_in' => '<code>uid=samaccountname</code> is probably not a valid auth filter. You probably want <code>uid=</code> '],
'ldap_filter' => ['regex' => 'This value should probably not be wrapped in parentheses.'],
],
/*
|--------------------------------------------------------------------------

View file

@ -189,14 +189,14 @@ dir="{{ Helper::determineLanguageDirection() }}">
action="{{ route('findbytag/hardware') }}" method="get">
<div class="col-xs-12 col-md-12">
<div class="col-xs-12 form-group">
<label class="sr-only"
for="tagSearch">{{ trans('general.lookup_by_tag') }}</label>
<input type="text" class="form-control" id="tagSearch" name="assetTag"
placeholder="{{ trans('general.lookup_by_tag') }}">
<label class="sr-only" for="tagSearch">
{{ trans('general.lookup_by_tag') }}
</label>
<input type="text" class="form-control" id="tagSearch" name="assetTag" placeholder="{{ trans('general.lookup_by_tag') }}">
<input type="hidden" name="topsearch" value="true" id="search">
</div>
<div class="col-xs-1">
<button type="submit" class="btn btn-primary pull-right">
<button type="submit" id="topSearchButton" class="btn btn-primary pull-right">
<x-icon type="search" />
<span class="sr-only">{{ trans('general.search') }}</span>
</button>

View file

@ -21,9 +21,10 @@
</style>
{{ Form::open(['method' => 'POST', 'files' => false, 'autocomplete' => 'off', 'class' => 'form-horizontal', 'role' => 'form' ]) }}
<form method="POST" action="{{ route('settings.alerts.save') }}" autocomplete="off" class="form-horizontal" role="form" id="create-form">
<!-- CSRF Token -->
{{csrf_field()}}
{{ csrf_field() }}
<div class="row">
<div class="col-sm-10 col-sm-offset-1 col-md-8 col-md-offset-2">
@ -68,12 +69,10 @@
{{ Form::label('alert_email', trans('admin/settings/general.alert_email')) }}
</div>
<div class="col-md-7">
{{ Form::text('alert_email', old('alert_email', $setting->alert_email), array('class' => 'form-control','placeholder' => 'admin@yourcompany.com')) }}
<input type="text" name="alert_email" value="{{ old('alert_email', $setting->alert_email) }}" class="form-control" placeholder="admin@yourcompany.com" maxlength="191">
{!! $errors->first('alert_email', '<span class="alert-msg" aria-hidden="true">:message</span><br>') !!}
<p class="help-block">{{ trans('admin/settings/general.alert_email_help') }}</p>
</div>
</div>
@ -84,7 +83,7 @@
{{ Form::label('admin_cc_email', trans('admin/settings/general.admin_cc_email')) }}
</div>
<div class="col-md-7">
{{ Form::text('admin_cc_email', old('admin_cc_email', $setting->admin_cc_email), array('class' => 'form-control','placeholder' => 'admin@yourcompany.com')) }}
<input type="text" name="admin_cc_email" value="{{ old('admin_cc_email', $setting->admin_cc_email) }}" class="form-control" placeholder="admin@yourcompany.com" maxlength="191">
{!! $errors->first('admin_cc_email', '<span class="alert-msg" aria-hidden="true">:message</span><br>') !!}
<p class="help-block">{{ trans('admin/settings/general.admin_cc_email_help') }}</p>
@ -122,7 +121,7 @@
{{ Form::label('audit_interval', trans('admin/settings/general.audit_interval')) }}
</div>
<div class="input-group col-md-2">
{{ Form::text('audit_interval', old('audit_interval', $setting->audit_interval), array('class' => 'form-control','placeholder' => '12', 'maxlength'=>'3', 'style'=>'width: 60px;')) }}
{{ Form::text('audit_interval', old('audit_interval', $setting->audit_interval), array('class' => 'form-control','placeholder' => '12', 'maxlength'=>'3')) }}
<span class="input-group-addon">{{ trans('general.months') }}</span>
</div>
<div class="col-md-9 col-md-offset-3">
@ -137,7 +136,7 @@
{{ Form::label('audit_warning_days', trans('admin/settings/general.audit_warning_days')) }}
</div>
<div class="input-group col-md-2">
{{ Form::text('audit_warning_days', old('audit_warning_days', $setting->audit_warning_days), array('class' => 'form-control','placeholder' => '14', 'maxlength'=>'3', 'style'=>'width: 60px;')) }}
{{ Form::text('audit_warning_days', old('audit_warning_days', $setting->audit_warning_days), array('class' => 'form-control','placeholder' => '14', 'maxlength'=>'3')) }}
<span class="input-group-addon">{{ trans('general.days') }}</span>
</div>
<div class="col-md-9 col-md-offset-3">
@ -152,12 +151,8 @@
{{ Form::label('due_checkin_days', trans('admin/settings/general.due_checkin_days')) }}
</div>
<div class="input-group col-md-2">
{{ Form::text('due_checkin_days', old('due_checkin_days', $setting->due_checkin_days), array('class' => 'form-control','placeholder' => '14', 'maxlength'=>'3', 'style'=>'width: 60px;')) }}
{{ Form::text('due_checkin_days', old('due_checkin_days', $setting->due_checkin_days), array('class' => 'form-control','placeholder' => '14', 'maxlength'=>'3')) }}
<span class="input-group-addon">{{ trans('general.days') }}</span>
</div>
<div class="col-md-9 col-md-offset-3">
{!! $errors->first('due_checkin_days', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}

View file

@ -18,7 +18,7 @@
{{ Form::open(['method' => 'POST', 'files' => false, 'autocomplete' => 'off', 'class' => 'form-horizontal', 'role' => 'form' ]) }}
<form method="POST" autocomplete="off" class="form-horizontal" role="form" id="create-form">
<!-- CSRF Token -->
{{csrf_field()}}

View file

@ -2,7 +2,7 @@
{{-- Page title --}}
@section('title')
Update LDAP/AD Settings
{{ trans('admin/settings/general.ldap_ad') }}
@parent
@stop
@ -42,8 +42,7 @@
@endif
{{ Form::open(['method' => 'POST', 'files' => false, 'autocomplete' => 'off', 'class' => 'form-horizontal', 'role' => 'form']) }}
<form method="POST" action="{{ route('settings.ldap.save') }}" autocomplete="off" class="form-horizontal" role="form" id="create-form">
<!-- CSRF Token -->
{{csrf_field()}}
@ -62,7 +61,7 @@
<h2 class="box-title">
<x-icon type="ldap"/>
{{ trans('admin/settings/general.ldap_ad') }}
</h4>
</h2>
</div>
<div class="box-body">
@ -76,11 +75,15 @@
<div class="col-md-8">
<label class="form-control">
{{ Form::checkbox('ldap_enabled', '1', old('ldap_enabled', $setting->ldap_enabled), [((config('app.lock_passwords')===true)) ? 'disabled ': '', 'class' => 'form-control '. $setting->demoMode, $setting->demoMode]) }}
{{ Form::checkbox('ldap_enabled', '1', old('ldap_enabled', $setting->ldap_enabled)) }}
{{ trans('admin/settings/general.ldap_enabled') }}
</label>
@if (config('app.lock_passwords')===true)
<p class="text-warning"><i class="fas fa-lock" aria-hidden="true"></i> {{ trans('general.feature_disabled') }}</p>
<p class="text-warning">
<x-icon type="locked" />
{{ trans('general.feature_disabled') }}
</p>
@endif
</div>
</div>
@ -93,13 +96,21 @@
</div>
<div class="col-md-8">
<label class="form-control">
{{ Form::checkbox('is_ad', '1', old('is_ad', $setting->is_ad), [((config('app.lock_passwords')===true)) ? 'disabled ': '', 'class' => 'minimal '. $setting->demoMode, $setting->demoMode]) }}
{{ Form::checkbox('is_ad', '1', old('is_ad', $setting->is_ad)) }}
{{ trans('admin/settings/general.is_ad') }}
</label>
{!! $errors->first('is_ad', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
@error('is_ad')
<span class="alert-msg">
<x-icon type="x" />
{{ $message }}
</span>
@enderror
@if (config('app.lock_passwords')===true)
<p class="text-warning"><i class="fas fa-lock" aria-hidden="true"></i> {{ trans('general.feature_disabled') }}</p>
<p class="text-warning">
<x-icon type="locked" />
{{ trans('general.feature_disabled') }}
</p>
@endif
</div>
</div>
@ -111,14 +122,23 @@
</div>
<div class="col-md-8">
<label class="form-control">
{{ Form::checkbox('ldap_pw_sync', '1', old('ldap_pw_sync', $setting->ldap_pw_sync), [((config('app.lock_passwords')===true)) ? 'disabled ': '', 'class' => 'minimal '. $setting->demoMode, $setting->demoMode]) }}
{{ Form::checkbox('ldap_pw_sync', '1', old('ldap_pw_sync', $setting->ldap_pw_sync)) }}
{{ trans('general.yes') }}
</label>
<p class="help-block">{{ trans('admin/settings/general.ldap_pw_sync_help') }}</p>
{!! $errors->first('ldap_pw_sync_help', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
@error('ldap_pw_sync')
<span class="alert-msg">
<x-icon type="x" />
{{ $message }}
</span>
@enderror
@if (config('app.lock_passwords')===true)
<p class="text-warning"><i class="fas fa-lock" aria-hidden="true"></i> {{ trans('general.feature_disabled') }}</p>
<p class="text-warning">
<x-icon type="locked" />
{{ trans('general.feature_disabled') }}
</p>
@endif
</div>
@ -130,42 +150,43 @@
{{ Form::label('ad_domain', trans('admin/settings/general.ad_domain')) }}
</div>
<div class="col-md-8">
{{ Form::text('ad_domain', old('ad_domain', $setting->ad_domain), ['class' => 'form-control','placeholder' => trans('general.example') .'example.com', $setting->demoMode]) }}
{{ Form::text('ad_domain', old('ad_domain', $setting->ad_domain), ['class' => 'form-control','placeholder' => trans('general.example') .'example.com']) }}
<p class="help-block">{{ trans('admin/settings/general.ad_domain_help') }}</p>
{!! $errors->first('ad_domain', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
@error('ad_domain')
<span class="alert-msg">
<x-icon type="x" />
{{ $message }}
</span>
@enderror
@if (config('app.lock_passwords')===true)
<p class="text-warning"><i class="fas fa-lock" aria-hidden="true"></i> {{ trans('general.feature_disabled') }}</p>
<p class="text-warning">
<x-icon type="locked" />
{{ trans('general.feature_disabled') }}
</p>
@endif
</div>
</div><!-- AD Domain -->
{{-- NOTICE - this was a feature for AdLdap2-based LDAP syncing, and is already handled in 'classic' LDAP, so we now hide the checkbox (but haven't deleted the field) <!-- AD Append Domain -->
<div class="form-group">
<div class="col-md-3">
{{ Form::label('ad_append_domain', trans('admin/settings/general.ad_append_domain_label')) }}
</div>
<div class="col-md-8">
{{ Form::checkbox('ad_append_domain', '1', old('ad_append_domain', $setting->ad_append_domain),['class' => 'minimal '. $setting->demoMode, $setting->demoMode]) }}
{{ trans('admin/settings/general.ad_append_domain') }}
<p class="help-block">{{ trans('admin/settings/general.ad_append_domain_help') }}</p>
{!! $errors->first('ad_append_domain', '<span class="alert-msg">: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>
@endif
</div>
</div> --}}
<!-- LDAP Client-Side TLS key -->
<div class="form-group {{ $errors->has('ldap_client_tls_key') ? 'error' : '' }}">
<div class="col-md-3">
{{ Form::label('ldap_client_tls_key', trans('admin/settings/general.ldap_client_tls_key')) }}
</div>
<div class="col-md-8">
{{ Form::textarea('ldap_client_tls_key', old('ldap_client_tls_key', $setting->ldap_client_tls_key), ['class' => 'form-control','placeholder' => trans('general.example') .'-----BEGIN RSA PRIVATE KEY-----'."\r\n1234567890\r\n-----END RSA PRIVATE KEY-----
", $setting->demoMode]) }}
{!! $errors->first('ldap_client_tls_key', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
{{ Form::textarea('ldap_client_tls_key', old('ldap_client_tls_key', $setting->ldap_client_tls_key), ['class' => 'form-control','placeholder' => trans('general.example') .'-----BEGIN RSA PRIVATE KEY-----'."\r\n1234567890\r\n-----END RSA PRIVATE KEY-----"]) }}
@error('ldap_client_tls_key')
<span class="alert-msg">
<x-icon type="x" />
{{ $message }}
</span>
@enderror
@if (config('app.lock_passwords')===true)
<p class="text-warning"><i class="fas fa-lock" aria-hidden="true"></i> {{ trans('general.feature_disabled') }}</p>
<p class="text-warning">
<x-icon type="locked" />
{{ trans('general.feature_disabled') }}
</p>
@endif
</div>
</div><!-- LDAP Client-Side TLS key -->
@ -176,11 +197,20 @@
{{ Form::label('ldap_client_tls_cert', trans('admin/settings/general.ldap_client_tls_cert')) }}
</div>
<div class="col-md-8">
{{ Form::textarea('ldap_client_tls_cert', old('ldap_client_tls_cert', $setting->ldap_client_tls_cert), ['class' => 'form-control','placeholder' => trans('general.example') .'-----BEGIN CERTIFICATE-----'."\r\n1234567890\r\n-----END CERTIFICATE-----", $setting->demoMode]) }}
{{ Form::textarea('ldap_client_tls_cert', old('ldap_client_tls_cert', $setting->ldap_client_tls_cert), ['class' => 'form-control','placeholder' => trans('general.example') .'-----BEGIN CERTIFICATE-----'."\r\n1234567890\r\n-----END CERTIFICATE-----"]) }}
<p class="help-block">{{ trans('admin/settings/general.ldap_client_tls_cert_help') }}</p>
{!! $errors->first('ldap_client_tls_cert', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
@error('ldap_client_tls_cert')
<span class="alert-msg">
<x-icon type="x" />
{{ $message }}
</span>
@enderror
@if (config('app.lock_passwords')===true)
<p class="text-warning"><i class="fas fa-lock" aria-hidden="true"></i> {{ trans('general.feature_disabled') }}</p>
<p class="text-warning">
<x-icon type="locked" />
{{ trans('general.feature_disabled') }}
</p>
@endif
</div>
</div><!-- LDAP Client-Side TLS certificate -->
@ -191,11 +221,21 @@
{{ Form::label('ldap_server', trans('admin/settings/general.ldap_server')) }}
</div>
<div class="col-md-8">
{{ Form::text('ldap_server', old('ldap_server', $setting->ldap_server), ['class' => 'form-control','placeholder' => trans('general.example') .'ldap://ldap.example.com', $setting->demoMode]) }}
{{ Form::text('ldap_server', old('ldap_server', $setting->ldap_server), ['class' => 'form-control','placeholder' => trans('general.example') .'ldap://ldap.example.com']) }}
@error('ldap_server')
<span class="alert-msg">
<x-icon type="x" />
{{ $message }}
</span>
@enderror
<p class="help-block">{{ trans('admin/settings/general.ldap_server_help') }}</p>
{!! $errors->first('ldap_server', '<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>
<p class="text-warning">
<x-icon type="locked" />
{{ trans('general.feature_disabled') }}
</p>
@endif
</div>
</div><!-- LDAP Server -->
@ -207,12 +247,21 @@
</div>
<div class="col-md-8">
<label class="form-control">
{{ Form::checkbox('ldap_tls', '1', old('ldap_tls', $setting->ldap_tls),['class' => 'minimal '. $setting->demoMode, $setting->demoMode]) }}
{{ Form::checkbox('ldap_tls', '1', old('ldap_tls', $setting->ldap_tls)) }}
{{ trans('admin/settings/general.ldap_tls_help') }}
</label>
{!! $errors->first('ldap_tls', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
@error('ldap_tls')
<span class="alert-msg">
<x-icon type="x" />
{{ $message }}
</span>
@enderror
@if (config('app.lock_passwords')===true)
<p class="text-warning"><i class="fas fa-lock" aria-hidden="true"></i> {{ trans('general.feature_disabled') }}</p>
<p class="text-warning">
<x-icon type="locked" />
{{ trans('general.feature_disabled') }}
</p>
@endif
</div>
</div>
@ -224,13 +273,24 @@
</div>
<div class="col-md-8">
<label class="form-control">
{{ Form::checkbox('ldap_server_cert_ignore', '1', old('ldap_server_cert_ignore', $setting->ldap_server_cert_ignore),['class' => 'minimal '. $setting->demoMode, $setting->demoMode]) }}
{{ Form::checkbox('ldap_server_cert_ignore', '1', old('ldap_server_cert_ignore', $setting->ldap_server_cert_ignore)) }}
{{ trans('admin/settings/general.ldap_server_cert_ignore') }}
</label>
{!! $errors->first('ldap_server_cert_ignore', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
<p class="help-block">{{ trans('admin/settings/general.ldap_server_cert_help') }}</p>
@error('ldap_server_cert_ignore')
<span class="alert-msg">
<x-icon type="x" />
{{ $message }}
</span>
@enderror
<p class="help-block">
{{ trans('admin/settings/general.ldap_server_cert_help') }}
</p>
@if (config('app.lock_passwords')===true)
<p class="text-warning"><i class="fas fa-lock" aria-hidden="true"></i> {{ trans('general.feature_disabled') }}</p>
<p class="text-warning">
<x-icon type="locked" />
{{ trans('general.feature_disabled') }}
</p>
@endif
</div>
</div>
@ -241,10 +301,19 @@
{{ Form::label('ldap_uname', trans('admin/settings/general.ldap_uname')) }}
</div>
<div class="col-md-8">
{{ Form::text('ldap_uname', 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>') !!}
{{ Form::text('ldap_uname', old('ldap_uname', $setting->ldap_uname), ['class' => 'form-control','autocomplete' => 'off', 'placeholder' => trans('general.example') .'binduser@example.com']) }}
@error('ldap_uname')
<span class="alert-msg">
<x-icon type="x" />
{{ $message }}
</span>
@enderror
@if (config('app.lock_passwords')===true)
<p class="text-warning"><i class="fas fa-lock" aria-hidden="true"></i> {{ trans('general.feature_disabled') }}</p>
<p class="text-warning">
<x-icon type="locked" />
{{ trans('general.feature_disabled') }}
</p>
@endif
</div>
</div>
@ -255,10 +324,19 @@
{{ Form::label('ldap_pword', trans('admin/settings/general.ldap_pword')) }}
</div>
<div class="col-md-8">
{{ 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>') !!}
{{ Form::password('ldap_pword', ['class' => 'form-control', 'autocomplete' => 'off', 'onfocus' => "this.removeAttribute('readonly');", ' readonly']) }}
@error('ldap_pword')
<span class="alert-msg">
<x-icon type="x" />
{{ $message }}
</span>
@enderror
@if (config('app.lock_passwords')===true)
<p class="text-warning"><i class="fas fa-lock" aria-hidden="true"></i> {{ trans('general.feature_disabled') }}</p>
<p class="text-warning">
<x-icon type="locked" />
{{ trans('general.feature_disabled') }}
</p>
@endif
</div>
</div>
@ -269,10 +347,19 @@
{{ Form::label('ldap_basedn', trans('admin/settings/general.ldap_basedn')) }}
</div>
<div class="col-md-8">
{{ Form::text('ldap_basedn', old('ldap_basedn', $setting->ldap_basedn), ['class' => 'form-control', 'placeholder' => trans('general.example') .'cn=users/authorized,dc=example,dc=com', $setting->demoMode]) }}
{!! $errors->first('ldap_basedn', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
{{ Form::text('ldap_basedn', old('ldap_basedn', $setting->ldap_basedn), ['class' => 'form-control', 'placeholder' => trans('general.example') .'cn=users/authorized,dc=example,dc=com']) }}
@error('ldap_basedn')
<span class="alert-msg">
<x-icon type="x" />
{{ $message }}
</span>
@enderror
@if (config('app.lock_passwords')===true)
<p class="text-warning"><i class="fas fa-lock" aria-hidden="true"></i> {{ trans('general.feature_disabled') }}</p>
<p class="text-warning">
<x-icon type="locked" />
{{ trans('general.feature_disabled') }}
</p>
@endif
</div>
</div>
@ -283,10 +370,19 @@
{{ Form::label('ldap_filter', trans('admin/settings/general.ldap_filter')) }}
</div>
<div class="col-md-8">
{{ Form::text('ldap_filter', old('ldap_filter', $setting->ldap_filter), ['class' => 'form-control','placeholder' => trans('general.example') .'&(cn=*)', $setting->demoMode]) }}
{!! $errors->first('ldap_filter', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
<input type="text" name="ldap_filter" id="ldap_filter" value="{{ old('ldap_filter', $setting->ldap_filter) }}" class="form-control" placeholder="{{ trans('general.example') .'&(cn=*)' }}">
@error('ldap_filter')
<span class="alert-msg">
<x-icon type="x" />
{{ $message }}
</span>
@enderror
@if (config('app.lock_passwords')===true)
<p class="text-warning"><i class="fas fa-lock" aria-hidden="true"></i> {{ trans('general.feature_disabled') }}</p>
<p class="text-warning">
<x-icon type="locked" />
{{ trans('general.feature_disabled') }}
</p>
@endif
</div>
</div>
@ -297,10 +393,19 @@
{{ Form::label('ldap_username_field', trans('admin/settings/general.ldap_username_field')) }}
</div>
<div class="col-md-8">
{{ Form::text('ldap_username_field', old('ldap_username_field', $setting->ldap_username_field), ['class' => 'form-control','placeholder' => trans('general.example') .'samaccountname', $setting->demoMode]) }}
{!! $errors->first('ldap_username_field', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
<input type="text" name="ldap_username_field" id="ldap_username_field" value="{{ old('ldap_username_field', $setting->ldap_username_field) }}" class="form-control" placeholder="{{ trans('general.example') .'samaccountname' }}">
@error('ldap_username_field')
<span class="alert-msg">
<x-icon type="x" />
{!! $message !!}
</span>
@enderror
@if (config('app.lock_passwords')===true)
<p class="text-warning"><i class="fas fa-lock" aria-hidden="true"></i> {{ trans('general.feature_disabled') }}</p>
<p class="text-warning">
<x-icon type="locked" />
{{ trans('general.feature_disabled') }}
</p>
@endif
</div>
</div>
@ -311,10 +416,19 @@
{{ Form::label('ldap_lname_field', trans('admin/settings/general.ldap_lname_field')) }}
</div>
<div class="col-md-8">
{{ Form::text('ldap_lname_field', old('ldap_lname_field', $setting->ldap_lname_field), ['class' => 'form-control','placeholder' => trans('general.example') .'sn', $setting->demoMode]) }}
{!! $errors->first('ldap_lname_field', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
<input type="text" name="ldap_lname_field" id="ldap_lname_field" value="{{ old('ldap_lname_field', $setting->ldap_lname_field) }}" class="form-control" placeholder="{{ trans('general.example') .'sn' }}">
@error('ldap_lname_field')
<span class="alert-msg">
<x-icon type="x" />
{{ $message }}
</span>
@enderror
@if (config('app.lock_passwords')===true)
<p class="text-warning"><i class="fas fa-lock" aria-hidden="true"></i> {{ trans('general.feature_disabled') }}</p>
<p class="text-warning">
<x-icon type="locked" />
{{ trans('general.feature_disabled') }}
</p>
@endif
</div>
</div>
@ -325,10 +439,19 @@
{{ Form::label('ldap_fname_field', trans('admin/settings/general.ldap_fname_field')) }}
</div>
<div class="col-md-8">
{{ Form::text('ldap_fname_field', old('ldap_fname_field', $setting->ldap_fname_field), ['class' => 'form-control', 'placeholder' => trans('general.example') .'givenname', $setting->demoMode]) }}
{!! $errors->first('ldap_fname_field', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
<input type="text" name="ldap_fname_field" id="ldap_fname_field" value="{{ old('ldap_fname_field', $setting->ldap_fname_field) }}" class="form-control" placeholder="{{ trans('general.example') .'givenname' }}">
@error('ldap_fname_field')
<span class="alert-msg">
<x-icon type="x" />
{{ $message }}
</span>
@enderror
@if (config('app.lock_passwords')===true)
<p class="text-warning"><i class="fas fa-lock" aria-hidden="true"></i> {{ trans('general.feature_disabled') }}</p>
<p class="text-warning">
<x-icon type="locked" />
{{ trans('general.feature_disabled') }}
</p>
@endif
</div>
</div>
@ -336,13 +459,23 @@
<!-- LDAP Auth Filter Query -->
<div class="form-group {{ $errors->has('ldap_auth_filter_query') ? 'error' : '' }}">
<div class="col-md-3">
{{ Form::label('ldap_auth_filter_query', trans('admin/settings/general.ldap_auth_filter_query')) }}
<label for="ldap_auth_filter_query">{{ trans('admin/settings/general.ldap_auth_filter_query') }}</label>
</div>
<div class="col-md-8">
{{ Form::text('ldap_auth_filter_query', old('ldap_auth_filter_query', $setting->ldap_auth_filter_query), ['class' => 'form-control','placeholder' => trans('general.example') .'uid=', $setting->demoMode]) }}
{!! $errors->first('ldap_auth_filter_query', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
<input type="text" name="ldap_auth_filter_query" id="ldap_auth_filter_query" value="{{ old('ldap_auth_filter_query', $setting->ldap_auth_filter_query) }}" class="form-control" placeholder="{{ trans('general.example') .'uid=' }}">
@error('ldap_auth_filter_query')
<span class="alert-msg">
<x-icon type="x" />
{!! $message !!}
</span>
@enderror
@if (config('app.lock_passwords')===true)
<p class="text-warning"><i class="fas fa-lock" aria-hidden="true"></i> {{ trans('general.feature_disabled') }}</p>
<p class="text-warning">
<x-icon type="locked" />
{{ trans('general.feature_disabled') }}
</p>
@endif
</div>
</div>
@ -364,7 +497,6 @@
@endforeach
</ul>
<span class="help-block">{{ trans('admin/users/general.group_memberships_helpblock') }}</span>
@else
<div class="controls">
@ -383,7 +515,7 @@
</div>
@endif
@else
<p>No groups have been created yet. Visit <code>Admin Settings > Permission Groups</code> to add one.</p>
<p>{!! trans('admin/settings/general.no_groups') !!}</p>
@endif
</div>
@ -395,13 +527,21 @@
{{ Form::label('ldap_active_flag', trans('admin/settings/general.ldap_active_flag')) }}
</div>
<div class="col-md-8">
{{ Form::text('ldap_active_flag', old('ldap_active_flag', $setting->ldap_active_flag), ['class' => 'form-control', $setting->demoMode]) }}
<input type="text" name="ldap_active_flag" id="ldap_active_flag" value="{{ old('ldap_active_flag', $setting->ldap_active_flag) }}" class="form-control">
<p class="help-block">{!! trans('admin/settings/general.ldap_activated_flag_help') !!}</p>
{!! $errors->first('ldap_active_flag', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
@error('ldap_active_flag')
<span class="alert-msg">
<x-icon type="x" />
{{ $message }}
</span>
@enderror
@if (config('app.lock_passwords')===true)
<p class="text-warning"><i class="fas fa-lock" aria-hidden="true"></i> {{ trans('general.feature_disabled') }}</p>
<p class="text-warning">
<x-icon type="locked" />
{{ trans('general.feature_disabled') }}
</p>
@endif
</div>
</div>
@ -412,10 +552,19 @@
{{ Form::label('ldap_emp_num', trans('admin/settings/general.ldap_emp_num')) }}
</div>
<div class="col-md-8">
{{ Form::text('ldap_emp_num', old('ldap_emp_num', $setting->ldap_emp_num), ['class' => 'form-control','placeholder' => trans('general.example') .'employeenumber/employeeid', $setting->demoMode]) }}
{!! $errors->first('ldap_emp_num', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
{{ Form::text('ldap_emp_num', old('ldap_emp_num', $setting->ldap_emp_num), ['class' => 'form-control','placeholder' => trans('general.example') .'employeenumber/employeeid']) }}
@error('ldap_emp_num')
<span class="alert-msg">
<x-icon type="x" />
{{ $message }}
</span>
@enderror
@if (config('app.lock_passwords')===true)
<p class="text-warning"><i class="fas fa-lock" aria-hidden="true"></i> {{ trans('general.feature_disabled') }}</p>
<p class="text-warning">
<x-icon type="locked" />
{{ trans('general.feature_disabled') }}
</p>
@endif
</div>
</div>
@ -425,10 +574,20 @@
{{ Form::label('ldap_dept', trans('admin/settings/general.ldap_dept')) }}
</div>
<div class="col-md-8">
{{ Form::text('ldap_dept', old('ldap_dept', $setting->ldap_dept), ['class' => 'form-control','placeholder' => trans('general.example') .'department', $setting->demoMode]) }}
{!! $errors->first('ldap_dept', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
{{ Form::text('ldap_dept', old('ldap_dept', $setting->ldap_dept), ['class' => 'form-control','placeholder' => trans('general.example') .'department']) }}
@error('ldap_dept')
<span class="alert-msg">
<x-icon type="x" />
{{ $message }}
</span>
@enderror
@if (config('app.lock_passwords')===true)
<p class="text-warning"><i class="fas fa-lock" aria-hidden="true"></i> {{ trans('general.feature_disabled') }}</p>
<p class="text-warning">
<x-icon type="locked" />
{{ trans('general.feature_disabled') }}
</p>
@endif
</div>
</div>
@ -438,10 +597,19 @@
{{ Form::label('ldap_dept', trans('admin/settings/general.ldap_manager')) }}
</div>
<div class="col-md-8">
{{ Form::text('ldap_manager', old('ldap_manager', $setting->ldap_manager), ['class' => 'form-control','placeholder' => trans('general.example') .'manager', $setting->demoMode]) }}
{!! $errors->first('ldap_manager', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
{{ Form::text('ldap_manager', old('ldap_manager', $setting->ldap_manager), ['class' => 'form-control','placeholder' => trans('general.example') .'manager']) }}
@error('ldap_manager')
<span class="alert-msg">
<x-icon type="x" />
{{ $message }}
</span>
@enderror
@if (config('app.lock_passwords')===true)
<p class="text-warning"><i class="fas fa-lock" aria-hidden="true"></i> {{ trans('general.feature_disabled') }}</p>
<p class="text-warning">
<x-icon type="locked" />
{{ trans('general.feature_disabled') }}
</p>
@endif
</div>
</div>
@ -452,10 +620,19 @@
{{ Form::label('ldap_email', trans('admin/settings/general.ldap_email')) }}
</div>
<div class="col-md-8">
{{ Form::text('ldap_email', old('ldap_email', $setting->ldap_email), ['class' => 'form-control','placeholder' => trans('general.example') .'mail', $setting->demoMode]) }}
{!! $errors->first('ldap_email', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
{{ Form::text('ldap_email', old('ldap_email', $setting->ldap_email), ['class' => 'form-control','placeholder' => trans('general.example') .'mail']) }}
@error('ldap_email')
<span class="alert-msg">
<x-icon type="x" />
{{ $message }}
</span>
@enderror
@if (config('app.lock_passwords')===true)
<p class="text-warning"><i class="fas fa-lock" aria-hidden="true"></i> {{ trans('general.feature_disabled') }}</p>
<p class="text-warning">
<x-icon type="locked" />
{{ trans('general.feature_disabled') }}
</p>
@endif
</div>
</div>
@ -466,10 +643,19 @@
{{ Form::label('ldap_phone', trans('admin/settings/general.ldap_phone')) }}
</div>
<div class="col-md-8">
{{ Form::text('ldap_phone', old('ldap_phone', $setting->ldap_phone_field), ['class' => 'form-control','placeholder' => trans('general.example') .'telephonenumber', $setting->demoMode]) }}
{!! $errors->first('ldap_phone', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
{{ Form::text('ldap_phone', old('ldap_phone', $setting->ldap_phone_field), ['class' => 'form-control','placeholder' => trans('general.example') .'telephonenumber']) }}
@error('ldap_phone')
<span class="alert-msg">
<x-icon type="x" />
{{ $message }}
</span>
@enderror
@if (config('app.lock_passwords')===true)
<p class="text-warning"><i class="fas fa-lock" aria-hidden="true"></i> {{ trans('general.feature_disabled') }}</p>
<p class="text-warning">
<x-icon type="locked" />
{{ trans('general.feature_disabled') }}
</p>
@endif
</div>
</div>
@ -480,10 +666,19 @@
{{ Form::label('ldap_jobtitle', trans('admin/settings/general.ldap_jobtitle')) }}
</div>
<div class="col-md-8">
{{ Form::text('ldap_jobtitle', old('ldap_jobtitle', $setting->ldap_jobtitle), ['class' => 'form-control','placeholder' => trans('general.example') .'title', $setting->demoMode]) }}
{!! $errors->first('ldap_jobtitle', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
{{ Form::text('ldap_jobtitle', old('ldap_jobtitle', $setting->ldap_jobtitle), ['class' => 'form-control','placeholder' => trans('general.example') .'title']) }}
@error('ldap_jobtitle')
<span class="alert-msg">
<x-icon type="x" />
{{ $message }}
</span>
@enderror
@if (config('app.lock_passwords')===true)
<p class="text-warning"><i class="fas fa-lock" aria-hidden="true"></i> {{ trans('general.feature_disabled') }}</p>
<p class="text-warning">
<x-icon type="locked" />
{{ trans('general.feature_disabled') }}
</p>
@endif
</div>
</div>
@ -494,10 +689,19 @@
{{ Form::label('ldap_country', trans('admin/settings/general.ldap_country')) }}
</div>
<div class="col-md-8">
{{ Form::text('ldap_country', old('ldap_country', $setting->ldap_country), ['class' => 'form-control','placeholder' => trans('general.example') .'c', $setting->demoMode]) }}
{!! $errors->first('ldap_country', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
{{ Form::text('ldap_country', old('ldap_country', $setting->ldap_country), ['class' => 'form-control','placeholder' => trans('general.example') .'c']) }}
@error('ldap_country')
<span class="alert-msg">
<x-icon type="x" />
{{ $message }}
</span>
@enderror
@if (config('app.lock_passwords')===true)
<p class="text-warning"><i class="fas fa-lock" aria-hidden="true"></i> {{ trans('general.feature_disabled') }}</p>
<p class="text-warning">
<x-icon type="locked" />
{{ trans('general.feature_disabled') }}
</p>
@endif
</div>
</div>
@ -507,11 +711,20 @@
{{ Form::label('ldap_location', trans('admin/settings/general.ldap_location')) }}
</div>
<div class="col-md-8">
{{ Form::text('ldap_location', old('ldap_location', $setting->ldap_location), ['class' => 'form-control','placeholder' => trans('general.example') .'physicaldeliveryofficename', $setting->demoMode]) }}
{{ Form::text('ldap_location', old('ldap_location', $setting->ldap_location), ['class' => 'form-control','placeholder' => trans('general.example') .'physicaldeliveryofficename']) }}
<p class="help-block">{!! trans('admin/settings/general.ldap_location_help') !!}</p>
{!! $errors->first('ldap_location', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
@error('ldap_location')
<span class="alert-msg">
<x-icon type="x" />
{{ $message }}
</span>
@enderror
@if (config('app.lock_passwords')===true)
<p class="text-warning"><i class="fas fa-lock" aria-hidden="true"></i> {{ trans('general.feature_disabled') }}</p>
<p class="text-warning">
<x-icon type="locked" />
{{ trans('general.feature_disabled') }}
</p>
@endif
</div>
</div>
@ -523,7 +736,7 @@
{{ Form::label('test_ldap_sync', 'Test LDAP Sync') }}
</div>
<div class="col-md-8" id="ldaptestrow">
<a {{ $setting->demoMode }} class="btn btn-default btn-sm" id="ldaptest" style="margin-right: 10px;">{{ trans('admin/settings/general.ldap_test_sync') }}</a>
<a class="btn btn-default btn-sm" id="ldaptest" style="margin-right: 10px;">{{ trans('admin/settings/general.ldap_test_sync') }}</a>
</div>
<div class="col-md-8 col-md-offset-3">
<br />
@ -532,7 +745,10 @@
<div class="col-md-8 col-md-offset-3">
<p class="help-block">{{ trans('admin/settings/general.ldap_login_sync_help') }}</p>
@if (config('app.lock_passwords')===true)
<p class="text-warning"><i class="fas fa-lock" aria-hidden="true"></i> {{ trans('general.feature_disabled') }}</p>
<p class="text-warning">
<x-icon type="locked" />
{{ trans('general.feature_disabled') }}
</p>
@endif
</div>
@ -578,11 +794,20 @@
{{ Form::label('custom_forgot_pass_url', trans('admin/settings/general.custom_forgot_pass_url')) }}
</div>
<div class="col-md-8">
{{ Form::text('custom_forgot_pass_url', old('custom_forgot_pass_url', $setting->custom_forgot_pass_url), ['class' => 'form-control','placeholder' => trans('general.example') .'https://my.ldapserver-forgotpass.com', $setting->demoMode]) }}
{{ Form::text('custom_forgot_pass_url', old('custom_forgot_pass_url', $setting->custom_forgot_pass_url), ['class' => 'form-control','placeholder' => trans('general.example') .'https://my.ldapserver-forgotpass.com']) }}
<p class="help-block">{{ trans('admin/settings/general.custom_forgot_pass_url_help') }}</p>
{!! $errors->first('custom_forgot_pass_url', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
@error('custom_forgot_pass_url')
<span class="alert-msg">
<x-icon type="x" />
{{ $message }}
</span>
@enderror
@if (config('app.lock_passwords')===true)
<p class="text-warning"><i class="fas fa-lock" aria-hidden="true"></i> {{ trans('general.feature_disabled') }}</p>
<p class="text-warning">
<x-icon type="locked" />
{{ trans('general.feature_disabled') }}
</p>
@endif
</div>
</div><!-- LDAP Server -->
@ -607,9 +832,10 @@
{{Form::close()}}
@stop
@endsection
@push('js')
<script nonce="{{ csrf_token() }}">
@ -618,11 +844,58 @@
* Check to see if is_ad is checked, if not disable the ad_domain field
*/
$(function() {
if( $('#is_ad').prop('checked') === false) {
// If the app is locked, disable all fields except the top search fields
@if (config('app.lock_passwords') === true)
$("input").prop('disabled', 'disabled');
$("textarea").prop('disabled', 'disabled');
$("button").prop('disabled', 'disabled');
$("#tagSearch").removeAttr("disabled");
$("#search").removeAttr("disabled");
$("#topSearchButton").removeAttr("disabled");
@endif
if ($('#is_ad').prop('checked') === false) {
$('#ad_domain').prop('disabled', 'disabled');
} else {
//$('#ldap_server').prop('disabled', 'disabled');
$("#ad_domain").prop('required',false);
}
// Mark fields as required if LDAP is enabled
if ($('#ldap_enabled').prop('checked') === false) {
$("#ldap_server").prop('required',false);
$("#ldap_auth_filter_query").prop('required',false);
$("#ldap_filter").prop('required',false);
$("#ldap_username_field").prop('required',false);
$("#ldap_uname").prop('required',false);
$("#ldap_pword").prop('required',false);
$("#ldap_basedn").prop('required',false);
$("#ldap_fname_field").prop('required',false);
}
$("#ldap_enabled").change(function() {
if (this.checked) {
$("#ldap_server").prop('required',true);
$("#ldap_auth_filter_query").prop('required',true);
$("#ldap_filter").prop('required',true);
$("#ldap_uname").prop('required',true);
$("#ldap_username_field").prop('required',true);
$("#ldap_pword").prop('required',true);
$("#ldap_basedn").prop('required',true);
} else {
$("#ldap_server").prop('required',false);
$("#ldap_auth_filter_query").prop('required',false);
$("#ldap_filter").prop('required',false);
$("#ldap_username_field").prop('required',false);
$("#ldap_pword").prop('required',false);
$("#ldap_basedn").prop('required',false);
$("#ldap_fname_field").prop('required',false);
}
});
});
$("#is_ad").change(function() {
@ -649,7 +922,7 @@
$("#ldaptest").click(function () {
$("#ldapad_test_results").removeClass('hidden text-success text-danger');
$("#ldapad_test_results").html('');
$("#ldapad_test_results").html('<i class="fas fa-spinner spin"></i> {{ trans('admin/settings/message.ldap.testing') }}');
$("#ldapad_test_results").html('<x-icon type="spinner" /> {{ trans('admin/settings/message.ldap.testing') }}');
$.ajax({
url: '{{ route('api.settings.ldaptest') }}',
type: 'GET',
@ -698,8 +971,8 @@
*/
function buildLdapTestResults(results) {
let html = '<ul style="list-style: none;padding-left: 5px;">'
html += '<li class="text-success"><i class="fas fa-check" aria-hidden="true"></i> ' + results.login.message + ' </li>'
html += '<li class="text-success"><i class="fas fa-check" aria-hidden="true"></i> ' + results.bind.message + ' </li>'
html += '<li class="text-success"><i class="fas fa-check""></i> ' + results.login.message + ' </li>'
html += '<li class="text-success"><i class="fas fa-check""></i> ' + results.bind.message + ' </li>'
html += '</ul>'
html += '<div style="overflow:auto;">'
html += '<div>{{ trans('admin/settings/message.ldap.sync_success') }}</div>'
@ -738,12 +1011,13 @@
return body;
}
$("#ldaptestlogin").click(function(){
$("#ldaptestloginrow").removeClass('text-success');
$("#ldaptestloginrow").removeClass('text-danger');
$("#ldaptestloginstatus").removeClass('text-danger');
$("#ldaptestloginstatus").html('');
$("#ldaptestloginicon").html('<i class="fas fa-spinner spin"></i> {{ trans('admin/settings/message.ldap.testing_authentication') }}');
$("#ldaptestloginicon").html('<x-icon type="spinner" /> {{ trans('admin/settings/message.ldap.testing_authentication') }}');
$.ajax({
url: '{{ route('api.settings.ldaptestlogin') }}',
type: 'POST',
@ -803,9 +1077,6 @@
}
}
});
});
</script>

View file

@ -16,9 +16,10 @@
{{ Form::open(['method' => 'POST', 'files' => false, 'autocomplete' => 'off', 'class' => 'form-horizontal', 'role' => 'form' ]) }}
<form method="POST" autocomplete="off" class="form-horizontal" role="form" id="create-form">
<!-- CSRF Token -->
{{csrf_field()}}
{{ csrf_field() }}
<div class="row">
<div class="col-sm-10 col-sm-offset-1 col-md-8 col-md-offset-2">

View file

@ -2,22 +2,28 @@
namespace Tests\Feature\Settings;
use App\Models\Asset;
use Tests\TestCase;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
use App\Models\User;
use App\Models\Setting;
class AlertsSettingTest extends TestCase
{
public function testPermissionRequiredToViewAlertSettings()
{
$asset = Asset::factory()->create();
$this->actingAs(User::factory()->create())
->get(route('settings.alerts.index'))
->assertForbidden();
}
public function testAdminCCEmailArrayCanBeSaved()
{
$response = $this->actingAs(User::factory()->superuser()->create())
->post(route('settings.alerts.save', ['alert_email' => 'me@example.com,you@example.com']))
->assertStatus(302)
->assertValid('alert_email')
->assertRedirect(route('settings.index'))
->assertSessionHasNoErrors();
$this->followRedirects($response)->assertSee('alert-success');
}
}

View file

@ -2,7 +2,6 @@
namespace Tests\Feature\Settings;
use App\Models\Asset;
use Tests\TestCase;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;

View file

@ -0,0 +1,18 @@
<?php
namespace Tests\Feature\Settings;
use Tests\TestCase;
use App\Models\User;
class LabelSettingTest extends TestCase
{
public function testPermissionRequiredToViewLabelSettings()
{
$this->actingAs(User::factory()->create())
->get(route('settings.labels.index'))
->assertForbidden();
}
}

View file

@ -0,0 +1,62 @@
<?php
namespace Tests\Feature\Settings;
use Tests\TestCase;
use App\Models\User;
class LdapSettingsTest extends TestCase
{
public function testPermissionRequiredToViewLdapSettings()
{
$this->actingAs(User::factory()->create())
->get(route('settings.ldap.index'))
->assertForbidden();
}
public function testLdapSettingsCanBeSaved()
{
$response = $this->actingAs(User::factory()->superuser()->create())
->post(route('settings.ldap.save', [
'ldap_enabled' => 1,
'ldap_username_field' => 'samaccountname',
'ldap_filter' => 'uid=',
'ldap_auth_filter_query' => 'uid=',
'ldap_uname' => 'SomeUserField',
'ldap_pword' => 'MyAwesomePassword',
'ldap_basedn' => 'uid=',
'ldap_fname_field' => 'SomeFirstnameField',
'ldap_server' => 'ldaps://ldap.example.com',
]))
->assertStatus(302)
->assertValid('ldap_enabled')
->assertRedirect(route('settings.ldap.index'))
->assertSessionHasNoErrors();
$this->followRedirects($response)->assertSee('alert-success');
}
public function testLdapSettingsAreValidatedCorrectly()
{
$response = $this->actingAs(User::factory()->superuser()->create())
->from(route('settings.ldap.index'))
->post(route('settings.ldap.save', [
'ldap_enabled' => 1,
'ldap_username_field' => 'sAMAccountName',
'ldap_filter' => '(uid=)',
]))
->assertStatus(302)
->assertRedirect(route('settings.ldap.index'))
->assertSessionHasErrors([
'ldap_username_field',
'ldap_auth_filter_query',
'ldap_uname',
'ldap_pword',
'ldap_basedn',
'ldap_fname_field',
'ldap_server',
]);
$this->followRedirects($response)->assertSee('alert-danger');
}
}

View file

@ -0,0 +1,18 @@
<?php
namespace Tests\Feature\Settings;
use Tests\TestCase;
use App\Models\User;
class SecuritySettingTest extends TestCase
{
public function testPermissionRequiredToViewSecuritySettings()
{
$this->actingAs(User::factory()->create())
->get(route('settings.security.index'))
->assertForbidden();
}
}

View file

@ -96,7 +96,7 @@ class LdapTest extends TestCase
"count" => 1,
0 => [
'sn' => 'Surname',
'firstName' => 'FirstName'
'firstname' => 'FirstName'
]
]
);