diff --git a/app/Classes/Template.php b/app/Classes/Template.php
new file mode 100644
index 00000000..8cd6fb30
--- /dev/null
+++ b/app/Classes/Template.php
@@ -0,0 +1,46 @@
+file = $file;
+
+ try {
+ $this->template = json_decode($td->get($file),null,512,JSON_OBJECT_AS_ARRAY|JSON_THROW_ON_ERROR);
+
+ } catch (\JsonException $e) {
+ $this->invalid = TRUE;
+ $this->reason = $e->getMessage();
+ }
+ }
+
+ 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),
+
+ default => throw new \Exception('Unknown key: '.$key),
+ };
+ }
+
+ public function __toString(): string
+ {
+ return $this->invalid ? '' : Arr::get($this->template,'title','No Template Name');
+ }
+}
\ No newline at end of file
diff --git a/app/Ldap/Entry.php b/app/Ldap/Entry.php
index 63243e44..faa89187 100644
--- a/app/Ldap/Entry.php
+++ b/app/Ldap/Entry.php
@@ -4,9 +4,12 @@ namespace App\Ldap;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Crypt;
+use Illuminate\Support\Facades\Storage;
+use Illuminate\Support\Str;
use LdapRecord\Support\Arr;
use LdapRecord\Models\Model;
+use App\Classes\Template;
use App\Classes\LDAP\Attribute;
use App\Classes\LDAP\Attribute\Factory;
use App\Classes\LDAP\Export\LDIF;
@@ -39,9 +42,19 @@ class Entry extends Model
public function __construct(array $attributes = [])
{
$this->objects = collect();
- $this->templates = collect(['default'=>__('LDAP Entry')]);
parent::__construct($attributes);
+
+ // Load any templates
+ $x = Storage::disk(config('pla.template.dir'));
+ $this->templates = collect();
+
+ foreach (array_filter($x->files(),fn($item)=>Str::endsWith($item,'.json')) as $file)
+ $this->templates->put($file,new Template($file));
+
+ $this->templates = $this->templates
+ ->filter(fn($item)=>(! $item->invalid) && $item->enabled)
+ ->sortBy(fn($item)=>$item);
}
public function discardChanges(): static
@@ -131,6 +144,13 @@ class Entry extends Model
$this->objects = collect();
}
+ // 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)=>(! $item->regexp) || preg_match($item->regexp,$this->dn))
+ ->filter(fn($item)=>! count(array_diff($item->objectclasses,array_map('strtolower',Arr::get($this->attributes,'objectclass')))));
+ }
+
return $this;
}
@@ -531,4 +551,9 @@ class Entry extends Model
$this->rdnbase = $bdn;
}
+
+ public function template(string $item): Template|Null
+ {
+ return Arr::get($this->templates,$item);
+ }
}
\ No newline at end of file
diff --git a/config/filesystems.php b/config/filesystems.php
new file mode 100644
index 00000000..6c9a2400
--- /dev/null
+++ b/config/filesystems.php
@@ -0,0 +1,10 @@
+ [
+ 'templates' => [
+ 'driver' => 'local',
+ 'root' => base_path(env('LDAP_TEMPLATE_DIR','templates')),
+ ],
+ ],
+];
diff --git a/config/pla.php b/config/pla.php
index e3d0f752..bbb09f75 100644
--- a/config/pla.php
+++ b/config/pla.php
@@ -76,4 +76,8 @@ return [
'attr' => [env('LDAP_LOGIN_ATTR','uid') => env('LDAP_LOGIN_ATTR_DESC','User ID')], // Attribute used to find user for login
'objectclass' => explode(',',env('LDAP_LOGIN_OBJECTCLASS', 'posixAccount')), // Objectclass that users must contain to login
],
+
+ 'template' => [
+ 'dir' => env('LDAP_TEMPLATE_DRIVER','templates'),
+ ],
];
\ No newline at end of file
diff --git a/resources/views/fragment/template/dn.blade.php b/resources/views/fragment/template/dn.blade.php
new file mode 100644
index 00000000..326bd0bf
--- /dev/null
+++ b/resources/views/fragment/template/dn.blade.php
@@ -0,0 +1,17 @@
+
+
\ No newline at end of file
diff --git a/resources/views/frames/dn.blade.php b/resources/views/frames/dn.blade.php
index 480ebcac..b581795a 100644
--- a/resources/views/frames/dn.blade.php
+++ b/resources/views/frames/dn.blade.php
@@ -74,53 +74,49 @@
-
- @if($o->templates->count() > 1)
- @foreach($o->templates as $template => $name)
- $loop->index === 0])>{{ $name }}
- @endforeach
+
+ @foreach($o->templates as $template => $name)
+ $loop->index === 0])> {{ $name }}
+ @endforeach
+ @if($o->templates->count())
+ (! $o->templates->count())])>{{ __('LDAP Entry') }}
@endif
@foreach($o->templates as $template => $name)
- @switch($template)
- @case('default')
-
$loop->index === 0]) id="template-{{$template}}" role="tabpanel">
-
-
- @break
-
- @default
-
$loop->index === 0]) id="template-{{$template}}" role="tabpanel">
-
{{$name}}
-
- @endswitch
+
$loop->index === 0]) id="template-{{$template}}" role="tabpanel">
+ @include('fragment.template.dn',['template'=>$template])
+
@endforeach
-
-
-
-
-
-
-
+
(! $o->templates->count())]) id="template-default" role="tabpanel">
+
+
+
+
+
@@ -162,7 +158,6 @@
// Find all input items and turn off readonly
$('input.form-control').each(function() {
- // Except for objectClass - @todo show an "X" instead
if ($(this)[0].name.match(/^objectclass/))
return;
diff --git a/templates/dns_domain.json b/templates/dns_domain.json
new file mode 100644
index 00000000..afb02f69
--- /dev/null
+++ b/templates/dns_domain.json
@@ -0,0 +1,22 @@
+{
+ "title": "Generic: DNS Entry",
+ "description": "New DNS Entry",
+ "enabled": true,
+ "icon": "fa-globe",
+ "rdn": "dc",
+
+ "objectclasses": [
+ "dnsDomain"
+ ],
+
+ "attributes": {
+ "dc": {
+ "display": "Domain Component",
+ "order": 1
+ },
+ "associatedDomain": {
+ "display": "Associated Domain",
+ "order": 2
+ }
+ }
+}
diff --git a/templates/example.json b/templates/example.json
new file mode 100644
index 00000000..b775b879
--- /dev/null
+++ b/templates/example.json
@@ -0,0 +1,25 @@
+{
+ "title": "Example entry",
+ "description": "This is the description",
+ "enabled": false,
+ "icon": "fa-star-of-life",
+ "rdn": "o",
+ "regexp": "/^$/",
+
+ "objectclasses": [
+ "organization"
+ ],
+
+ "attributes": {
+ "attribute1": {
+ "display": "Attribute 1",
+ "hint": "This is an example",
+ "order": 1
+ },
+ "attribute2": {
+ "display": "Attribute 2",
+ "hint": "This is an example",
+ "order": 2
+ }
+ }
+}
diff --git a/templates/o.json b/templates/o.json
new file mode 100644
index 00000000..ba203fa3
--- /dev/null
+++ b/templates/o.json
@@ -0,0 +1,20 @@
+{
+ "title": "Generic: Organisational",
+ "description": "New Organisational",
+ "enabled": true,
+ "icon": "fa-building",
+ "rdn": "ou",
+ "regexp": "/^o=/",
+
+ "objectclasses": [
+ "organization"
+ ],
+
+ "attributes": {
+ "o": {
+ "display": "Organisation",
+ "hint": "This is an example",
+ "order": 1
+ }
+ }
+}
diff --git a/templates/ou.json b/templates/ou.json
new file mode 100644
index 00000000..8050f52b
--- /dev/null
+++ b/templates/ou.json
@@ -0,0 +1,25 @@
+{
+ "title": "Generic: Organisational Unit",
+ "description": "New Organisational Unit",
+ "enabled": true,
+ "icon": "fa-layer-group",
+ "rdn": "ou",
+ "regexp": "/^ou=.+,o=/",
+
+ "objectclasses": [
+ "organizationalUnit"
+ ],
+
+ "attributes": {
+ "ou": {
+ "display": "Organisational Unit",
+ "hint": "This is an example",
+ "order": 1
+ },
+ "attribute2": {
+ "display": "Attribute 2",
+ "hint": "This is an example",
+ "order": 2
+ }
+ }
+}
diff --git a/templates/user_account.json b/templates/user_account.json
new file mode 100644
index 00000000..bc6c5efa
--- /dev/null
+++ b/templates/user_account.json
@@ -0,0 +1,82 @@
+{
+ "title": "Generic: User Account",
+ "description": "New User Account",
+ "enabled": true,
+ "icon": "fa-user",
+ "rdn": "cn",
+ "regexp": "/,ou=People,o=/",
+
+ "objectclasses": [
+ "inetOrgPerson",
+ "posixAccount"
+ ],
+
+ "attributes": {
+ "givenName": {
+ "display": "First Name",
+ "onchange": [
+ "=autoFill(cn;%givenName% %sn%)",
+ "=autoFill(uid;%givenName|0-1/l%%sn/l%)"
+ ],
+ "order": 1
+ },
+ "sn": {
+ "display": "Last Name",
+ "onchange": [
+ "=autoFill(cn;%givenName% %sn%)",
+ "=autoFill(uid;%givenName|0-1/l%%sn/l%)"
+ ],
+ "order": 2
+ },
+ "cn": {
+ "display": "Common Name",
+ "readonly": true,
+ "order": 3
+ },
+ "uid": {
+ "display": "User ID",
+ "onchange": [
+ "=autoFill(homeDirectory;/home/users/%uid%)"
+ ],
+ "order": 4
+ },
+ "userPassword": {
+ "display": "Password",
+ "order": 5
+ },
+ "uidNumber": {
+ "display": "UID Number",
+ "readonly": true,
+ "value": "=php.GetNextNumber(/;uidNumber)",
+ "order": 6
+ },
+ "gidNumber": {
+ "display": "UID Number",
+ "readonly": true,
+ "onchange": [
+ "=autoFill(homeDirectory;/home/users/%gidNumber|0-0/T%/%uid|3-%)"
+ ],
+ "value": "=php.GetNextNumber(/;uidNumber)",
+ "value": "=php.PickList(/;(&(objectClass=posixGroup));gidNumber;%cn%;;;;cn)",
+ "order": 7
+ },
+ "homeDirectory": {
+ "display": "Home Directory",
+ "order": 8
+ },
+ "loginShell": {
+ "display": "Login Shell",
+ "select": {
+ "/bin/bash": "Bash",
+ "/bin/csh": "C Shell",
+ "/bin/dash": "Dash",
+ "/bin/sh": "Shell",
+ "/bin/tsh": "Turbo C Shell",
+ "/bin/zsh": "ZSH",
+ "/bin/false": "False",
+ "/usr/sbin/nologin": "No Login"
+ },
+ "order": 9
+ }
+ }
+}