This commit is mainly as a result of creating DN entries and improves some backend functions:
* Enable creation of new entries, * Change all our ajax frames to go through /frames URI instead of /dn, * Add our frame command to the encrypted DN, * Automatically redirect to root URL when selecting a tree item and currently in another path (as a result of a prior POST activity), * Some validation improvements DNExists/HasStructuralObjectClass
This commit is contained in:
@@ -145,9 +145,9 @@ class Attribute implements \Countable, \ArrayAccess, \Iterator
|
||||
// Attribute values
|
||||
'values' => $this->values,
|
||||
// Required by Object Classes
|
||||
'required_by' => $this->schema->required_by_object_classes,
|
||||
'required_by' => $this->schema?->required_by_object_classes ?: collect(),
|
||||
// Used in Object Classes
|
||||
'used_in' => $this->schema->used_in_object_classes,
|
||||
'used_in' => $this->schema?->used_in_object_classes ?: collect(),
|
||||
|
||||
default => throw new \Exception('Unknown key:' . $key),
|
||||
};
|
||||
|
49
app/Classes/LDAP/Attribute/RDN.php
Normal file
49
app/Classes/LDAP/Attribute/RDN.php
Normal file
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace App\Classes\LDAP\Attribute;
|
||||
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
use App\Classes\LDAP\Attribute;
|
||||
|
||||
/**
|
||||
* Represents the RDN for an Entry
|
||||
*/
|
||||
final class RDN extends Attribute
|
||||
{
|
||||
private string $base;
|
||||
private Collection $attrs;
|
||||
|
||||
public function __get(string $key): mixed
|
||||
{
|
||||
return match ($key) {
|
||||
'base' => $this->base,
|
||||
'attrs' => $this->attrs->pluck('name'),
|
||||
default => parent::__get($key),
|
||||
};
|
||||
}
|
||||
|
||||
public function hints(): array
|
||||
{
|
||||
return [
|
||||
'required' => __('RDN is required')
|
||||
];
|
||||
}
|
||||
|
||||
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE): View
|
||||
{
|
||||
return view('components.attribute.rdn')
|
||||
->with('o',$this);
|
||||
}
|
||||
|
||||
public function setAttributes(Collection $attrs): void
|
||||
{
|
||||
$this->attrs = $attrs;
|
||||
}
|
||||
|
||||
public function setBase(string $base): void
|
||||
{
|
||||
$this->base = $base;
|
||||
}
|
||||
}
|
@@ -208,7 +208,7 @@ final class ObjectClass extends Base
|
||||
public function __get(string $key): mixed
|
||||
{
|
||||
return match ($key) {
|
||||
'attributes' => $this->getAllAttrs(),
|
||||
'attributes' => $this->getAllAttrs(TRUE),
|
||||
'sup' => $this->sup_classes,
|
||||
'type_name' => match ($this->type) {
|
||||
Server::OC_STRUCTURAL => 'Structural',
|
||||
@@ -223,13 +223,18 @@ final class ObjectClass extends Base
|
||||
/**
|
||||
* Return a list of attributes that this objectClass provides
|
||||
*
|
||||
* @param bool $parents
|
||||
* @return Collection
|
||||
* @throws InvalidUsage
|
||||
*/
|
||||
public function getAllAttrs(): Collection
|
||||
public function getAllAttrs(bool $parents=FALSE): Collection
|
||||
{
|
||||
return $this->getMustAttrs()
|
||||
->merge($this->getMayAttrs());
|
||||
return $this->getMustAttrs($parents)
|
||||
->transform(function($item) {
|
||||
$item->required = true;
|
||||
return $item;
|
||||
})
|
||||
->merge($this->getMayAttrs($parents));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -16,6 +16,7 @@ namespace App\Classes\LDAP\Schema;
|
||||
final class ObjectClassAttribute extends Base {
|
||||
// This Attribute's root.
|
||||
private string $source;
|
||||
public bool $required = FALSE;
|
||||
|
||||
/**
|
||||
* Creates a new ObjectClassAttribute with specified name and source objectClass.
|
||||
@@ -31,11 +32,9 @@ final class ObjectClassAttribute extends Base {
|
||||
|
||||
public function __get(string $key): mixed
|
||||
{
|
||||
switch ($key) {
|
||||
case 'source':
|
||||
return $this->source;
|
||||
|
||||
default: return parent::__get($key);
|
||||
}
|
||||
return match ($key) {
|
||||
'source' => $this->source,
|
||||
default => parent::__get($key),
|
||||
};
|
||||
}
|
||||
}
|
@@ -16,21 +16,21 @@ class APIController extends Controller
|
||||
* Get the LDAP server BASE DNs
|
||||
*
|
||||
* @return Collection
|
||||
* @throws LdapRecord\Query\ObjectNotFoundException
|
||||
* @throws \LdapRecord\Query\ObjectNotFoundException
|
||||
*/
|
||||
public function bases(): Collection
|
||||
{
|
||||
$base = Server::baseDNs() ?: collect();
|
||||
|
||||
return $base->transform(function($item) {
|
||||
return [
|
||||
'title'=>$item->getRdn(),
|
||||
'item'=>$item->getDNSecure(),
|
||||
'lazy'=>TRUE,
|
||||
'icon'=>'fa-fw fas fa-sitemap',
|
||||
'tooltip'=>$item->getDn(),
|
||||
];
|
||||
});
|
||||
return $base
|
||||
->transform(fn($item)=>
|
||||
[
|
||||
'title'=>$item->getRdn(),
|
||||
'item'=>$item->getDNSecure(),
|
||||
'lazy'=>TRUE,
|
||||
'icon'=>'fa-fw fas fa-sitemap',
|
||||
'tooltip'=>$item->getDn(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -41,19 +41,31 @@ class APIController extends Controller
|
||||
{
|
||||
$levels = $request->query('depth',1);
|
||||
$dn = Crypt::decryptString($request->query('key'));
|
||||
|
||||
// Sometimes our key has a command, so we'll ignore it
|
||||
if (str_starts_with($dn,'*') && ($x=strpos($dn,'|')))
|
||||
$dn = substr($dn,$x+1);
|
||||
|
||||
Log::debug(sprintf('%s: Query [%s] - Levels [%d]',__METHOD__,$dn,$levels));
|
||||
|
||||
return (config('server'))
|
||||
->children($dn)
|
||||
->transform(function($item) {
|
||||
return [
|
||||
->transform(fn($item)=>
|
||||
[
|
||||
'title'=>$item->getRdn(),
|
||||
'item'=>$item->getDNSecure(),
|
||||
'icon'=>$item->icon(),
|
||||
'lazy'=>Arr::get($item->getAttribute('hassubordinates'),0) == 'TRUE',
|
||||
'tooltip'=>$item->getDn(),
|
||||
];
|
||||
});
|
||||
])
|
||||
->prepend(
|
||||
[
|
||||
'title'=>sprintf('[%s]',__('Create Entry')),
|
||||
'item'=>Crypt::encryptString(sprintf('*%s|%s','create',$dn)),
|
||||
'lazy'=>FALSE,
|
||||
'icon'=>'fas fa-fw fa-square-plus text-warning',
|
||||
'tooltip'=>__('Create new LDAP item here'),
|
||||
]);
|
||||
}
|
||||
|
||||
public function schema_view(Request $request)
|
||||
@@ -63,20 +75,20 @@ class APIController extends Controller
|
||||
switch($request->type) {
|
||||
case 'objectclasses':
|
||||
return view('fragment.schema.objectclasses')
|
||||
->with('objectclasses',$server->schema('objectclasses')->sortBy(function($item) { return strtolower($item->name); }));
|
||||
->with('objectclasses',$server->schema('objectclasses')->sortBy(fn($item)=>strtolower($item->name)));
|
||||
|
||||
case 'attributetypes':
|
||||
return view('fragment.schema.attributetypes')
|
||||
->with('server',$server)
|
||||
->with('attributetypes',$server->schema('attributetypes')->sortBy(function($item) { return strtolower($item->name); }));
|
||||
->with('attributetypes',$server->schema('attributetypes')->sortBy(fn($item)=>strtolower($item->name)));
|
||||
|
||||
case 'ldapsyntaxes':
|
||||
return view('fragment.schema.ldapsyntaxes')
|
||||
->with('ldapsyntaxes',$server->schema('ldapsyntaxes')->sortBy(function($item) { return strtolower($item->description); }));
|
||||
->with('ldapsyntaxes',$server->schema('ldapsyntaxes')->sortBy(fn($item)=>strtolower($item->description)));
|
||||
|
||||
case 'matchingrules':
|
||||
return view('fragment.schema.matchingrules')
|
||||
->with('matchingrules',$server->schema('matchingrules')->sortBy(function($item) { return strtolower($item->name); }));
|
||||
->with('matchingrules',$server->schema('matchingrules')->sortBy(fn($item)=>strtolower($item->name)));
|
||||
|
||||
default:
|
||||
abort(404);
|
||||
|
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Collection;
|
||||
@@ -12,20 +13,21 @@ use Illuminate\Support\Facades\Redirect;
|
||||
use LdapRecord\Exceptions\InsufficientAccessException;
|
||||
use LdapRecord\LdapRecordException;
|
||||
use LdapRecord\Query\ObjectNotFoundException;
|
||||
use Nette\NotImplementedException;
|
||||
|
||||
use App\Classes\LDAP\Attribute\Factory;
|
||||
use App\Classes\LDAP\{Attribute,Server};
|
||||
use App\Classes\LDAP\Import\LDIF as LDIFImport;
|
||||
use App\Classes\LDAP\Export\LDIF as LDIFExport;
|
||||
use App\Exceptions\Import\{GeneralException,VersionException};
|
||||
use App\Exceptions\InvalidUsage;
|
||||
use App\Http\Requests\{EntryRequest,ImportRequest};
|
||||
use App\Http\Requests\{EntryRequest,EntryAddRequest,ImportRequest};
|
||||
use App\Ldap\Entry;
|
||||
use App\View\Components\AttributeType;
|
||||
use Nette\NotImplementedException;
|
||||
|
||||
class HomeController extends Controller
|
||||
{
|
||||
private function bases()
|
||||
private function bases(): Collection
|
||||
{
|
||||
$base = Server::baseDNs() ?: collect();
|
||||
|
||||
@@ -51,21 +53,38 @@ class HomeController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a specific DN
|
||||
* Create a new object in the LDAP server
|
||||
*
|
||||
* @param Request $request
|
||||
* @param EntryAddRequest $request
|
||||
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
|
||||
* @throws InvalidUsage
|
||||
*/
|
||||
public function dn_frame(Request $request)
|
||||
public function entry_add(EntryAddRequest $request)
|
||||
{
|
||||
$dn = Crypt::decryptString($request->post('key'));
|
||||
if (! old('step',$request->validated('step')))
|
||||
abort(404);
|
||||
|
||||
$page_actions = collect(['edit'=>TRUE,'copy'=>TRUE]);
|
||||
$key = $this->request_key($request,collect(old()));
|
||||
|
||||
return view('frames.dn')
|
||||
->with('o',config('server')->fetch($dn))
|
||||
->with('dn',$dn)
|
||||
->with('page_actions',$page_actions);
|
||||
$o = new Entry;
|
||||
|
||||
if (count(array_filter($x=old('objectclass',$request->objectclass)))) {
|
||||
$o->objectclass = $x;
|
||||
|
||||
foreach($o->getAvailableAttributes()->filter(fn($item)=>$item->required) as $ao)
|
||||
$o->addAttribute($ao,'');
|
||||
|
||||
$o->setRDNBase($key['dn']);
|
||||
}
|
||||
|
||||
$step = $request->step ? $request->step+1 : old('step');
|
||||
|
||||
return view('frame')
|
||||
->with('subframe','create')
|
||||
->with('bases',$this->bases())
|
||||
->with('o',$o)
|
||||
->with('step',$step)
|
||||
->with('container',old('container',$key['dn']));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -75,7 +94,7 @@ class HomeController extends Controller
|
||||
* @param string $id
|
||||
* @return \Closure|\Illuminate\Contracts\View\View|string
|
||||
*/
|
||||
public function entry_attr_add(Request $request,string $id)
|
||||
public function entry_attr_add(Request $request,string $id): string
|
||||
{
|
||||
$xx = new \stdClass();
|
||||
$xx->index = 0;
|
||||
@@ -90,6 +109,53 @@ class HomeController extends Controller
|
||||
return $x;
|
||||
}
|
||||
|
||||
public function entry_create(EntryAddRequest $request)
|
||||
{
|
||||
$key = $this->request_key($request,collect(old()));
|
||||
|
||||
$dn = sprintf('%s=%s,%s',$request->rdn,$request->rdn_value,$key['dn']);
|
||||
|
||||
$o = new Entry;
|
||||
$o->setDn($dn);
|
||||
|
||||
foreach ($request->except(['_token','key','step','rdn','rdn_value']) as $key => $value)
|
||||
$o->{$key} = array_filter($value);
|
||||
|
||||
try {
|
||||
$o->save();
|
||||
|
||||
} catch (InsufficientAccessException $e) {
|
||||
$request->flash();
|
||||
|
||||
switch ($x=$e->getDetailedError()->getErrorCode()) {
|
||||
case 50:
|
||||
return Redirect::to('/')
|
||||
->withInput()
|
||||
->withErrors(sprintf('%s: %s (%s)',__('LDAP Server Error Code'),$x,__($e->getDetailedError()->getErrorMessage())));
|
||||
|
||||
default:
|
||||
abort(599,$e->getDetailedError()->getErrorMessage());
|
||||
}
|
||||
|
||||
// @todo To test and valide this Exception is caught
|
||||
} catch (LdapRecordException $e) {
|
||||
$request->flash();
|
||||
|
||||
switch ($x=$e->getDetailedError()->getErrorCode()) {
|
||||
case 8:
|
||||
return Redirect::to('/')
|
||||
->withInput()
|
||||
->withErrors(sprintf('%s: %s (%s)',__('LDAP Server Error Code'),$x,__($e->getDetailedError()->getErrorMessage())));
|
||||
|
||||
default:
|
||||
abort(599,$e->getDetailedError()->getErrorMessage());
|
||||
}
|
||||
}
|
||||
|
||||
return Redirect::to('/')
|
||||
->withFragment($o->getDNSecure());
|
||||
}
|
||||
|
||||
public function entry_export(Request $request,string $id)
|
||||
{
|
||||
$dn = Crypt::decryptString($id);
|
||||
@@ -112,11 +178,9 @@ class HomeController extends Controller
|
||||
* @param string $id
|
||||
* @return mixed
|
||||
*/
|
||||
public function entry_objectclass_add(string $id)
|
||||
public function entry_objectclass_add(Request $request)
|
||||
{
|
||||
$dn = Crypt::decryptString($id);
|
||||
$o = config('server')->fetch($dn);
|
||||
$oc = $o->getObject('objectclass');
|
||||
$oc = Factory::create('objectclass',$request->oc);
|
||||
|
||||
$ocs = $oc
|
||||
->structural
|
||||
@@ -259,26 +323,51 @@ class HomeController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Application home page
|
||||
* Render a frame, normally as a result of an AJAX call
|
||||
* This will render the right frame.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Collection|null $old
|
||||
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|View
|
||||
*/
|
||||
public function home()
|
||||
public function frame(Request $request,?Collection $old=NULL): View
|
||||
{
|
||||
if (old('dn'))
|
||||
return view('frame')
|
||||
->with('subframe','dn')
|
||||
->with('bases',$this->bases())
|
||||
->with('o',config('server')->fetch($dn=Crypt::decryptString(old('dn'))))
|
||||
->with('dn',$dn);
|
||||
// If our index was not render from a root url, then redirect to it
|
||||
if (($request->root().'/' !== url()->previous()) && $request->method() === 'POST')
|
||||
abort(409);
|
||||
|
||||
elseif (old('frame'))
|
||||
return view('frame')
|
||||
->with('subframe',old('frame'))
|
||||
$key = $this->request_key($request,$old);
|
||||
|
||||
$view = ($old
|
||||
? view('frame')->with('subframe',$key['cmd'])
|
||||
: view('frames.'.$key['cmd']))
|
||||
->with('bases',$this->bases());
|
||||
|
||||
return match ($key['cmd']) {
|
||||
'create' => $view
|
||||
->with('container',old('container',$key['dn']))
|
||||
->with('step',1),
|
||||
|
||||
'dn' => $view
|
||||
->with('dn',$key['dn'])
|
||||
->with('page_actions',collect(['edit'=>TRUE,'copy'=>TRUE])),
|
||||
|
||||
'import' => $view,
|
||||
|
||||
default => abort(404),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the main page render function
|
||||
*/
|
||||
public function home(Request $request)
|
||||
{
|
||||
// Did we come here as a result of a redirect
|
||||
return count(old())
|
||||
? $this->frame($request,collect(old()))
|
||||
: view('home')
|
||||
->with('bases',$this->bases());
|
||||
|
||||
else
|
||||
return view('home')
|
||||
->with('bases',$this->bases())
|
||||
->with('server',config('ldap.connections.default.name'));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -334,6 +423,39 @@ class HomeController extends Controller
|
||||
->with('s',config('server'));
|
||||
}
|
||||
|
||||
/**
|
||||
* For any incoming request, work out the command and DN involved
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Collection|null $old
|
||||
* @return array
|
||||
*/
|
||||
private function request_key(Request $request,?Collection $old=NULL): array
|
||||
{
|
||||
// Setup
|
||||
$cmd = NULL;
|
||||
$dn = NULL;
|
||||
$key = $request->get('key',old('key'))
|
||||
? Crypt::decryptString($request->get('key',old('key')))
|
||||
: NULL;
|
||||
|
||||
// Determine if our key has a command
|
||||
if (str_contains($key,'|')) {
|
||||
$m = [];
|
||||
|
||||
if (preg_match('/\*([a-z_]+)\|(.+)$/',$key,$m)) {
|
||||
$cmd = $m[1];
|
||||
$dn = ($m[2] !== '_NOP') ? $m[2] : NULL;
|
||||
}
|
||||
|
||||
} elseif (old('dn',$request->get('key'))) {
|
||||
$cmd = 'dn';
|
||||
$dn = Crypt::decryptString(old('dn',$request->get('key')));
|
||||
}
|
||||
|
||||
return ['cmd'=>$cmd,'dn'=>$dn];
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the Schema Viewer
|
||||
*
|
||||
|
71
app/Http/Requests/EntryAddRequest.php
Normal file
71
app/Http/Requests/EntryAddRequest.php
Normal file
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
|
||||
use App\Rules\{DNExists,HasStructuralObjectClass};
|
||||
|
||||
class EntryAddRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Get the error messages for the defined validation rules.
|
||||
*
|
||||
* @return array<string, string>
|
||||
*/
|
||||
public function messages(): array
|
||||
{
|
||||
return [
|
||||
'rdn' => __('RDN is required.'),
|
||||
'rdn_value' => __('RDN value is required.'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
* @throws \Psr\Container\ContainerExceptionInterface
|
||||
* @throws \Psr\Container\NotFoundExceptionInterface
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
if (request()->method() === 'GET')
|
||||
return [];
|
||||
|
||||
return config('server')
|
||||
->schema('attributetypes')
|
||||
->intersectByKeys($this->request)
|
||||
->map(fn($item)=>$item->validation(request()->get('objectclass')))
|
||||
->filter()
|
||||
->flatMap(fn($item)=>$item)
|
||||
->merge([
|
||||
'key' => [
|
||||
'required',
|
||||
new DNExists,
|
||||
function (string $attribute,mixed $value,\Closure $fail) {
|
||||
$cmd = Crypt::decryptString($value);
|
||||
|
||||
// Sometimes our key has a command, so we'll ignore it
|
||||
if (str_starts_with($cmd,'*') && ($x=strpos($cmd,'|')))
|
||||
$cmd = substr($cmd,1,$x-1);
|
||||
|
||||
if ($cmd !== 'create') {
|
||||
$fail(sprintf('Invalid command: %s',$cmd));
|
||||
}
|
||||
},
|
||||
],
|
||||
'rdn' => 'required_if:step,2|string|min:1',
|
||||
'rdn_value' => 'required_if:step,2|string|min:1',
|
||||
'step' => 'int|min:1|max:2',
|
||||
'objectclass'=>[
|
||||
'required',
|
||||
'array',
|
||||
'min:1',
|
||||
new HasStructuralObjectClass,
|
||||
]
|
||||
])
|
||||
->toArray();
|
||||
}
|
||||
}
|
@@ -6,27 +6,17 @@ use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class EntryRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function rules()
|
||||
public function rules(): array
|
||||
{
|
||||
return config('server')
|
||||
->schema('attributetypes')
|
||||
->intersectByKeys($this->request)
|
||||
->map(fn($item)=>$item->validation(request()->get('objectclass')))
|
||||
->map(fn($item)=>$item->validation(request()?->get('objectclass') ?: []))
|
||||
->filter()
|
||||
->flatMap(fn($item)=>$item)
|
||||
->toArray();
|
||||
|
@@ -6,15 +6,9 @@ use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class ImportRequest extends FormRequest
|
||||
{
|
||||
public function authorize()
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
public function rules()
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'frame' => 'required|string|in:import',
|
||||
'file' => 'nullable|extensions:ldif|required_without:text',
|
||||
'text'=> 'nullable|prohibits:file|string|min:16',
|
||||
];
|
||||
|
@@ -12,11 +12,14 @@ use App\Classes\LDAP\Attribute;
|
||||
use App\Classes\LDAP\Attribute\Factory;
|
||||
use App\Classes\LDAP\Export\LDIF;
|
||||
use App\Exceptions\Import\AttributeException;
|
||||
use App\Exceptions\InvalidUsage;
|
||||
|
||||
class Entry extends Model
|
||||
{
|
||||
private Collection $objects;
|
||||
private bool $noObjectAttributes = FALSE;
|
||||
// For new entries, this is the container that this entry will be stored in
|
||||
private string $rdnbase;
|
||||
|
||||
/* OVERRIDES */
|
||||
|
||||
@@ -46,7 +49,7 @@ class Entry extends Model
|
||||
public function getAttributes(): array
|
||||
{
|
||||
return $this->objects
|
||||
->map(fn($item)=>$item->values->toArray())
|
||||
->map(fn($item)=>$item->values)
|
||||
->toArray();
|
||||
}
|
||||
|
||||
@@ -92,10 +95,7 @@ class Entry extends Model
|
||||
$key = $this->normalizeAttributeKey($key);
|
||||
|
||||
if ((! $this->objects->get($key)) && $value) {
|
||||
$o = new Attribute($key,[]);
|
||||
$o->value = $value;
|
||||
|
||||
$this->objects->put($key,$o);
|
||||
$this->objects->put($key,Factory::create($key,$value));
|
||||
|
||||
} elseif ($this->objects->get($key)) {
|
||||
$this->objects->get($key)->value = $this->attributes[$key];
|
||||
@@ -265,8 +265,12 @@ class Entry extends Model
|
||||
*/
|
||||
public function getObject(string $key): Attribute|null
|
||||
{
|
||||
return $this->objects
|
||||
->get($this->normalizeAttributeKey($key));
|
||||
return match ($key) {
|
||||
'rdn' => $this->getRDNObject(),
|
||||
|
||||
default => $this->objects
|
||||
->get($this->normalizeAttributeKey($key))
|
||||
};
|
||||
}
|
||||
|
||||
public function getObjects(): Collection
|
||||
@@ -289,6 +293,16 @@ class Entry extends Model
|
||||
->filter(fn($a)=>(! $this->getVisibleAttributes()->contains(fn($b)=>($a->name === $b->name))));
|
||||
}
|
||||
|
||||
private function getRDNObject(): Attribute\RDN
|
||||
{
|
||||
$o = new Attribute\RDN('dn',['']);
|
||||
// @todo for an existing object, return the base.
|
||||
$o->setBase($this->rdnbase);
|
||||
$o->setAttributes($this->getAvailableAttributes()->filter(fn($item)=>$item->required));
|
||||
|
||||
return $o;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return this list of user attributes
|
||||
*
|
||||
@@ -413,4 +427,12 @@ class Entry extends Model
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setRDNBase(string $bdn): void
|
||||
{
|
||||
if ($this->exists)
|
||||
throw new InvalidUsage('Cannot set RDN base on existing entries');
|
||||
|
||||
$this->rdnbase = $bdn;
|
||||
}
|
||||
}
|
27
app/Rules/DNExists.php
Normal file
27
app/Rules/DNExists.php
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace App\Rules;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Contracts\Validation\ValidationRule;
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
|
||||
class DNExists implements ValidationRule
|
||||
{
|
||||
/**
|
||||
* Run the validation rule.
|
||||
*
|
||||
* @param \Closure(string, ?string=): \Illuminate\Translation\PotentiallyTranslatedString $fail
|
||||
*/
|
||||
public function validate(string $attribute,mixed $value,Closure $fail): void
|
||||
{
|
||||
$dn = Crypt::decryptString($value);
|
||||
|
||||
// Sometimes our key has a command, so we'll ignore it
|
||||
if (str_starts_with($dn,'*') && ($x=strpos($dn,'|')))
|
||||
$dn = substr($dn,$x+1);
|
||||
|
||||
if (! config('server')->fetch($dn))
|
||||
$fail(sprintf('The DN %s doesnt exist.',$dn));
|
||||
}
|
||||
}
|
23
app/Rules/HasStructuralObjectClass.php
Normal file
23
app/Rules/HasStructuralObjectClass.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace App\Rules;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Contracts\Validation\ValidationRule;
|
||||
|
||||
class HasStructuralObjectClass implements ValidationRule
|
||||
{
|
||||
/**
|
||||
* Run the validation rule.
|
||||
*
|
||||
* @param \Closure(string, ?string=): \Illuminate\Translation\PotentiallyTranslatedString $fail
|
||||
*/
|
||||
public function validate(string $attribute,mixed $value,Closure $fail): void
|
||||
{
|
||||
foreach ($value as $item)
|
||||
if ($item && config('server')->schema('objectclasses',$item)->isStructural())
|
||||
return;
|
||||
|
||||
$fail('There isnt a Structural Objectclass.');
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user