Start of work on templates - identify templates that apply to existing entries
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 1m24s
Create Docker Image / Build Docker Image (arm64) (push) Successful in 2m37s
Create Docker Image / Final Docker Image Manifest (push) Successful in 10s
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 1m24s
Create Docker Image / Build Docker Image (arm64) (push) Successful in 2m37s
Create Docker Image / Final Docker Image Manifest (push) Successful in 10s
This commit is contained in:
parent
8602c2b17f
commit
8e8a902c80
46
app/Classes/Template.php
Normal file
46
app/Classes/Template.php
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Classes;
|
||||||
|
|
||||||
|
use Illuminate\Support\Arr;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
|
||||||
|
class Template
|
||||||
|
{
|
||||||
|
private string $file;
|
||||||
|
private array $template;
|
||||||
|
private(set) bool $invalid = FALSE;
|
||||||
|
private string $reason = '';
|
||||||
|
|
||||||
|
public function __construct(string $file)
|
||||||
|
{
|
||||||
|
$td = Storage::disk(config('pla.template.dir'));
|
||||||
|
|
||||||
|
$this->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');
|
||||||
|
}
|
||||||
|
}
|
@ -4,9 +4,12 @@ namespace App\Ldap;
|
|||||||
|
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Illuminate\Support\Facades\Crypt;
|
use Illuminate\Support\Facades\Crypt;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
use LdapRecord\Support\Arr;
|
use LdapRecord\Support\Arr;
|
||||||
use LdapRecord\Models\Model;
|
use LdapRecord\Models\Model;
|
||||||
|
|
||||||
|
use App\Classes\Template;
|
||||||
use App\Classes\LDAP\Attribute;
|
use App\Classes\LDAP\Attribute;
|
||||||
use App\Classes\LDAP\Attribute\Factory;
|
use App\Classes\LDAP\Attribute\Factory;
|
||||||
use App\Classes\LDAP\Export\LDIF;
|
use App\Classes\LDAP\Export\LDIF;
|
||||||
@ -39,9 +42,19 @@ class Entry extends Model
|
|||||||
public function __construct(array $attributes = [])
|
public function __construct(array $attributes = [])
|
||||||
{
|
{
|
||||||
$this->objects = collect();
|
$this->objects = collect();
|
||||||
$this->templates = collect(['default'=>__('LDAP Entry')]);
|
|
||||||
|
|
||||||
parent::__construct($attributes);
|
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
|
public function discardChanges(): static
|
||||||
@ -131,6 +144,13 @@ class Entry extends Model
|
|||||||
$this->objects = collect();
|
$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;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -531,4 +551,9 @@ class Entry extends Model
|
|||||||
|
|
||||||
$this->rdnbase = $bdn;
|
$this->rdnbase = $bdn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function template(string $item): Template|Null
|
||||||
|
{
|
||||||
|
return Arr::get($this->templates,$item);
|
||||||
|
}
|
||||||
}
|
}
|
10
config/filesystems.php
Normal file
10
config/filesystems.php
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
'disks' => [
|
||||||
|
'templates' => [
|
||||||
|
'driver' => 'local',
|
||||||
|
'root' => base_path(env('LDAP_TEMPLATE_DIR','templates')),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
@ -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
|
'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
|
'objectclass' => explode(',',env('LDAP_LOGIN_OBJECTCLASS', 'posixAccount')), // Objectclass that users must contain to login
|
||||||
],
|
],
|
||||||
|
|
||||||
|
'template' => [
|
||||||
|
'dir' => env('LDAP_TEMPLATE_DRIVER','templates'),
|
||||||
|
],
|
||||||
];
|
];
|
17
resources/views/fragment/template/dn.blade.php
Normal file
17
resources/views/fragment/template/dn.blade.php
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<!-- $template=Template -->
|
||||||
|
<form id="template-edit" method="POST" class="needs-validation" action="{{ url('entry/update/pending') }}" novalidate readonly>
|
||||||
|
@csrf
|
||||||
|
|
||||||
|
<input type="hidden" name="dn" value="">
|
||||||
|
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="tab-content">
|
||||||
|
@php($up=(session()->pull('updated') ?: collect()))
|
||||||
|
@php($attributes=$o->template($template)?->attributes)
|
||||||
|
|
||||||
|
@foreach($o->getVisibleAttributes()->filter(fn($item)=>in_array($item,$attributes)) as $ao)
|
||||||
|
<x-attribute-type :o="$ao" :edit="TRUE" :new="FALSE" :updated="$up->contains($ao->name_lc)"/>
|
||||||
|
@endforeach
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
@ -74,53 +74,49 @@
|
|||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<div class="d-flex justify-content-center">
|
<div class="d-flex justify-content-center">
|
||||||
<div role="group" class="btn-group btn-group-sm nav pb-3">
|
<div role="group" class="btn-group btn-group-sm nav pb-3">
|
||||||
<!-- It is assumed that the entry has atleast 1 template "default" -->
|
<!-- If we have templates that cover this entry -->
|
||||||
@if($o->templates->count() > 1)
|
@foreach($o->templates as $template => $name)
|
||||||
@foreach($o->templates as $template => $name)
|
<span data-bs-toggle="tab" href="#template-{{$template}}" @class(['btn','btn-outline-focus','active'=>$loop->index === 0])><i class="fa fa-fw pe-2 {{ $o->template($template)->icon }}"></i> {{ $name }}</span>
|
||||||
<span data-bs-toggle="tab" href="#template-{{$template}}" @class(['btn','btn-outline-focus','active'=>$loop->index === 0])>{{ $name }}</span>
|
@endforeach
|
||||||
@endforeach
|
@if($o->templates->count())
|
||||||
|
<span data-bs-toggle="tab" href="#template-default" @class(['btn','btn-outline-focus','p-1','active'=>(! $o->templates->count())])>{{ __('LDAP Entry') }}</span>
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="tab-content">
|
<div class="tab-content">
|
||||||
@foreach($o->templates as $template => $name)
|
@foreach($o->templates as $template => $name)
|
||||||
@switch($template)
|
<div @class(['tab-pane','active'=>$loop->index === 0]) id="template-{{$template}}" role="tabpanel">
|
||||||
@case('default')
|
@include('fragment.template.dn',['template'=>$template])
|
||||||
<div @class(['tab-pane','active'=>$loop->index === 0]) id="template-{{$template}}" role="tabpanel">
|
</div>
|
||||||
<form id="dn-edit" method="POST" class="needs-validation" action="{{ url('entry/update/pending') }}" novalidate readonly>
|
|
||||||
@csrf
|
|
||||||
|
|
||||||
<input type="hidden" name="dn" value="">
|
|
||||||
|
|
||||||
<div class="card-body">
|
|
||||||
<div class="tab-content">
|
|
||||||
@php($up=(session()->pull('updated') ?: collect()))
|
|
||||||
@foreach($o->getVisibleAttributes() as $ao)
|
|
||||||
<x-attribute-type :o="$ao" :edit="TRUE" :new="FALSE" :updated="$up->contains($ao->name_lc)"/>
|
|
||||||
@endforeach
|
|
||||||
|
|
||||||
@include('fragment.dn.add_attr')
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
@break
|
|
||||||
|
|
||||||
@default
|
|
||||||
<div @class(['tab-pane','active'=>$loop->index === 0]) id="template-{{$template}}" role="tabpanel">
|
|
||||||
<p>{{$name}}</p>
|
|
||||||
</div>
|
|
||||||
@endswitch
|
|
||||||
@endforeach
|
@endforeach
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row d-none pt-3">
|
<div @class(['tab-pane','active'=>(! $o->templates->count())]) id="template-default" role="tabpanel">
|
||||||
<div class="col-12 offset-sm-2 col-sm-4 col-lg-2">
|
<form id="dn-edit" method="POST" class="needs-validation" action="{{ url('entry/update/pending') }}" novalidate readonly>
|
||||||
<x-form.reset form="dn-edit"/>
|
@csrf
|
||||||
<x-form.submit :action="__('Update')" form="dn-edit"/>
|
|
||||||
|
<input type="hidden" name="dn" value="">
|
||||||
|
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="tab-content">
|
||||||
|
@php($up=(session()->pull('updated') ?: collect()))
|
||||||
|
@foreach($o->getVisibleAttributes() as $ao)
|
||||||
|
<x-attribute-type :o="$ao" :edit="TRUE" :new="FALSE" :updated="$up->contains($ao->name_lc)"/>
|
||||||
|
@endforeach
|
||||||
|
|
||||||
|
@include('fragment.dn.add_attr')
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<div class="row d-none pt-3">
|
||||||
|
<div class="col-11 text-end">
|
||||||
|
<x-form.reset form="dn-edit"/>
|
||||||
|
<x-form.submit :action="__('Update')" form="dn-edit"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -162,7 +158,6 @@
|
|||||||
|
|
||||||
// Find all input items and turn off readonly
|
// Find all input items and turn off readonly
|
||||||
$('input.form-control').each(function() {
|
$('input.form-control').each(function() {
|
||||||
// Except for objectClass - @todo show an "X" instead
|
|
||||||
if ($(this)[0].name.match(/^objectclass/))
|
if ($(this)[0].name.match(/^objectclass/))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
22
templates/dns_domain.json
Normal file
22
templates/dns_domain.json
Normal file
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
25
templates/example.json
Normal file
25
templates/example.json
Normal file
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
20
templates/o.json
Normal file
20
templates/o.json
Normal file
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
25
templates/ou.json
Normal file
25
templates/ou.json
Normal file
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
82
templates/user_account.json
Normal file
82
templates/user_account.json
Normal file
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user