Compare commits

..

6 Commits

Author SHA1 Message Date
d4509747df Update npm assets to make dependabot happier
All checks were successful
Create Docker Image / Test Application (x86_64) (push) Successful in 3m27s
Create Docker Image / Build Docker Image (x86_64) (push) Successful in 1m25s
Create Docker Image / Build Docker Image (arm64) (push) Successful in 2m51s
Create Docker Image / Final Docker Image Manifest (push) Successful in 10s
2025-06-19 18:09:39 +10:00
2d732e5d52 Remove our highlighted item from the tree, when we click on the top-menu buttons
All checks were successful
Create Docker Image / Test Application (x86_64) (push) Successful in 28s
Create Docker Image / Build Docker Image (x86_64) (push) Successful in 1m39s
Create Docker Image / Build Docker Image (arm64) (push) Successful in 2m53s
Create Docker Image / Final Docker Image Manifest (push) Successful in 10s
2025-06-19 17:46:13 +10:00
d294c9449d Fix page expired 419 started showing a page expired message, instead of refreshing the session and loading the clicked item on the tree 2025-06-19 17:22:24 +10:00
deefd9be43 Fix for when specifying multiple base DNs with LDAP_BASE_DN, and the user doesnt have access to the first one. 2025-06-19 16:15:22 +10:00
59cf0d337e Add alert for DN logins that dont exist. Might be attempts to use the rootdn which is not supported.
Closes #345
2025-06-19 16:15:22 +10:00
c4b1d9ec51 Pass the template object to the attributes, so we can leverage template rules when rendering attributes 2025-06-19 16:15:22 +10:00
23 changed files with 321 additions and 598 deletions

View File

@ -27,29 +27,38 @@ Take a look at the [Docker Container](https://github.com/leenooks/phpLDAPadmin/w
> >
> Open an issue (details below) with enough information for me to be able to recreate the problem. An `LDIF` will be invaluable if it is not handling data correctly. > Open an issue (details below) with enough information for me to be able to recreate the problem. An `LDIF` will be invaluable if it is not handling data correctly.
## Templates ## Version 2 Progress
Starting with v2.2, PLA reintroduces the template engine. Each point release going forward will improve the template
functionality. Check [releases](releases) for details.
Templates in v2 are in JSON format (in v1 they were XML format). If you want to create your own templates you can use The update to v2 is progressing well - here is a list of work to do and done:
the [example.json](blob/master/templates/example.json) template as a guide. Place your custom templates in a subdirectory
under `templates`, eg: `templates/custom`, and they wont be overwritten by an update.
## Outstanding items - [X] Creating new LDAP entries
Compare to v1.x, there are a couple of outstanding items to address - [X] Delete existing LDAP entries
- [X] Updating existing LDAP Entries
Entry Editing: - [X] Password attributes
- [X] Support different password hash options
- [X] Validate password is correct
- [ ] JpegPhoto Create/Delete - [ ] JpegPhoto Create/Delete
- [ ] Binary attribute upload - [ ] Binary attribute upload
- [ ] If removing an objectClass, remove all attributes that only that objectclass provided - [X] JpegPhoto Display
- [X] ObjectClass Add/Remove
Templates Engine - [X] Add additional required attributes (for ObjectClass Addition)
- [ ] Present SELECT lists when an attribute is marked as `type=select` - [ ] Remove existing required attributes (for ObjectClass Removal)
- [X] Add additional values to Attributes that support multiple values
- [X] Delete extra values for Attributes that support multiple values
- [ ] Delete Attributes
- [ ] Templates to enable entries to conform to a custom standard
- [ ] Autopopulate attribute values
- [X] Login to LDAP server
- [X] Configure login by a specific attribute
- [X] Logout LDAP server
- [X] Export entries as an LDAP
- [X] Import LDIF
- [X] Schema Browser
- [X] Searching
- [ ] Enforcing attribute uniqueness - [ ] Enforcing attribute uniqueness
- [ ] Is there something missing?
Raise a [feature request](issues/new) if there is a capability that you would like to see added to PLA. Support is known for these LDAP servers:
## Support is known for these LDAP servers:
- [X] OpenLDAP - [X] OpenLDAP
- [X] OpenDJ - [X] OpenDJ
- [ ] Microsoft Active Directory - [ ] Microsoft Active Directory

View File

@ -3,16 +3,12 @@
namespace App\Classes; namespace App\Classes;
use Illuminate\Support\Arr; use Illuminate\Support\Arr;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage; use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str; use Illuminate\Support\Str;
class Template class Template
{ {
private const LOGKEY = 'T--'; private string $file;
private(set) string $file;
private array $template; private array $template;
private(set) bool $invalid = FALSE; private(set) bool $invalid = FALSE;
private(set) string $reason = ''; private(set) string $reason = '';
@ -53,136 +49,159 @@ class Template
return array_key_exists($key,$this->template); return array_key_exists($key,$this->template);
} }
/** private function autofill()
* Return the onchange JavaScript for attribute
*
* @param string $attribute
* @return Collection
*/
public function onChange(string $attribute): Collection
{ {
$attr = collect($this->template['attributes']) /*
->filter(fn($item,$key)=>! strcasecmp($key,$attribute)) autoFill:string
->pop(); string is a literal string, and may contain many fields like %attr|start-end/flags|additionalcontrolchar%
to substitute values read from other fields.
|start-end is optional, but must be present if the k flag is used.
/flags is optional.
|additionalcontrolchar is optional.
if (! $attr) flags may be:
return collect(); T: Read display text from selection item (drop-down list), otherwise, read the value of the field
For fields that aren't selection items, /T shouldn't be used, and the field value will always be read.
$result = collect(); k: Tokenize:
If the "k" flag is not given:
foreach (Arr::get($attr,'onchange',[]) as $item) { A |start-end instruction will perform a sub-string operation upon
list($command,$args) = preg_split('/^=([a-zA-Z]+)\((.+)\)$/',$item,-1,PREG_SPLIT_DELIM_CAPTURE|PREG_SPLIT_NO_EMPTY); the value of the attr, passing character positions start-end through.
start can be 0 for first character, or any other integer.
switch ($command) { end can be 0 for last character, or any other integer for a specific position.
case 'autoFill': If the "k" flag is given:
$result->push($this->autofill($args)); The string read will be split into fields, using : as a delimiter
break; "start" indicates which field number to pass through.
} K: The string read will be split into fields, using ' ' as a delimiter "start" indicates which field number to pass through.
} If additionalcontrolchar is given, it will be used as delimiter (e.g. this allows for splitting e-mail addresses
into domain and domain-local part).
return $result; l: Make the result lower case.
} U: Make the result upper case.
A: Remap special characters to their corresponding ASCII value
/**
* autoFill - javascript to have one attribute fill the value of another
*
* args: is a literal string, with two parts, delimited by a semi-colon ;
* + The first part is the attribute that will be populated
* + The second part may contain many fields like %attr|start-end/flags|additionalcontrolchar%
* to substitute values read from other fields.
* + |start-end is optional, but must be present if the k flag is used
* + /flags is optional
* + |additionalcontrolchar is optional, and specific to a flag being used
*
* + flags may be:
* T:(?) Read display text from selection item (drop-down list), otherwise, read the value of the field
* For fields that aren't selection items, /T shouldn't be used, and the field value will always be read
* k:(?) Tokenize:
* If the "k" flag is not given:
* + A |start-end instruction will perform a sub-string operation upon the value of the attr, passing
* character positions start-end through
* + start can be 0 for first character, or any other integer
* + end can be 0 for last character, or any other integer for a specific position
* If the "k" flag is given:
* + The string read will be split into fields, using : as a delimiter
* + start indicates which field number to pass through
*
* If additionalcontrolchar is given, it will be used as delimiter (e.g. this allows for splitting
* e-mail addresses into domain and domain-local part)
* l: Make the result lower case
* U: Make the result upper case
* A:(?) Remap special characters to their corresponding ASCII value
*
* @note Attributes rendered on the page are lowercase, eg: <attribute id="gidnumber"> for gidNumber
* @note JavaScript generated here depends on js/template.js
* (?) = to test
*/ */
private function autofill(string $arg): string
{
if (! preg_match('/;/',$arg)) { if (! preg_match('/;/',$arg)) {
Log::alert(sprintf('%s:Invalid argument given to autofill [%s]',self::LOGKEY,$arg)); system_message(array(
return ''; 'title'=>_('Problem with autoFill() in template'),
'body'=>sprintf('%s (<b>%s</b>)',_('There is only 1 argument, when there should be two'),$attribute->getName(false)),
'type'=>'warn'));
return;
} }
$result = '';
// $attr has our attribute to update, $string is the format to use when updating it
list($attr,$string) = preg_split('(([^,]+);(.*))',$arg,-1,PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); list($attr,$string) = preg_split('(([^,]+);(.*))',$arg,-1,PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
$output = $string; preg_match_all('/%(\w+)(\|[0-9]*-[0-9]*)?(\/[KklTUA]+)?(?:\|(.))?%/U',$string,$matchall);
//$result .= sprintf("\n// %s\n",$arg); //print"<PRE>";print_r($matchall); //0 = highlevel match, 1 = attr, 2 = subst, 3 = mod, 4 = delimiter
$m = []; if (! isset($attribute->js['autoFill']))
// MATCH : 0 = highlevel match, 1 = attr, 2 = subst, 3 = mod, 4 = delimiter $attribute->js['autoFill'] = '';
preg_match_all('/%(\w+)(?:\|([0-9]*-[0-9])+)?(?:\/([klTUA]+))?(?:\|(.)?)?%/U',$string,$m);
foreach ($m[0] as $index => $null) { $formula = $string;
$match_attr = strtolower($m[1][$index]); $formula = preg_replace('/^([^%])/','\'$1',$formula);
$match_subst = $m[2][$index]; $formula = preg_replace('/([^%])$/','$1\'',$formula);
$match_mod = $m[3][$index];
$match_delim = $m[4][$index];
$substrarray = []; # Check that our attributes match our schema attributes.
foreach ($matchall[1] as $index => $checkattr) {
$sattr = $this->getServer()->getSchemaAttribute($checkattr);
$result .= sprintf("var %s;\n",$match_attr); # If the attribute is the same as in the XML file, then dont need to do anything.
if (! $sattr || ! strcasecmp($sattr->getName(),$checkattr))
continue;
if (str_contains($match_mod,'k')) { $formula = preg_replace("/$checkattr/",$sattr->getName(),$formula);
$matchall[1][$index] = $sattr->getName();
}
$elem_id = 0;
foreach ($matchall[0] as $index => $null) {
$match_attr = strtolower($matchall[1][$index]);
$match_subst = $matchall[2][$index];
$match_mod = $matchall[3][$index];
$match_delim = $matchall[4][$index];
$substrarray = array();
if (! isset($varcount[$match_attr]))
$varcount[$match_attr] = 0;
else
$varcount[$match_attr]++;
$js_match_attr = $match_attr;
$match_attr = $js_match_attr.'xx'.$varcount[$match_attr];
$formula = preg_replace('/%'.$js_match_attr.'([|\/%])/i','%'.$match_attr.'$1',$formula,1);
$attribute->js['autoFill'] .= sprintf(" var %s;\n",$match_attr);
$attribute->js['autoFill'] .= sprintf(
" var elem$elem_id = document.getElementById(pre+'%s'+suf);\n".
" if (!elem$elem_id) return;\n", $js_match_attr);
if (strstr($match_mod,'T')) {
$attribute->js['autoFill'] .= sprintf(" %s = elem$elem_id.options[elem$elem_id.selectedIndex].text;\n",
$match_attr);
} else {
$attribute->js['autoFill'] .= sprintf(" %s = elem$elem_id.value;\n",$match_attr);
}
$elem_id++;
if (strstr($match_mod,'k')) {
preg_match_all('/([0-9]+)/',trim($match_subst),$substrarray); preg_match_all('/([0-9]+)/',trim($match_subst),$substrarray);
if (isset($substrarray[1][0])) {
$tok_idx = $substrarray[1][0];
} else {
$tok_idx = '0';
}
$attribute->js['autoFill'] .= sprintf(" %s = %s.split(':')[%s];\n",$match_attr,$match_attr,$tok_idx);
$delimiter = ($match_delim === '') ? ' ' : preg_quote($match_delim); } elseif (strstr($match_mod,'K')) {
$result .= sprintf(" %s = %s.split('%s')[%s];\n",$match_attr,$match_attr,$delimiter,$substrarray[1][0] ?? '0'); preg_match_all('/([0-9]+)/',trim($match_subst),$substrarray);
if (isset($substrarray[1][0])) {
$tok_idx = $substrarray[1][0];
} else {
$tok_idx = '0';
}
if ($match_delim == '') {
$delimiter = ' ';
} else {
$delimiter = preg_quote($match_delim);
}
$attribute->js['autoFill'] .= sprintf(" %s = %s.split('%s')[%s];\n",$match_attr,$match_attr,$delimiter,$tok_idx);
} else { } else {
// Work out the start and end chars needed from this value if we have a range specifier preg_match_all('/([0-9]*)-([0-9]*)/',trim($match_subst),$substrarray);
preg_match_all('/([0-9]*)-([0-9]+)/',$match_subst,$substrarray);
if ((isset($substrarray[1][0]) && $substrarray[1][0]) || (isset($substrarray[2][0]) && $substrarray[2][0])) { if ((isset($substrarray[1][0]) && $substrarray[1][0]) || (isset($substrarray[2][0]) && $substrarray[2][0])) {
$result .= sprintf("%s = get_attribute('%s',%d,%s);\n", $attribute->js['autoFill'] .= sprintf(" %s = %s.substr(%s,%s);\n",
$match_attr,$match_attr, $match_attr,$match_attr,
$substrarray[1][0] ?? '0', $substrarray[1][0] ? $substrarray[1][0] : '0',
$substrarray[2][0] ?: sprintf('%s.length',$match_attr)); $substrarray[2][0] ? $substrarray[2][0] : sprintf('%s.length',$match_attr));
} else {
$result .= sprintf("%s = get_attribute('%s');\n",$match_attr,$match_attr);
} }
} }
if (str_contains($match_mod,'l')) if (strstr($match_mod,'l')) {
$result .= sprintf("%s = %s.toLowerCase();\n",$match_attr,$match_attr); $attribute->js['autoFill'] .= sprintf(" %s = %s.toLowerCase();\n",$match_attr,$match_attr);
}
if (str_contains($match_mod,'U')) if (strstr($match_mod,'U')) {
$result .= sprintf("%s = %s.toUpperCase();\n",$match_attr,$match_attr); $attribute->js['autoFill'] .= sprintf(" %s = %s.toUpperCase();\n",$match_attr,$match_attr);
}
if (str_contains($match_mod,'A')) if (strstr($match_mod,'A')) {
$result .= sprintf("%s = toAscii(%s);\n",$match_attr,$match_attr); $attribute->js['autoFill'] .= sprintf(" %s = toAscii(%s);\n",$match_attr,$match_attr);
// For debugging
//$result .= sprintf("console.log('%s will return:'+%s);\n",$match_attr,$match_attr);
// Reformat out output into JS variables
$output = preg_replace('/'.preg_quote($m[0][$index],'/').'/','\'+'.$match_attr.'+\'',$output);
} }
$result .= sprintf("put_attribute('%s','%s');\n",strtolower($attr),$output); # Matchfor only entry without modifiers.
$result .= "\n"; $formula = preg_replace('/^%('.$match_attr.')%$/U','$1 + \'\'',$formula);
# Matchfor only entry with modifiers.
$formula = preg_replace('/^%('.$match_attr.')(\|[0-9]*-[0-9]*)?(\/[KklTUA]+)?(?:\|(.))?%$/U','$1 + \'\'',$formula);
# Matchfor begining entry.
$formula = preg_replace('/^%('.$match_attr.')(\|[0-9]*-[0-9]*)?(\/[KklTUA]+)?(?:\|(.))?%/U','$1 + \'',$formula);
# Matchfor ending entry.
$formula = preg_replace('/%('.$match_attr.')(\|[0-9]*-[0-9]*)?(\/[KklTUA]+)?(?:\|(.))?%$/U','\' + $1 ',$formula);
# Match for entries not at begin/end.
$formula = preg_replace('/%('.$match_attr.')(\|[0-9]*-[0-9]*)?(\/[KklTUA]+)?(?:\|(.))?%/U','\' + $1 + \'',$formula);
$attribute->js['autoFill'] .= "\n";
}
return $result; $attribute->js['autoFill'] .= sprintf(" fillRec(pre+'%s'+suf, %s); // %s\n",strtolower($attr),$formula,$string);
$attribute->js['autoFill'] .= "\n";
} }
} }

View File

@ -38,7 +38,7 @@ class AjaxController extends Controller
*/ */
public function children(Request $request): Collection public function children(Request $request): Collection
{ {
$dn = Crypt::decryptString($request->query('_key')); $dn = Crypt::decryptString($request->query('key'));
// Sometimes our key has a command, so we'll ignore it // Sometimes our key has a command, so we'll ignore it
if (str_starts_with($dn,'*') && ($x=strpos($dn,'|'))) if (str_starts_with($dn,'*') && ($x=strpos($dn,'|')))

View File

@ -28,8 +28,6 @@ class HomeController extends Controller
{ {
private const LOGKEY = 'CHc'; private const LOGKEY = 'CHc';
private const INTERNAL_POST = ['_key','_rdn','_rdn_value','_step','_template','_token','_userpassword_hash'];
/** /**
* Create a new object in the LDAP server * Create a new object in the LDAP server
* *
@ -39,7 +37,7 @@ class HomeController extends Controller
*/ */
public function entry_add(EntryAddRequest $request): \Illuminate\View\View public function entry_add(EntryAddRequest $request): \Illuminate\View\View
{ {
if (! old('_step',$request->validated('_step'))) if (! old('step',$request->validated('step')))
abort(404); abort(404);
$key = $this->request_key($request,collect(old())); $key = $this->request_key($request,collect(old()));
@ -48,12 +46,18 @@ class HomeController extends Controller
$o = new Entry; $o = new Entry;
$o->setRDNBase($key['dn']); $o->setRDNBase($key['dn']);
foreach (collect(old())->except(self::INTERNAL_POST) as $old => $value) foreach (collect(old())->except(['_token','key','step','rdn','rdn_value','userpassword_hash']) as $old => $value)
$o->{$old} = array_filter($value); $o->{$old} = array_filter($value);
if (old('_template',$request->validated('template'))) { if (count($x=collect(old('objectclass',$request->validated('objectclass')))->dot()->filter())) {
$template = $o->template(old('_template',$request->validated('template'))); $o->objectclass = Arr::undot($x);
// Also add in our required attributes
foreach ($o->getAvailableAttributes()->filter(fn($item)=>$item->is_must) as $ao)
$o->{$ao->name} = [Entry::TAG_NOTAG=>''];
} elseif ($request->validated('template')) {
$template = $o->template($request->validated('template'));
$o->objectclass = [Entry::TAG_NOTAG=>$template->objectclasses->toArray()]; $o->objectclass = [Entry::TAG_NOTAG=>$template->objectclasses->toArray()];
foreach ($o->getAvailableAttributes() foreach ($o->getAvailableAttributes()
@ -62,16 +66,9 @@ class HomeController extends Controller
{ {
$o->{$ao->name} = [Entry::TAG_NOTAG=>'']; $o->{$ao->name} = [Entry::TAG_NOTAG=>''];
} }
} elseif (count($x=collect(old('objectclass',$request->validated('objectclass')))->dot()->filter())) {
$o->objectclass = Arr::undot($x);
// Also add in our required attributes
foreach ($o->getAvailableAttributes()->filter(fn($item)=>$item->is_must) as $ao)
$o->{$ao->name} = [Entry::TAG_NOTAG=>''];
} }
$step = $request->get('_step') ? $request->get('_step')+1 : old('_step'); $step = $request->step ? $request->step+1 : old('step');
return view('frame') return view('frame')
->with('subframe','create') ->with('subframe','create')
@ -107,7 +104,6 @@ class HomeController extends Controller
return $view return $view
->with('o',$o) ->with('o',$o)
->with('langtag',Entry::TAG_NOTAG) ->with('langtag',Entry::TAG_NOTAG)
->with('template',NULL)
->with('updated',FALSE); ->with('updated',FALSE);
} }
@ -115,12 +111,12 @@ class HomeController extends Controller
{ {
$key = $this->request_key($request,collect(old())); $key = $this->request_key($request,collect(old()));
$dn = sprintf('%s=%s,%s',$request->get('_rdn'),$request->get('_rdn_value'),$key['dn']); $dn = sprintf('%s=%s,%s',$request->rdn,$request->rdn_value,$key['dn']);
$o = new Entry; $o = new Entry;
$o->setDn($dn); $o->setDn($dn);
foreach ($request->except(self::INTERNAL_POST) as $key => $value) foreach ($request->except(['_token','key','step','rdn','rdn_value','userpassword_hash']) as $key => $value)
$o->{$key} = array_filter($value); $o->{$key} = array_filter($value);
try { try {
@ -216,7 +212,7 @@ class HomeController extends Controller
*/ */
public function entry_objectclass_add(Request $request): Collection public function entry_objectclass_add(Request $request): Collection
{ {
$dn = $request->get('_key') ? Crypt::decryptString($request->dn) : ''; $dn = $request->key ? Crypt::decryptString($request->dn) : '';
$oc = Factory::create($dn,'objectclass',$request->oc); $oc = Factory::create($dn,'objectclass',$request->oc);
$ocs = $oc $ocs = $oc
@ -271,7 +267,7 @@ class HomeController extends Controller
$o = config('server')->fetch($dn); $o = config('server')->fetch($dn);
foreach ($request->except(['_token','dn','_userpassword_hash','userpassword']) as $key => $value) foreach ($request->except(['_token','dn','userpassword_hash','userpassword']) as $key => $value)
$o->{$key} = array_filter($value,fn($item)=>! is_null($item)); $o->{$key} = array_filter($value,fn($item)=>! is_null($item));
// @todo Need to handle incoming attributes that were modified by MD5Updates Trait (eg: jpegphoto) // @todo Need to handle incoming attributes that were modified by MD5Updates Trait (eg: jpegphoto)
@ -288,7 +284,7 @@ class HomeController extends Controller
} }
if ($value) { if ($value) {
$type = Arr::get($request->get('_userpassword_hash'),$dotkey); $type = Arr::get($request->userpassword_hash,$dotkey);
$passwords[$dotkey] = Password::hash_id($type) $passwords[$dotkey] = Password::hash_id($type)
->encode($value); ->encode($value);
} }
@ -372,7 +368,6 @@ class HomeController extends Controller
* @param Request $request * @param Request $request
* @param Collection|null $old * @param Collection|null $old
* @return \Illuminate\View\View * @return \Illuminate\View\View
* @throws InvalidUsage
*/ */
public function frame(Request $request,?Collection $old=NULL): \Illuminate\View\View public function frame(Request $request,?Collection $old=NULL): \Illuminate\View\View
{ {
@ -395,7 +390,7 @@ class HomeController extends Controller
// @todo Need to handle if DN is null, for example if the user's session expired and the ACLs dont let them retrieve $key['dn'] // @todo Need to handle if DN is null, for example if the user's session expired and the ACLs dont let them retrieve $key['dn']
$o = config('server')->fetch($key['dn']); $o = config('server')->fetch($key['dn']);
foreach (collect(old())->except(array_merge(self::INTERNAL_POST,['dn'])) as $attr => $value) foreach (collect(old())->except(['key','dn','step','_token','userpassword_hash','rdn','rdn_value']) as $attr => $value)
$o->{$attr} = $value; $o->{$attr} = $value;
} }
@ -483,8 +478,8 @@ class HomeController extends Controller
// Setup // Setup
$cmd = NULL; $cmd = NULL;
$dn = NULL; $dn = NULL;
$key = $request->get('_key',old('_key')) $key = $request->get('key',old('key'))
? Crypt::decryptString($request->get('_key',old('_key'))) ? Crypt::decryptString($request->get('key',old('key')))
: NULL; : NULL;
// Determine if our key has a command // Determine if our key has a command
@ -496,9 +491,9 @@ class HomeController extends Controller
$dn = ($m[2] !== '_NOP') ? $m[2] : NULL; $dn = ($m[2] !== '_NOP') ? $m[2] : NULL;
} }
} elseif (old('dn',$request->get('_key'))) { } elseif (old('dn',$request->get('key'))) {
$cmd = 'dn'; $cmd = 'dn';
$dn = Crypt::decryptString(old('dn',$request->get('_key'))); $dn = Crypt::decryptString(old('dn',$request->get('key')));
} }
return ['cmd'=>$cmd,'dn'=>$dn]; return ['cmd'=>$cmd,'dn'=>$dn];
@ -515,12 +510,12 @@ class HomeController extends Controller
public function schema_frame(Request $request): \Illuminate\View\View public function schema_frame(Request $request): \Illuminate\View\View
{ {
// If an invalid key, we'll 404 // If an invalid key, we'll 404
if ($request->type && $request->get('_key') && (! config('server')->schema($request->type)->has($request->get('_key')))) if ($request->type && $request->key && (! config('server')->schema($request->type)->has($request->key)))
abort(404); abort(404);
return view('frames.schema') return view('frames.schema')
->with('type',$request->type) ->with('type',$request->type)
->with('key',$request->get('_key')); ->with('key',$request->key);
} }
/** /**

View File

@ -17,8 +17,8 @@ class EntryAddRequest extends FormRequest
public function messages(): array public function messages(): array
{ {
return [ return [
'_rdn' => __('RDN is required.'), 'rdn' => __('RDN is required.'),
'_rdn_value' => __('RDN value is required.'), 'rdn_value' => __('RDN value is required.'),
]; ];
} }
@ -51,7 +51,7 @@ class EntryAddRequest extends FormRequest
->filter() ->filter()
->flatMap(fn($item)=>$item) ->flatMap(fn($item)=>$item)
->merge([ ->merge([
'_key' => [ 'key' => [
'required', 'required',
new DNExists, new DNExists,
function (string $attribute,mixed $value,\Closure $fail) { function (string $attribute,mixed $value,\Closure $fail) {
@ -66,9 +66,9 @@ class EntryAddRequest extends FormRequest
} }
}, },
], ],
'_rdn' => 'required_if:_step,2|string|min:1', 'rdn' => 'required_if:step,2|string|min:1',
'_rdn_value' => 'required_if:_step,2|string|min:1', 'rdn_value' => 'required_if:step,2|string|min:1',
'_step' => 'int|min:1|max:2', 'step' => 'int|min:1|max:2',
'objectclass'=>[ 'objectclass'=>[
'required', 'required',
'array', 'array',
@ -81,7 +81,7 @@ class EntryAddRequest extends FormRequest
// If this is step 1 and there is no objectclass, and no template, then fail // If this is step 1 and there is no objectclass, and no template, then fail
if ((! $oc->count()) if ((! $oc->count())
&& (request()->post('_step') == 1) && (request()->post('step') == 1)
&& (! request()->post('template'))) && (! request()->post('template')))
{ {
$fail(__('Select an objectclass or a template')); $fail(__('Select an objectclass or a template'));
@ -101,7 +101,7 @@ class EntryAddRequest extends FormRequest
// If this is step 1 and there is no objectclass, and no template, then fail // If this is step 1 and there is no objectclass, and no template, then fail
if ((! collect($value)->filter()->count()) if ((! collect($value)->filter()->count())
&& (request()->post('_step') == 1) && (request()->post('step') == 1)
&& (! $oc->count())) && (! $oc->count()))
{ {
$fail(__('Select an objectclass or a template')); $fail(__('Select an objectclass or a template'));

View File

@ -53,10 +53,7 @@ class Entry extends Model
$template_dir = Storage::disk(config('pla.template.dir')); $template_dir = Storage::disk(config('pla.template.dir'));
$templates = collect(); $templates = collect();
foreach (array_filter($template_dir->files('.',TRUE),fn($item)=>Str::endsWith($item,'.json')) as $file) { foreach (array_filter($template_dir->files(),fn($item)=>Str::endsWith($item,'.json')) as $file) {
if (config('pla.template.exclude_system',FALSE) && Str::doesntContain($file,'/'))
continue;
$to = new Template($file); $to = new Template($file);
if ($to->invalid) { if ($to->invalid) {

165
composer.lock generated
View File

@ -8,16 +8,16 @@
"packages": [ "packages": [
{ {
"name": "brick/math", "name": "brick/math",
"version": "0.13.1", "version": "0.12.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/brick/math.git", "url": "https://github.com/brick/math.git",
"reference": "fc7ed316430118cc7836bf45faff18d5dfc8de04" "reference": "866551da34e9a618e64a819ee1e01c20d8a588ba"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/brick/math/zipball/fc7ed316430118cc7836bf45faff18d5dfc8de04", "url": "https://api.github.com/repos/brick/math/zipball/866551da34e9a618e64a819ee1e01c20d8a588ba",
"reference": "fc7ed316430118cc7836bf45faff18d5dfc8de04", "reference": "866551da34e9a618e64a819ee1e01c20d8a588ba",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -56,7 +56,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/brick/math/issues", "issues": "https://github.com/brick/math/issues",
"source": "https://github.com/brick/math/tree/0.13.1" "source": "https://github.com/brick/math/tree/0.12.3"
}, },
"funding": [ "funding": [
{ {
@ -64,7 +64,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2025-03-29T13:50:30+00:00" "time": "2025-02-28T13:11:00+00:00"
}, },
{ {
"name": "carbonphp/carbon-doctrine-types", "name": "carbonphp/carbon-doctrine-types",
@ -288,16 +288,16 @@
}, },
{ {
"name": "directorytree/ldaprecord-laravel", "name": "directorytree/ldaprecord-laravel",
"version": "v3.4.2", "version": "v3.4.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/DirectoryTree/LdapRecord-Laravel.git", "url": "https://github.com/DirectoryTree/LdapRecord-Laravel.git",
"reference": "28c5a7aa42aa3fa631f9c0f0c8236fd19bc7b00c" "reference": "15f56e01319852d41023633d3688ac4aa139aa6e"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/DirectoryTree/LdapRecord-Laravel/zipball/28c5a7aa42aa3fa631f9c0f0c8236fd19bc7b00c", "url": "https://api.github.com/repos/DirectoryTree/LdapRecord-Laravel/zipball/15f56e01319852d41023633d3688ac4aa139aa6e",
"reference": "28c5a7aa42aa3fa631f9c0f0c8236fd19bc7b00c", "reference": "15f56e01319852d41023633d3688ac4aa139aa6e",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -343,7 +343,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/DirectoryTree/LdapRecord-Laravel/issues", "issues": "https://github.com/DirectoryTree/LdapRecord-Laravel/issues",
"source": "https://github.com/DirectoryTree/LdapRecord-Laravel/tree/v3.4.2" "source": "https://github.com/DirectoryTree/LdapRecord-Laravel/tree/v3.4.1"
}, },
"funding": [ "funding": [
{ {
@ -351,7 +351,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2025-06-13T15:46:25+00:00" "time": "2025-03-21T19:16:44+00:00"
}, },
{ {
"name": "doctrine/inflector", "name": "doctrine/inflector",
@ -1199,20 +1199,20 @@
}, },
{ {
"name": "laravel/framework", "name": "laravel/framework",
"version": "v12.19.3", "version": "v12.16.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/laravel/framework.git", "url": "https://github.com/laravel/framework.git",
"reference": "4e6ec689ef704bb4bd282f29d9dd658dfb4fb262" "reference": "293bb1c70224faebfd3d4328e201c37115da055f"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/laravel/framework/zipball/4e6ec689ef704bb4bd282f29d9dd658dfb4fb262", "url": "https://api.github.com/repos/laravel/framework/zipball/293bb1c70224faebfd3d4328e201c37115da055f",
"reference": "4e6ec689ef704bb4bd282f29d9dd658dfb4fb262", "reference": "293bb1c70224faebfd3d4328e201c37115da055f",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"brick/math": "^0.11|^0.12|^0.13", "brick/math": "^0.11|^0.12",
"composer-runtime-api": "^2.2", "composer-runtime-api": "^2.2",
"doctrine/inflector": "^2.0.5", "doctrine/inflector": "^2.0.5",
"dragonmantank/cron-expression": "^3.4", "dragonmantank/cron-expression": "^3.4",
@ -1410,7 +1410,7 @@
"issues": "https://github.com/laravel/framework/issues", "issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework" "source": "https://github.com/laravel/framework"
}, },
"time": "2025-06-18T12:56:23+00:00" "time": "2025-05-27T15:49:44+00:00"
}, },
{ {
"name": "laravel/prompts", "name": "laravel/prompts",
@ -2315,16 +2315,16 @@
}, },
{ {
"name": "nesbot/carbon", "name": "nesbot/carbon",
"version": "3.10.0", "version": "3.9.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/CarbonPHP/carbon.git", "url": "https://github.com/CarbonPHP/carbon.git",
"reference": "c1397390dd0a7e0f11660f0ae20f753d88c1f3d9" "reference": "ced71f79398ece168e24f7f7710462f462310d4d"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/c1397390dd0a7e0f11660f0ae20f753d88c1f3d9", "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/ced71f79398ece168e24f7f7710462f462310d4d",
"reference": "c1397390dd0a7e0f11660f0ae20f753d88c1f3d9", "reference": "ced71f79398ece168e24f7f7710462f462310d4d",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -2332,7 +2332,7 @@
"ext-json": "*", "ext-json": "*",
"php": "^8.1", "php": "^8.1",
"psr/clock": "^1.0", "psr/clock": "^1.0",
"symfony/clock": "^6.3.12 || ^7.0", "symfony/clock": "^6.3 || ^7.0",
"symfony/polyfill-mbstring": "^1.0", "symfony/polyfill-mbstring": "^1.0",
"symfony/translation": "^4.4.18 || ^5.2.1|| ^6.0 || ^7.0" "symfony/translation": "^4.4.18 || ^5.2.1|| ^6.0 || ^7.0"
}, },
@ -2342,13 +2342,14 @@
"require-dev": { "require-dev": {
"doctrine/dbal": "^3.6.3 || ^4.0", "doctrine/dbal": "^3.6.3 || ^4.0",
"doctrine/orm": "^2.15.2 || ^3.0", "doctrine/orm": "^2.15.2 || ^3.0",
"friendsofphp/php-cs-fixer": "^3.75.0", "friendsofphp/php-cs-fixer": "^3.57.2",
"kylekatarnls/multi-tester": "^2.5.3", "kylekatarnls/multi-tester": "^2.5.3",
"ondrejmirtes/better-reflection": "^6.25.0.4",
"phpmd/phpmd": "^2.15.0", "phpmd/phpmd": "^2.15.0",
"phpstan/extension-installer": "^1.4.3", "phpstan/extension-installer": "^1.3.1",
"phpstan/phpstan": "^2.1.17", "phpstan/phpstan": "^1.11.2",
"phpunit/phpunit": "^10.5.46", "phpunit/phpunit": "^10.5.20",
"squizlabs/php_codesniffer": "^3.13.0" "squizlabs/php_codesniffer": "^3.9.0"
}, },
"bin": [ "bin": [
"bin/carbon" "bin/carbon"
@ -2416,7 +2417,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2025-06-12T10:24:28+00:00" "time": "2025-05-01T19:51:51+00:00"
}, },
{ {
"name": "nette/schema", "name": "nette/schema",
@ -2482,16 +2483,16 @@
}, },
{ {
"name": "nette/utils", "name": "nette/utils",
"version": "v4.0.7", "version": "v4.0.6",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/nette/utils.git", "url": "https://github.com/nette/utils.git",
"reference": "e67c4061eb40b9c113b218214e42cb5a0dda28f2" "reference": "ce708655043c7050eb050df361c5e313cf708309"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/nette/utils/zipball/e67c4061eb40b9c113b218214e42cb5a0dda28f2", "url": "https://api.github.com/repos/nette/utils/zipball/ce708655043c7050eb050df361c5e313cf708309",
"reference": "e67c4061eb40b9c113b218214e42cb5a0dda28f2", "reference": "ce708655043c7050eb050df361c5e313cf708309",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -2562,9 +2563,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/nette/utils/issues", "issues": "https://github.com/nette/utils/issues",
"source": "https://github.com/nette/utils/tree/v4.0.7" "source": "https://github.com/nette/utils/tree/v4.0.6"
}, },
"time": "2025-06-03T04:55:08+00:00" "time": "2025-03-30T21:06:30+00:00"
}, },
{ {
"name": "nunomaduro/termwind", "name": "nunomaduro/termwind",
@ -3262,16 +3263,16 @@
}, },
{ {
"name": "ramsey/uuid", "name": "ramsey/uuid",
"version": "4.8.1", "version": "4.8.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/ramsey/uuid.git", "url": "https://github.com/ramsey/uuid.git",
"reference": "fdf4dd4e2ff1813111bd0ad58d7a1ddbb5b56c28" "reference": "6700833915c00f890615fbcb653faed513836836"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/ramsey/uuid/zipball/fdf4dd4e2ff1813111bd0ad58d7a1ddbb5b56c28", "url": "https://api.github.com/repos/ramsey/uuid/zipball/6700833915c00f890615fbcb653faed513836836",
"reference": "fdf4dd4e2ff1813111bd0ad58d7a1ddbb5b56c28", "reference": "6700833915c00f890615fbcb653faed513836836",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -3335,9 +3336,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/ramsey/uuid/issues", "issues": "https://github.com/ramsey/uuid/issues",
"source": "https://github.com/ramsey/uuid/tree/4.8.1" "source": "https://github.com/ramsey/uuid/tree/4.8.0"
}, },
"time": "2025-06-01T06:28:46+00:00" "time": "2025-06-01T02:32:15+00:00"
}, },
{ {
"name": "symfony/clock", "name": "symfony/clock",
@ -6075,16 +6076,16 @@
}, },
{ {
"name": "filp/whoops", "name": "filp/whoops",
"version": "2.18.3", "version": "2.18.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/filp/whoops.git", "url": "https://github.com/filp/whoops.git",
"reference": "59a123a3d459c5a23055802237cb317f609867e5" "reference": "a7de6c3c6c3c022f5cfc337f8ede6a14460cf77e"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/filp/whoops/zipball/59a123a3d459c5a23055802237cb317f609867e5", "url": "https://api.github.com/repos/filp/whoops/zipball/a7de6c3c6c3c022f5cfc337f8ede6a14460cf77e",
"reference": "59a123a3d459c5a23055802237cb317f609867e5", "reference": "a7de6c3c6c3c022f5cfc337f8ede6a14460cf77e",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -6134,7 +6135,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/filp/whoops/issues", "issues": "https://github.com/filp/whoops/issues",
"source": "https://github.com/filp/whoops/tree/2.18.3" "source": "https://github.com/filp/whoops/tree/2.18.0"
}, },
"funding": [ "funding": [
{ {
@ -6142,7 +6143,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2025-06-16T00:02:10+00:00" "time": "2025-03-15T12:00:00+00:00"
}, },
{ {
"name": "hamcrest/hamcrest-php", "name": "hamcrest/hamcrest-php",
@ -6398,23 +6399,23 @@
}, },
{ {
"name": "nunomaduro/collision", "name": "nunomaduro/collision",
"version": "v8.8.1", "version": "v8.8.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/nunomaduro/collision.git", "url": "https://github.com/nunomaduro/collision.git",
"reference": "44ccb82e3e21efb5446748d2a3c81a030ac22bd5" "reference": "4cf9f3b47afff38b139fb79ce54fc71799022ce8"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/nunomaduro/collision/zipball/44ccb82e3e21efb5446748d2a3c81a030ac22bd5", "url": "https://api.github.com/repos/nunomaduro/collision/zipball/4cf9f3b47afff38b139fb79ce54fc71799022ce8",
"reference": "44ccb82e3e21efb5446748d2a3c81a030ac22bd5", "reference": "4cf9f3b47afff38b139fb79ce54fc71799022ce8",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"filp/whoops": "^2.18.1", "filp/whoops": "^2.18.0",
"nunomaduro/termwind": "^2.3.1", "nunomaduro/termwind": "^2.3.0",
"php": "^8.2.0", "php": "^8.2.0",
"symfony/console": "^7.3.0" "symfony/console": "^7.2.5"
}, },
"conflict": { "conflict": {
"laravel/framework": "<11.44.2 || >=13.0.0", "laravel/framework": "<11.44.2 || >=13.0.0",
@ -6422,15 +6423,15 @@
}, },
"require-dev": { "require-dev": {
"brianium/paratest": "^7.8.3", "brianium/paratest": "^7.8.3",
"larastan/larastan": "^3.4.2", "larastan/larastan": "^3.2",
"laravel/framework": "^11.44.2 || ^12.18", "laravel/framework": "^11.44.2 || ^12.6",
"laravel/pint": "^1.22.1", "laravel/pint": "^1.21.2",
"laravel/sail": "^1.43.1", "laravel/sail": "^1.41.0",
"laravel/sanctum": "^4.1.1", "laravel/sanctum": "^4.0.8",
"laravel/tinker": "^2.10.1", "laravel/tinker": "^2.10.1",
"orchestra/testbench-core": "^9.12.0 || ^10.4", "orchestra/testbench-core": "^9.12.0 || ^10.1",
"pestphp/pest": "^3.8.2", "pestphp/pest": "^3.8.0",
"sebastian/environment": "^7.2.1 || ^8.0" "sebastian/environment": "^7.2.0 || ^8.0"
}, },
"type": "library", "type": "library",
"extra": { "extra": {
@ -6493,7 +6494,7 @@
"type": "patreon" "type": "patreon"
} }
], ],
"time": "2025-06-11T01:04:21+00:00" "time": "2025-04-03T14:33:09+00:00"
}, },
{ {
"name": "phar-io/manifest", "name": "phar-io/manifest",
@ -6685,16 +6686,16 @@
}, },
{ {
"name": "phpunit/php-code-coverage", "name": "phpunit/php-code-coverage",
"version": "11.0.10", "version": "11.0.9",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
"reference": "1a800a7446add2d79cc6b3c01c45381810367d76" "reference": "14d63fbcca18457e49c6f8bebaa91a87e8e188d7"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/1a800a7446add2d79cc6b3c01c45381810367d76", "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/14d63fbcca18457e49c6f8bebaa91a87e8e188d7",
"reference": "1a800a7446add2d79cc6b3c01c45381810367d76", "reference": "14d63fbcca18457e49c6f8bebaa91a87e8e188d7",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -6751,27 +6752,15 @@
"support": { "support": {
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
"security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/show" "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/11.0.9"
}, },
"funding": [ "funding": [
{ {
"url": "https://github.com/sebastianbergmann", "url": "https://github.com/sebastianbergmann",
"type": "github" "type": "github"
},
{
"url": "https://liberapay.com/sebastianbergmann",
"type": "liberapay"
},
{
"url": "https://thanks.dev/u/gh/sebastianbergmann",
"type": "thanks_dev"
},
{
"url": "https://tidelift.com/funding/github/packagist/phpunit/php-code-coverage",
"type": "tidelift"
} }
], ],
"time": "2025-06-18T08:56:18+00:00" "time": "2025-02-25T13:26:39+00:00"
}, },
{ {
"name": "phpunit/php-file-iterator", "name": "phpunit/php-file-iterator",
@ -7020,16 +7009,16 @@
}, },
{ {
"name": "phpunit/phpunit", "name": "phpunit/phpunit",
"version": "11.5.24", "version": "11.5.21",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git", "url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "6b07ab1047155cf38f82dd691787a277782271dd" "reference": "d565e2cdc21a7db9dc6c399c1fc2083b8010f289"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/6b07ab1047155cf38f82dd691787a277782271dd", "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/d565e2cdc21a7db9dc6c399c1fc2083b8010f289",
"reference": "6b07ab1047155cf38f82dd691787a277782271dd", "reference": "d565e2cdc21a7db9dc6c399c1fc2083b8010f289",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -7043,7 +7032,7 @@
"phar-io/manifest": "^2.0.4", "phar-io/manifest": "^2.0.4",
"phar-io/version": "^3.2.1", "phar-io/version": "^3.2.1",
"php": ">=8.2", "php": ">=8.2",
"phpunit/php-code-coverage": "^11.0.10", "phpunit/php-code-coverage": "^11.0.9",
"phpunit/php-file-iterator": "^5.1.0", "phpunit/php-file-iterator": "^5.1.0",
"phpunit/php-invoker": "^5.0.1", "phpunit/php-invoker": "^5.0.1",
"phpunit/php-text-template": "^4.0.1", "phpunit/php-text-template": "^4.0.1",
@ -7101,7 +7090,7 @@
"support": { "support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues", "issues": "https://github.com/sebastianbergmann/phpunit/issues",
"security": "https://github.com/sebastianbergmann/phpunit/security/policy", "security": "https://github.com/sebastianbergmann/phpunit/security/policy",
"source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.24" "source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.21"
}, },
"funding": [ "funding": [
{ {
@ -7125,7 +7114,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2025-06-20T11:31:02+00:00" "time": "2025-05-21T12:35:00+00:00"
}, },
{ {
"name": "sebastian/cli-parser", "name": "sebastian/cli-parser",

View File

@ -94,6 +94,5 @@ return [
'template' => [ 'template' => [
'dir' => env('LDAP_TEMPLATE_DRIVER','templates'), 'dir' => env('LDAP_TEMPLATE_DRIVER','templates'),
'exclude_system' => env('LDAP_TEMPLATE_EXCLUDE_SYSTEM',FALSE),
], ],
]; ];

193
package-lock.json generated
View File

@ -2800,21 +2800,6 @@
"postcss": "^8.1.0" "postcss": "^8.1.0"
} }
}, },
"node_modules/available-typed-arrays": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
"integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==",
"license": "MIT",
"dependencies": {
"possible-typed-array-names": "^1.0.0"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/axios": { "node_modules/axios": {
"version": "1.10.0", "version": "1.10.0",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.10.0.tgz", "resolved": "https://registry.npmjs.org/axios/-/axios-1.10.0.tgz",
@ -3327,9 +3312,9 @@
} }
}, },
"node_modules/caniuse-lite": { "node_modules/caniuse-lite": {
"version": "1.0.30001724", "version": "1.0.30001723",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001724.tgz", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001723.tgz",
"integrity": "sha512-WqJo7p0TbHDOythNTqYujmaJTvtYRZrjpP8TCvH6Vb9CYJerJNKamKzIWOM4BkQatWj9H2lYulpdAQNBe7QhNA==", "integrity": "sha512-1R/elMjtehrFejxwmexeXAtae5UO9iSyFn6G/I806CYC/BLyyBk1EPhrKBkWhy6wM6Xnm47dSJQec+tLJ39WHw==",
"funding": [ "funding": [
{ {
"type": "opencollective", "type": "opencollective",
@ -4340,9 +4325,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/electron-to-chromium": { "node_modules/electron-to-chromium": {
"version": "1.5.171", "version": "1.5.170",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.171.tgz", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.170.tgz",
"integrity": "sha512-scWpzXEJEMrGJa4Y6m/tVotb0WuvNmasv3wWVzUAeCgKU0ToFOhUW6Z+xWnRQANMYGxN4ngJXIThgBJOqzVPCQ==", "integrity": "sha512-GP+M7aeluQo9uAyiTCxgIj/j+PrWhMlY7LFVj8prlsPljd0Fdg9AprlfUi+OCSFWy9Y5/2D/Jrj9HS8Z4rpKWA==",
"license": "ISC" "license": "ISC"
}, },
"node_modules/elliptic": { "node_modules/elliptic": {
@ -4923,21 +4908,6 @@
} }
} }
}, },
"node_modules/for-each": {
"version": "0.3.5",
"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz",
"integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==",
"license": "MIT",
"dependencies": {
"is-callable": "^1.2.7"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/form-data": { "node_modules/form-data": {
"version": "4.0.3", "version": "4.0.3",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.3.tgz", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.3.tgz",
@ -5761,18 +5731,6 @@
"integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/is-callable": {
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
"integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-core-module": { "node_modules/is-core-module": {
"version": "2.16.1", "version": "2.16.1",
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz",
@ -5878,21 +5836,6 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/is-typed-array": {
"version": "1.1.15",
"resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz",
"integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==",
"license": "MIT",
"dependencies": {
"which-typed-array": "^1.1.16"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-what": { "node_modules/is-what": {
"version": "3.14.1", "version": "3.14.1",
"resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz", "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz",
@ -7108,53 +7051,21 @@
} }
}, },
"node_modules/pbkdf2": { "node_modules/pbkdf2": {
"version": "3.1.3", "version": "3.1.2",
"resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.3.tgz", "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz",
"integrity": "sha512-wfRLBZ0feWRhCIkoMB6ete7czJcnNnqRpcoWQBLqatqXXmelSRqfdDK4F3u9T2s2cXas/hQJcryI/4lAL+XTlA==", "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"create-hash": "~1.1.3", "create-hash": "^1.1.2",
"create-hmac": "^1.1.7", "create-hmac": "^1.1.4",
"ripemd160": "=2.0.1", "ripemd160": "^2.0.1",
"safe-buffer": "^5.2.1", "safe-buffer": "^5.0.1",
"sha.js": "^2.4.11", "sha.js": "^2.4.8"
"to-buffer": "^1.2.0"
}, },
"engines": { "engines": {
"node": ">=0.12" "node": ">=0.12"
} }
}, },
"node_modules/pbkdf2/node_modules/create-hash": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.1.3.tgz",
"integrity": "sha512-snRpch/kwQhcdlnZKYanNF1m0RDlrCdSKQaH87w1FCFPVPNCQ/Il9QJKAX2jVBZddRdaHBMC+zXa9Gw9tmkNUA==",
"license": "MIT",
"dependencies": {
"cipher-base": "^1.0.1",
"inherits": "^2.0.1",
"ripemd160": "^2.0.0",
"sha.js": "^2.4.0"
}
},
"node_modules/pbkdf2/node_modules/hash-base": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/hash-base/-/hash-base-2.0.2.tgz",
"integrity": "sha512-0TROgQ1/SxE6KmxWSvXHvRj90/Xo1JvZShofnYF+f6ZsGtR4eES7WfrQzPalmyagfKZCXpVnitiRebZulWsbiw==",
"license": "MIT",
"dependencies": {
"inherits": "^2.0.1"
}
},
"node_modules/pbkdf2/node_modules/ripemd160": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.1.tgz",
"integrity": "sha512-J7f4wutN8mdbV08MJnXibYpCOPHR+yzy+iQ/AsjMv2j8cLavQ8VGagDFUwwTAdF8FmRKVeNpbTTEwNHCW1g94w==",
"license": "MIT",
"dependencies": {
"hash-base": "^2.0.0",
"inherits": "^2.0.1"
}
},
"node_modules/pe7-icon": { "node_modules/pe7-icon": {
"version": "1.0.4", "version": "1.0.4",
"resolved": "https://registry.npmjs.org/pe7-icon/-/pe7-icon-1.0.4.tgz", "resolved": "https://registry.npmjs.org/pe7-icon/-/pe7-icon-1.0.4.tgz",
@ -7206,15 +7117,6 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/possible-typed-array-names": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz",
"integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
}
},
"node_modules/postcss": { "node_modules/postcss": {
"version": "8.5.6", "version": "8.5.6",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
@ -9094,9 +8996,9 @@
} }
}, },
"node_modules/terser": { "node_modules/terser": {
"version": "5.43.1", "version": "5.43.0",
"resolved": "https://registry.npmjs.org/terser/-/terser-5.43.1.tgz", "resolved": "https://registry.npmjs.org/terser/-/terser-5.43.0.tgz",
"integrity": "sha512-+6erLbBm0+LROX2sPXlUYx/ux5PyE9K/a92Wrt6oA+WDAoFTdpHE5tCYCI5PNzq2y8df4rA+QgHLJuR4jNymsg==", "integrity": "sha512-CqNNxKSGKSZCunSvwKLTs8u8sGGlp27sxNZ4quGh0QeNuyHM0JSEM/clM9Mf4zUp6J+tO2gUXhgXT2YMMkwfKQ==",
"license": "BSD-2-Clause", "license": "BSD-2-Clause",
"dependencies": { "dependencies": {
"@jridgewell/source-map": "^0.3.3", "@jridgewell/source-map": "^0.3.3",
@ -9228,26 +9130,6 @@
"integrity": "sha512-okFlQcoGTi4LQBG/PgSYblw9VOyptsz2KJZqc6qtgGdes8VktzUQkj4BI2blit072iS8VODNcMA+tvnS9dnuMA==", "integrity": "sha512-okFlQcoGTi4LQBG/PgSYblw9VOyptsz2KJZqc6qtgGdes8VktzUQkj4BI2blit072iS8VODNcMA+tvnS9dnuMA==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/to-buffer": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.2.1.tgz",
"integrity": "sha512-tB82LpAIWjhLYbqjx3X4zEeHN6M8CiuOEy2JY8SEQVdYRe3CCHOFaqrBW1doLDrfpWhplcW7BL+bO3/6S3pcDQ==",
"license": "MIT",
"dependencies": {
"isarray": "^2.0.5",
"safe-buffer": "^5.2.1",
"typed-array-buffer": "^1.0.3"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/to-buffer/node_modules/isarray": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
"integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
"license": "MIT"
},
"node_modules/to-regex-range": { "node_modules/to-regex-range": {
"version": "5.0.1", "version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
@ -9294,20 +9176,6 @@
"node": ">= 0.6" "node": ">= 0.6"
} }
}, },
"node_modules/typed-array-buffer": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz",
"integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==",
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.3",
"es-errors": "^1.3.0",
"is-typed-array": "^1.1.14"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/undici-types": { "node_modules/undici-types": {
"version": "7.8.0", "version": "7.8.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.8.0.tgz", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.8.0.tgz",
@ -9923,9 +9791,9 @@
} }
}, },
"node_modules/webpack/node_modules/webpack-sources": { "node_modules/webpack/node_modules/webpack-sources": {
"version": "3.3.3", "version": "3.3.2",
"resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.3.3.tgz", "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.3.2.tgz",
"integrity": "sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==", "integrity": "sha512-ykKKus8lqlgXX/1WjudpIEjqsafjOTcOJqxnAbMLAu/KCsDCJ6GBtvscewvTkrn24HsnvFwrSCbenFrhtcCsAA==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=10.13.0" "node": ">=10.13.0"
@ -9987,27 +9855,6 @@
"node": ">= 8" "node": ">= 8"
} }
}, },
"node_modules/which-typed-array": {
"version": "1.1.19",
"resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz",
"integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==",
"license": "MIT",
"dependencies": {
"available-typed-arrays": "^1.0.7",
"call-bind": "^1.0.8",
"call-bound": "^1.0.4",
"for-each": "^0.3.5",
"get-proto": "^1.0.1",
"gopd": "^1.2.0",
"has-tostringtag": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/wildcard": { "node_modules/wildcard": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz",

View File

@ -15,7 +15,7 @@ function getNode(item) {
$.ajax({ $.ajax({
url: '/frame', url: '/frame',
method: 'POST', method: 'POST',
data: { _key: item }, data: { key: item },
dataType: 'html', dataType: 'html',
beforeSend: function() { beforeSend: function() {
content = $('.main-content') content = $('.main-content')
@ -96,7 +96,7 @@ $(document).ready(function() {
lazyLoad: function(event,data) { lazyLoad: function(event,data) {
data.result = { data.result = {
url: '/ajax/children', url: '/ajax/children',
data: {_key: data.node.data.item,depth: 1} data: {key: data.node.data.item,depth: 1}
}; };
expandChildren(data.tree.rootNode); expandChildren(data.tree.rootNode);

View File

@ -1,23 +0,0 @@
/* JavaScript template engine abstraction layer */
/* Currently implemented for jquery */
// Get a value from an attribute
function get_attribute(attribute,start,end) {
var val = $('#'+attribute).find('input').val();
return ((start !== undefined) && (end !== undefined))
? val.substring(start,end)
: val;
}
// Put a value to an attribute
function put_attribute(attribute,result) {
// Get the value, if the value hasnt changed, then we dont need to do anything
if (get_attribute(attribute) === result)
return;
$('#'+attribute)
.find('input')
.val(result)
.trigger('change');
}

View File

@ -1,81 +0,0 @@
//
// Purpose of this file is to remap characters as ASCII characters
//
//
var to_ascii_array = new Array();
to_ascii_array['à'] = 'a';
to_ascii_array['á'] = 'a';
to_ascii_array['â'] = 'a';
to_ascii_array['À'] = 'a';
to_ascii_array['ã'] = 'a';
to_ascii_array['Ã¥'] = 'a';
to_ascii_array['À'] = 'A';
to_ascii_array['Á'] = 'A';
to_ascii_array['Ä'] = 'A';
to_ascii_array['Â'] = 'A';
to_ascii_array['Ã'] = 'A';
to_ascii_array['Å'] = 'A';
to_ascii_array['é'] = 'e';
to_ascii_array['Ú'] = 'e';
to_ascii_array['ë'] = 'e';
to_ascii_array['ê'] = 'e';
to_ascii_array['€'] = 'E';
to_ascii_array['ï'] = 'i';
to_ascii_array['î'] = 'i';
to_ascii_array['ì'] = 'i';
to_ascii_array['í'] = 'i';
to_ascii_array['Ï'] = 'I';
to_ascii_array['Î'] = 'I';
to_ascii_array['Ì'] = 'I';
to_ascii_array['Í'] = 'I';
to_ascii_array['ò'] = 'o';
to_ascii_array['ó'] = 'o';
to_ascii_array['ÃŽ'] = 'o';
to_ascii_array['õ'] = 'o';
to_ascii_array['ö'] = 'o';
to_ascii_array['Þ'] = 'o';
to_ascii_array['Ò'] = 'O';
to_ascii_array['Ó'] = 'O';
to_ascii_array['Ô'] = 'O';
to_ascii_array['Õ'] = 'O';
to_ascii_array['Ö'] = 'O';
to_ascii_array['Ø'] = 'O';
to_ascii_array['ù'] = 'u';
to_ascii_array['ú'] = 'u';
to_ascii_array['Ì'] = 'u';
to_ascii_array['û'] = 'u';
to_ascii_array['Ù'] = 'U';
to_ascii_array['Ú'] = 'U';
to_ascii_array['Ü'] = 'U';
to_ascii_array['Û'] = 'U';
to_ascii_array['Ê'] = 'ae';
to_ascii_array['Æ'] = 'AE';
to_ascii_array['Ü'] = 'y';
to_ascii_array['ÿ'] = 'y';
to_ascii_array['ß'] = 'SS';
to_ascii_array['Ç'] = 'C';
to_ascii_array['ç'] = 'c';
to_ascii_array['Ñ'] = 'N';
to_ascii_array['ñ'] = 'n';
to_ascii_array['¢'] = 'c';
to_ascii_array['©'] = '(C)';
to_ascii_array['®'] = '(R)';
to_ascii_array['«'] = '<<';
to_ascii_array['»'] = '>>';
function toAscii(text) {
//var text = field.value;
var output = '';
for (position=0; position < text.length; position++) {
var tmp = text.substring(position,position+1);
if (to_ascii_array[tmp] !== undefined)
tmp = to_ascii_array[tmp];
output += tmp;
}
return output;
}

View File

@ -18,8 +18,3 @@
<!-- Any Custom JS --> <!-- Any Custom JS -->
<script src="{{ asset('js/custom.js') }}"></script> <script src="{{ asset('js/custom.js') }}"></script>
@endif @endif
@if(file_exists('js/template.js'))
<!-- Template Engine JS -->
<script src="{{ asset('js/template.js') }}"></script>
@endif

View File

@ -7,10 +7,6 @@
<span class="d-flex justify-content-between"> <span class="d-flex justify-content-between">
<span style="width: 20em;"> <span style="width: 20em;">
<strong class="align-middle"><abbr title="{{ $o->description }}">{{ $o->name }}</abbr></strong> <strong class="align-middle"><abbr title="{{ $o->description }}">{{ $o->name }}</abbr></strong>
@if($new && $template?->onChange($o->name)->count())
<sup data-bs-toggle="tooltip" title="@lang('Value calculated by template')"><i class="fas fa-wand-magic-sparkles"></i></sup>
@endif
@if($o->hints->count()) @if($o->hints->count())
<sup> <sup>
[ [

View File

@ -34,15 +34,3 @@
</div> </div>
</div> </div>
</x-attribute.layout> </x-attribute.layout>
@if($new && ($x=$template?->onChange($o->name))?->count())
@section('page-scripts')
<!-- START: ONCHANGE PROCESSING {{ $o->name }} -->
<script type="text/javascript">
$('#{{ $o->name_lc }}').on('change',function() {
{!! $x->join('') !!}
});
</script>
<!-- END: ONCHANGE PROCESSING {{ $o->name }} -->
@append
@endif

View File

@ -4,7 +4,7 @@
@foreach(($o->tagValues($langtag)->count() ? $o->tagValues($langtag) : [$langtag => NULL]) as $key => $value) @foreach(($o->tagValues($langtag)->count() ? $o->tagValues($langtag) : [$langtag => NULL]) as $key => $value)
@if($edit) @if($edit)
<div class="input-group has-validation"> <div class="input-group has-validation">
<x-form.select id="userpassword_hash_{{$loop->index}}{{$template?->name ?? ''}}" name="_userpassword_hash[{{ $langtag }}][]" :value="$o->hash($new ? '' : ($value ?? ''))->id()" :options="$helpers" allowclear="false" :disabled="! $new"/> <x-form.select id="userpassword_hash_{{$loop->index}}{{$template?->name ?? ''}}" name="userpassword_hash[{{ $langtag }}][]" :value="$o->hash($new ? '' : ($value ?? ''))->id()" :options="$helpers" allowclear="false" :disabled="! $new"/>
<input type="password" @class(['form-control','is-invalid'=>($e=$errors->get($o->name_lc.'.'.$langtag.'.'.$loop->index)),'mb-1','border-focus'=>! $o->tagValuesOld($langtag)->contains($value),'bg-success-subtle'=>$updated]) name="{{ $o->name_lc }}[{{ $langtag }}][]" value="{{ Arr::get(old($o->name_lc),$langtag.'.'.$loop->index,$value ? md5($value) : '') }}" @readonly(! $new)> <input type="password" @class(['form-control','is-invalid'=>($e=$errors->get($o->name_lc.'.'.$langtag.'.'.$loop->index)),'mb-1','border-focus'=>! $o->tagValuesOld($langtag)->contains($value),'bg-success-subtle'=>$updated]) name="{{ $o->name_lc }}[{{ $langtag }}][]" value="{{ Arr::get(old($o->name_lc),$langtag.'.'.$loop->index,$value ? md5($value) : '') }}" @readonly(! $new)>
<div class="invalid-feedback pb-2"> <div class="invalid-feedback pb-2">

View File

@ -3,24 +3,24 @@
@foreach(($o->values->count() ? $o->values : [NULL]) as $value) @foreach(($o->values->count() ? $o->values : [NULL]) as $value)
@if($edit) @if($edit)
<div class="input-group has-validation mb-3"> <div class="input-group has-validation mb-3">
<select @class(['form-select','is-invalid'=>$errors->get('_rdn')]) id="rdn" name="_rdn"> <select class="form-select @error('rdn')is-invalid @enderror" id="rdn" name="rdn">
<option value=""></option> <option value=""></option>
@foreach($o->attrs->map(fn($item)=>['id'=>$item,'value'=>$item]) as $option) @foreach($o->attrs->map(fn($item)=>['id'=>$item,'value'=>$item]) as $option)
@continue(! Arr::get($option,'value')) @continue(! Arr::get($option,'value'))
<option value="{{ strtolower(Arr::get($option,'id')) }}" @selected(Arr::get($option,'id') == old('_rdn',$value ?? ''))>{{ Arr::get($option,'value') }}</option> <option value="{{ strtolower(Arr::get($option,'id')) }}" @selected(Arr::get($option,'id') == old('rdn',$value ?? ''))>{{ Arr::get($option,'value') }}</option>
@endforeach @endforeach
</select> </select>
<span class="input-group-text">=</span> <span class="input-group-text">=</span>
<input type="text" @class(['form-control','is-invalid'=>$errors->get('_rdn_value')]) id="rdn_value" name="_rdn_value" value="{{ old('_rdn_value') }}" placeholder="rdn"> <input type="text" @class(['form-control','is-invalid'=>$errors->get('rdn_value')]) id="rdn_value" name="rdn_value" value="{{ old('rdn_value') }}" placeholder="rdn">
<label class="input-group-text" for="inputGroupSelect02">,{{ $o->base }}</label> <label class="input-group-text" for="inputGroupSelect02">,{{ $o->base }}</label>
<div class="invalid-feedback pb-2"> <div class="invalid-feedback pb-2">
@error('_rdn') @error('rdn')
{{ $message }} {{ $message }}
@enderror @enderror
@error('_rdn_value') @error('rdn_value')
{{ $message }} {{ $message }}
@enderror @enderror
</div> </div>

View File

@ -24,8 +24,8 @@
<form id="dn-create" method="POST" class="needs-validation" action="{{ url((int)$step === 2 ? 'entry/create' : 'entry/add') }}" enctype="multipart/form-data" novalidate> <form id="dn-create" method="POST" class="needs-validation" action="{{ url((int)$step === 2 ? 'entry/create' : 'entry/add') }}" enctype="multipart/form-data" novalidate>
@csrf @csrf
<input type="hidden" name="_key" value="{{ Crypt::encryptString('*create|'.$container) }}"> <input type="hidden" name="key" value="{{ Crypt::encryptString('*create|'.$container) }}">
<input type="hidden" name="_step" value="{{ $step }}"> <input type="hidden" name="step" value="{{ $step }}">
@switch($step) @switch($step)
@case(1) @case(1)
@ -63,11 +63,10 @@
@break @break
@case(2) @case(2)
<input type="hidden" name="_template" value="{{ $template?->file }}"> <x-attribute-type :o="$o->getObject('rdn')" :edit="TRUE" :new="FALSE" :updated="FALSE"/>
<x-attribute-type :o="$o->getObject('rdn')" :edit="TRUE" :new="TRUE" :template="$template" :updated="FALSE"/>
@foreach($o->getVisibleAttributes() as $ao) @foreach($o->getVisibleAttributes() as $ao)
<x-attribute-type :o="$ao" :edit="TRUE" :new="TRUE" :template="$template" :updated="FALSE"/> <x-attribute-type :o="$ao" :edit="TRUE" :new="FALSE" :template="$template" :updated="FALSE"/>
@endforeach @endforeach
@if(! $template) @if(! $template)

View File

@ -101,7 +101,7 @@
<div class="tab-content"> <div class="tab-content">
@php($up=(session()->pull('updated') ?: collect())) @php($up=(session()->pull('updated') ?: collect()))
@foreach($o->getVisibleAttributes() as $ao) @foreach($o->getVisibleAttributes() as $ao)
<x-attribute-type :o="$ao" :edit="TRUE" :new="FALSE" :template="$template ?? NULL" :updated="$up->contains($ao->name_lc)"/> <x-attribute-type :o="$ao" :edit="TRUE" :new="FALSE" :updated="$up->contains($ao->name_lc)"/>
@endforeach @endforeach
@include('fragment.dn.add_attr') @include('fragment.dn.add_attr')
@ -124,7 +124,7 @@
<!-- Internal Attributes --> <!-- Internal Attributes -->
<div class="tab-pane mt-3" id="internal" role="tabpanel"> <div class="tab-pane mt-3" id="internal" role="tabpanel">
@foreach($o->getInternalAttributes() as $ao) @foreach($o->getInternalAttributes() as $ao)
<x-attribute-type :o="$ao" :edit="FALSE" :new="FALSE" :template="$template ?? NULL" :updated="FALSE"/> <x-attribute-type :o="$ao" :edit="FALSE" :new="FALSE" :updated="FALSE"/>
@endforeach @endforeach
</div> </div>
</div> </div>

View File

@ -15,7 +15,7 @@
<div class="main-card mb-3 card"> <div class="main-card mb-3 card">
<form id="import-form" action="{{ url('import/process/ldif') }}" method="POST" enctype="multipart/form-data"> <form id="import-form" action="{{ url('import/process/ldif') }}" method="POST" enctype="multipart/form-data">
@csrf @csrf
<input type="hidden" name="_key" value="{{ Crypt::encryptString('*import|_NOP') }}"> <input type="hidden" name="key" value="{{ Crypt::encryptString('*import|_NOP') }}">
<div class="card-header"> <div class="card-header">
@lang('LDIF Import') @lang('LDIF Import')

View File

@ -44,12 +44,6 @@
<li class="ps-0 p-1"> <li class="ps-0 p-1">
<i class="fas fa-fw fa-sitemap me-2"></i> Hierarchical Tree View <i class="fas fa-fw fa-sitemap me-2"></i> Hierarchical Tree View
</li> </li>
<li class="ps-0 p-1">
<i class="fas fa-fw fa-clone me-2"></i> Creation and Modification Templates
</li>
<li class="ps-0 p-1">
<i class="fas fa-fw fa-magnifying-glass-chart me-2"></i> Data Rich Attribute Values
</li>
<li class="ps-0 p-1"> <li class="ps-0 p-1">
<i class="fas fa-fw fa-language me-2"></i> Multi-language Support <i class="fas fa-fw fa-language me-2"></i> Multi-language Support
</li> </li>

View File

@ -15,7 +15,7 @@
"givenName": { "givenName": {
"display": "First Name", "display": "First Name",
"onchange": [ "onchange": [
"=autoFill(cn;%givenName% %sn/U%)", "=autoFill(cn;%givenName% %sn%)",
"=autoFill(uid;%givenName|0-1/l%%sn/l%)" "=autoFill(uid;%givenName|0-1/l%%sn/l%)"
], ],
"order": 1 "order": 1
@ -23,7 +23,7 @@
"sn": { "sn": {
"display": "Last Name", "display": "Last Name",
"onchange": [ "onchange": [
"=autoFill(cn;%givenName% %sn/U%)", "=autoFill(cn;%givenName% %sn%)",
"=autoFill(uid;%givenName|0-1/l%%sn/l%)" "=autoFill(uid;%givenName|0-1/l%%sn/l%)"
], ],
"order": 2 "order": 2

View File

@ -34,7 +34,7 @@ class ImportTest extends TestCase
->from('/import') ->from('/import')
->post('/import/process/ldif',[ ->post('/import/process/ldif',[
'_token' => csrf_token(), '_token' => csrf_token(),
'_key'=>Crypt::encryptString('*import|_NOP'), 'key'=>Crypt::encryptString('*import|_NOP'),
'file' => $file, 'file' => $file,
]); ]);