From d61ecc96dbd9f069f9e8513886a54324d79be8a4 Mon Sep 17 00:00:00 2001 From: Deon George Date: Wed, 11 Jun 2025 19:28:38 +0930 Subject: [PATCH] Enable creation of new entries via templates --- app/Classes/Template.php | 13 +++++-- app/Http/Controllers/HomeController.php | 23 +++++++++-- app/Http/Requests/EntryAddRequest.php | 37 ++++++++++++++++-- app/Ldap/Entry.php | 2 +- app/Rules/HasStructuralObjectClass.php | 3 +- .../views/fragment/template/dn.blade.php | 2 +- resources/views/frames/create.blade.php | 38 +++++++++++++++---- 7 files changed, 96 insertions(+), 22 deletions(-) diff --git a/app/Classes/Template.php b/app/Classes/Template.php index 8cd6fb30..b49f6665 100644 --- a/app/Classes/Template.php +++ b/app/Classes/Template.php @@ -30,15 +30,20 @@ class Template public function __get(string $key): mixed { return match ($key) { - 'attributes' => array_map('strtolower',array_keys(Arr::get($this->template,$key))), - 'objectclasses' => array_map('strtolower',Arr::get($this->template,$key)), - 'enabled' => Arr::get($this->template,$key,FALSE), - 'icon','regexp' => Arr::get($this->template,$key), + 'attributes' => collect(array_map('strtolower',array_keys(Arr::get($this->template,$key)))), + 'objectclasses' => collect(array_map('strtolower',Arr::get($this->template,$key))), + 'enabled' => Arr::get($this->template,$key,FALSE) && (! $this->invalid), + 'icon','regexp','title' => Arr::get($this->template,$key), default => throw new \Exception('Unknown key: '.$key), }; } + public function __isset(string $key): bool + { + return array_key_exists($key,$this->template); + } + public function __toString(): string { return $this->invalid ? '' : Arr::get($this->template,'title','No Template Name'); diff --git a/app/Http/Controllers/HomeController.php b/app/Http/Controllers/HomeController.php index aa040060..ae71a6fe 100644 --- a/app/Http/Controllers/HomeController.php +++ b/app/Http/Controllers/HomeController.php @@ -55,16 +55,24 @@ class HomeController extends Controller $key = $this->request_key($request,collect(old())); + $template = NULL; $o = new Entry; + $o->setRDNBase($key['dn']); - if (count($x=array_filter(old('objectclass',$request->objectclass)))) { - $o->objectclass = $x; + if (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->required) as $ao) $o->{$ao->name} = [Entry::TAG_NOTAG=>'']; - $o->setRDNBase($key['dn']); + } elseif ($request->validated('template')) { + $template = $o->template($request->validated('template')); + $o->objectclass = [Entry::TAG_NOTAG=>$template->objectclasses->toArray()]; + + // @todo We need to add aliases + foreach($o->getAvailableAttributes()->filter(fn($item)=>$template->attributes->contains($item)) as $ao) + $o->{$ao->name} = [Entry::TAG_NOTAG=>'']; } $step = $request->step ? $request->step+1 : old('step'); @@ -74,6 +82,7 @@ class HomeController extends Controller ->with('bases',$this->bases()) ->with('o',$o) ->with('step',$step) + ->with('template',$template) ->with('container',old('container',$key['dn'])); } @@ -383,7 +392,12 @@ class HomeController extends Controller ->with('bases',$this->bases()); // If we are rendering a DN, rebuild our object - if ($key['dn']) { + if ($key['cmd'] === 'create') { + $o = new Entry; + $o->setRDNBase($key['dn']); + + } elseif ($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']); foreach (collect(old())->except(['key','dn','step','_token','userpassword_hash','rdn','rdn_value']) as $attr => $value) @@ -393,6 +407,7 @@ class HomeController extends Controller return match ($key['cmd']) { 'create' => $view ->with('container',old('container',$key['dn'])) + ->with('o',$o) ->with('step',1), 'dn' => $view diff --git a/app/Http/Requests/EntryAddRequest.php b/app/Http/Requests/EntryAddRequest.php index d3231772..dacbd2c2 100644 --- a/app/Http/Requests/EntryAddRequest.php +++ b/app/Http/Requests/EntryAddRequest.php @@ -66,12 +66,43 @@ class EntryAddRequest extends FormRequest 'min:1', 'max:1', ], - 'objectclass._null_'=>[ - 'required', + 'objectclass._null_' => [ + function (string $attribute,mixed $value,\Closure $fail) { + $oc = collect($value)->dot()->filter(); + + // If this is step 1 and there is no objectclass, and no template, then fail + if ((! $oc->count()) + && (request()->post('step') == 1) + && (! request()->post('template'))) + { + $fail(__('Select an objectclass or a template')); + } + + // Cant have both an objectclass and a template + if (request()->post('template') && $oc->count()) + $fail(__('You cannot select a template and an objectclass')); + }, 'array', 'min:1', new HasStructuralObjectClass, - ] + ], + 'template' => [ + function (string $attribute,mixed $value,\Closure $fail) { + $oc = collect(request()->post('objectclass'))->dot()->filter(); + + // If this is step 1 and there is no objectclass, and no template, then fail + if ((! collect($value)->filter()->count()) + && (request()->post('step') == 1) + && (! $oc->count())) + { + $fail(__('Select an objectclass or a template')); + } + + // Cant have both an objectclass and a template + if ($oc->count() && strlen($value)) + $fail(__('You cannot select a template and an objectclass')); + }, + ], ]) ->toArray(); } diff --git a/app/Ldap/Entry.php b/app/Ldap/Entry.php index 087a7f62..89c8c1dd 100644 --- a/app/Ldap/Entry.php +++ b/app/Ldap/Entry.php @@ -147,7 +147,7 @@ class Entry extends Model // Filter out our templates specific for this entry if ($this->dn && (! in_array(strtolower($this->dn),['cn=subschema']))) { $this->templates = $this->templates - ->filter(fn($item)=>! count(array_diff($item->objectclasses,array_map('strtolower',Arr::get($this->attributes,'objectclass'))))); + ->filter(fn($item)=>! count($item->objectclasses->diff(array_map('strtolower',Arr::get($this->attributes,'objectclass'))))); } return $this; diff --git a/app/Rules/HasStructuralObjectClass.php b/app/Rules/HasStructuralObjectClass.php index 7af2a313..dff4e7d1 100644 --- a/app/Rules/HasStructuralObjectClass.php +++ b/app/Rules/HasStructuralObjectClass.php @@ -24,6 +24,7 @@ class HasStructuralObjectClass implements ValidationRule if ($item && config('server')->schema('objectclasses',$item)->isStructural()) return; - $fail('There isnt a Structural Objectclass.'); + if (collect($value)->dot()->filter()->count()) + $fail(__('There isnt a Structural Objectclass.')); } } diff --git a/resources/views/fragment/template/dn.blade.php b/resources/views/fragment/template/dn.blade.php index 326bd0bf..b548b419 100644 --- a/resources/views/fragment/template/dn.blade.php +++ b/resources/views/fragment/template/dn.blade.php @@ -9,7 +9,7 @@ @php($up=(session()->pull('updated') ?: collect())) @php($attributes=$o->template($template)?->attributes) - @foreach($o->getVisibleAttributes()->filter(fn($item)=>in_array($item,$attributes)) as $ao) + @foreach($o->getVisibleAttributes()->filter(fn($item)=>$attributes->contains($item)) as $ao) @endforeach diff --git a/resources/views/frames/create.blade.php b/resources/views/frames/create.blade.php index 86af7aa1..75c20e35 100644 --- a/resources/views/frames/create.blade.php +++ b/resources/views/frames/create.blade.php @@ -17,7 +17,7 @@
- @lang('Create New Entry') - @lang('Step') {{ $step }} + @lang('Create New Entry') - @lang('Step') {{ $step }} @isset($template) {{ $template->title }}@endisset
@@ -30,19 +30,35 @@ @switch($step) @case(1)
-
+
+ + @if($o->templates->count()) +
+ @lang('OR') +
+ +
+ +
+ @endif
@break @@ -53,14 +69,12 @@ @endforeach - @include('fragment.dn.add_attr') - @break; @endswitch
-
+
@@ -102,7 +116,15 @@ } $(document).ready(function() { - @if($step === 2) + @if($step === 1) + $('#objectclass').on('select2:open',function(){ + $('#template').val(null).trigger('change'); + }); + + $('#template').on('select2:open',function(){ + $('#objectclass').val(null).trigger('change'); + }) + @elseif($step === 2) $('#newattr').on('change',function(item) { var oc = $('attribute#objectclass input[type=text]') .map((key,item)=>{return $(item).val()}).toArray();