Compare commits
5 Commits
e4d2304696
...
dd759b23d9
Author | SHA1 | Date | |
---|---|---|---|
dd759b23d9 | |||
bcea6de791 | |||
28f4869628 | |||
cf535286c5 | |||
633513d3e9 |
@ -7,11 +7,12 @@ use Illuminate\Support\Arr;
|
|||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
use App\Classes\LDAP\Schema\AttributeType;
|
use App\Classes\LDAP\Schema\AttributeType;
|
||||||
|
use App\Ldap\Entry;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents an attribute of an LDAP Object
|
* Represents an attribute of an LDAP Object
|
||||||
*/
|
*/
|
||||||
class Attribute implements \Countable, \ArrayAccess, \Iterator
|
class Attribute implements \Countable, \ArrayAccess
|
||||||
{
|
{
|
||||||
// Attribute Name
|
// Attribute Name
|
||||||
protected string $name;
|
protected string $name;
|
||||||
@ -100,9 +101,9 @@ class Attribute implements \Countable, \ArrayAccess, \Iterator
|
|||||||
{
|
{
|
||||||
$this->dn = $dn;
|
$this->dn = $dn;
|
||||||
$this->name = $name;
|
$this->name = $name;
|
||||||
$this->values_old = collect($values);
|
$this->_values = collect($values);
|
||||||
|
$this->_values_old = collect($values);
|
||||||
|
|
||||||
$this->values = collect();
|
|
||||||
$this->oc = collect($oc);
|
$this->oc = collect($oc);
|
||||||
|
|
||||||
$this->schema = (new Server)
|
$this->schema = (new Server)
|
||||||
@ -149,15 +150,15 @@ class Attribute implements \Countable, \ArrayAccess, \Iterator
|
|||||||
// Used in Object Classes
|
// Used in Object Classes
|
||||||
'used_in' => $this->schema?->used_in_object_classes ?: collect(),
|
'used_in' => $this->schema?->used_in_object_classes ?: collect(),
|
||||||
// The current attribute values
|
// The current attribute values
|
||||||
'values' => $this->no_attr_tags ? collect($this->_values->first()) : $this->_values,
|
'values' => $this->no_attr_tags ? $this->tagValues() : $this->_values,
|
||||||
// The original attribute values
|
// The original attribute values
|
||||||
'values_old' => $this->no_attr_tags ? collect($this->_values_old->first()) : $this->_values_old,
|
'values_old' => $this->no_attr_tags ? $this->tagValuesOld() : $this->_values_old,
|
||||||
|
|
||||||
default => throw new \Exception('Unknown key:' . $key),
|
default => throw new \Exception('Unknown key:' . $key),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __set(string $key,mixed $values)
|
public function __set(string $key,mixed $values): void
|
||||||
{
|
{
|
||||||
switch ($key) {
|
switch ($key) {
|
||||||
case 'values':
|
case 'values':
|
||||||
@ -178,53 +179,21 @@ class Attribute implements \Countable, \ArrayAccess, \Iterator
|
|||||||
return $this->name;
|
return $this->name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function addValue(string $tag,string $value): void
|
/* INTERFACE */
|
||||||
{
|
|
||||||
$this->_values->put(
|
|
||||||
$tag,
|
|
||||||
$this->_values
|
|
||||||
->get($tag,collect())
|
|
||||||
->push($value));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function current(): mixed
|
|
||||||
{
|
|
||||||
return $this->values->get($this->counter);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function next(): void
|
|
||||||
{
|
|
||||||
$this->counter++;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function key(): mixed
|
|
||||||
{
|
|
||||||
return $this->counter;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function valid(): bool
|
|
||||||
{
|
|
||||||
return $this->values->has($this->counter);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function rewind(): void
|
|
||||||
{
|
|
||||||
$this->counter = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function count(): int
|
public function count(): int
|
||||||
{
|
{
|
||||||
return $this->values->count();
|
return $this->_values->dot()->count();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function offsetExists(mixed $offset): bool
|
public function offsetExists(mixed $offset): bool
|
||||||
{
|
{
|
||||||
return ! is_null($this->values->has($offset));
|
return $this->_values->dot()->has($offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function offsetGet(mixed $offset): mixed
|
public function offsetGet(mixed $offset): mixed
|
||||||
{
|
{
|
||||||
return $this->values->get($offset);
|
return $this->_values->dot()->get($offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function offsetSet(mixed $offset, mixed $value): void
|
public function offsetSet(mixed $offset, mixed $value): void
|
||||||
@ -237,6 +206,24 @@ class Attribute implements \Countable, \ArrayAccess, \Iterator
|
|||||||
// We cannot clear values using array syntax
|
// We cannot clear values using array syntax
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* METHODS */
|
||||||
|
|
||||||
|
public function addValue(string $tag,array $values): void
|
||||||
|
{
|
||||||
|
$this->_values->put(
|
||||||
|
$tag,
|
||||||
|
array_unique(array_merge($this->_values
|
||||||
|
->get($tag,[]),$values)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addValueOld(string $tag,array $values): void
|
||||||
|
{
|
||||||
|
$this->_values_old->put(
|
||||||
|
$tag,
|
||||||
|
array_unique(array_merge($this->_values_old
|
||||||
|
->get($tag,[]),$values)));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the hints about this attribute, ie: RDN, Required, etc
|
* Return the hints about this attribute, ie: RDN, Required, etc
|
||||||
*
|
*
|
||||||
@ -266,8 +253,10 @@ class Attribute implements \Countable, \ArrayAccess, \Iterator
|
|||||||
*/
|
*/
|
||||||
public function isDirty(): bool
|
public function isDirty(): bool
|
||||||
{
|
{
|
||||||
return ($this->values_old->count() !== $this->values->count())
|
return (($a=$this->values_old->dot())->keys()->count() !== ($b=$this->values->dot())->keys()->count())
|
||||||
|| ($this->values->diff($this->values_old)->count() !== 0);
|
|| ($a->values()->count() !== $b->values()->count())
|
||||||
|
|| ($a->keys()->diff($b->keys())->count() !== 0)
|
||||||
|
|| ($a->values()->diff($b->values())->count() !== 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -307,14 +296,14 @@ class Attribute implements \Countable, \ArrayAccess, \Iterator
|
|||||||
->with('new',$new);
|
->with('new',$new);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function render_item_old(int $key): ?string
|
public function render_item_old(string $dotkey): ?string
|
||||||
{
|
{
|
||||||
return Arr::get($this->values_old,$key);
|
return Arr::get($this->values_old->dot(),$dotkey);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function render_item_new(int $key): ?string
|
public function render_item_new(string $dotkey): ?string
|
||||||
{
|
{
|
||||||
return Arr::get($this->values,$key);
|
return Arr::get($this->values->dot(),$dotkey);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -329,4 +318,18 @@ class Attribute implements \Countable, \ArrayAccess, \Iterator
|
|||||||
? $this->oc->intersect($this->required_by->keys())->sort()
|
? $this->oc->intersect($this->required_by->keys())->sort()
|
||||||
: collect();
|
: collect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function tagValues(string $tag=Entry::TAG_NOTAG): Collection
|
||||||
|
{
|
||||||
|
return collect($this->_values
|
||||||
|
->filter(fn($item,$key)=>($key===$tag))
|
||||||
|
->get($tag,[]));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function tagValuesOld(string $tag=Entry::TAG_NOTAG): Collection
|
||||||
|
{
|
||||||
|
return collect($this->_values_old
|
||||||
|
->filter(fn($item,$key)=>($key===$tag))
|
||||||
|
->get($tag,[]));
|
||||||
|
}
|
||||||
}
|
}
|
@ -5,6 +5,7 @@ namespace App\Classes\LDAP\Attribute\Binary;
|
|||||||
use Illuminate\Contracts\View\View;
|
use Illuminate\Contracts\View\View;
|
||||||
|
|
||||||
use App\Classes\LDAP\Attribute\Binary;
|
use App\Classes\LDAP\Attribute\Binary;
|
||||||
|
use App\Ldap\Entry;
|
||||||
use App\Traits\MD5Updates;
|
use App\Traits\MD5Updates;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -14,13 +15,14 @@ final class JpegPhoto extends Binary
|
|||||||
{
|
{
|
||||||
use MD5Updates;
|
use MD5Updates;
|
||||||
|
|
||||||
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE): View
|
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,string $langtag=Entry::TAG_NOTAG): View
|
||||||
{
|
{
|
||||||
return view('components.attribute.binary.jpegphoto')
|
return view('components.attribute.binary.jpegphoto')
|
||||||
->with('o',$this)
|
->with('o',$this)
|
||||||
->with('edit',$edit)
|
->with('edit',$edit)
|
||||||
->with('old',$old)
|
->with('old',$old)
|
||||||
->with('new',$new)
|
->with('new',$new)
|
||||||
|
->with('langtag',$langtag)
|
||||||
->with('f',new \finfo);
|
->with('f',new \finfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -26,18 +26,16 @@ final class KrbPrincipalKey extends Attribute
|
|||||||
->with('new',$new);
|
->with('new',$new);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function render_item_old(int $key): ?string
|
public function render_item_old(string $dotkey): ?string
|
||||||
{
|
{
|
||||||
$pw = Arr::get($this->values_old,$key);
|
return parent::render_item_old($dotkey)
|
||||||
return $pw
|
|
||||||
? str_repeat('*',16)
|
? str_repeat('*',16)
|
||||||
: NULL;
|
: NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function render_item_new(int $key): ?string
|
public function render_item_new(string $dotkey): ?string
|
||||||
{
|
{
|
||||||
$pw = Arr::get($this->values,$key);
|
return parent::render_item_new($dotkey)
|
||||||
return $pw
|
|
||||||
? str_repeat('*',16)
|
? str_repeat('*',16)
|
||||||
: NULL;
|
: NULL;
|
||||||
}
|
}
|
||||||
|
@ -3,9 +3,9 @@
|
|||||||
namespace App\Classes\LDAP\Attribute;
|
namespace App\Classes\LDAP\Attribute;
|
||||||
|
|
||||||
use Illuminate\Contracts\View\View;
|
use Illuminate\Contracts\View\View;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
use App\Classes\LDAP\Attribute;
|
use App\Classes\LDAP\Attribute;
|
||||||
use Illuminate\Support\Collection;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents an attribute whose value is a Kerberos Ticket Flag
|
* Represents an attribute whose value is a Kerberos Ticket Flag
|
||||||
|
@ -29,19 +29,33 @@ final class ObjectClass extends Attribute
|
|||||||
{
|
{
|
||||||
parent::__construct($dn,$name,$values,['top']);
|
parent::__construct($dn,$name,$values,['top']);
|
||||||
|
|
||||||
$this->oc_schema = config('server')
|
$this->set_oc_schema($this->tagValuesOld());
|
||||||
->schema('objectclasses')
|
|
||||||
->filter(fn($item)=>$this->values_old->contains($item->name));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __get(string $key): mixed
|
public function __get(string $key): mixed
|
||||||
{
|
{
|
||||||
return match ($key) {
|
return match ($key) {
|
||||||
'structural' => $this->oc_schema->filter(fn($item) => $item->isStructural()),
|
'structural' => $this->oc_schema->filter(fn($item)=>$item->isStructural()),
|
||||||
default => parent::__get($key),
|
default => parent::__get($key),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function __set(string $key,mixed $values): void
|
||||||
|
{
|
||||||
|
switch ($key) {
|
||||||
|
case 'values':
|
||||||
|
parent::__set($key,$values);
|
||||||
|
|
||||||
|
// We need to populate oc_schema, if we are a new OC and thus dont have any old values
|
||||||
|
if (! $this->values_old->count() && $this->values->count())
|
||||||
|
$this->set_oc_schema($this->tagValues());
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: parent::__set($key,$values);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is a specific value the structural objectclass
|
* Is a specific value the structural objectclass
|
||||||
*
|
*
|
||||||
@ -63,4 +77,11 @@ final class ObjectClass extends Attribute
|
|||||||
->with('old',$old)
|
->with('old',$old)
|
||||||
->with('new',$new);
|
->with('new',$new);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function set_oc_schema(Collection $tv): void
|
||||||
|
{
|
||||||
|
$this->oc_schema = config('server')
|
||||||
|
->schema('objectclasses')
|
||||||
|
->filter(fn($item)=>$tv->contains($item->name));
|
||||||
|
}
|
||||||
}
|
}
|
@ -88,19 +88,23 @@ final class Password extends Attribute
|
|||||||
->with('helpers',static::helpers()->map(fn($item,$key)=>['id'=>$key,'value'=>$key])->sort());
|
->with('helpers',static::helpers()->map(fn($item,$key)=>['id'=>$key,'value'=>$key])->sort());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function render_item_old(int $key): ?string
|
public function render_item_old(string $dotkey): ?string
|
||||||
{
|
{
|
||||||
$pw = Arr::get($this->values_old,$key);
|
$pw = parent::render_item_old($dotkey);
|
||||||
|
|
||||||
return $pw
|
return $pw
|
||||||
? (((($x=$this->hash($pw)) && ($x::id() !== '*clear*')) ? sprintf('{%s}',$x::shortid()) : '').str_repeat('*',16))
|
? (((($x=$this->hash($pw)) && ($x::id() === '*clear*')) ? sprintf('{%s}',$x::shortid()) : '')
|
||||||
|
.str_repeat('*',16))
|
||||||
: NULL;
|
: NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function render_item_new(int $key): ?string
|
public function render_item_new(string $dotkey): ?string
|
||||||
{
|
{
|
||||||
$pw = Arr::get($this->values,$key);
|
$pw = parent::render_item_new($dotkey);
|
||||||
|
|
||||||
return $pw
|
return $pw
|
||||||
? (((($x=$this->hash($pw)) && ($x::id() !== '*clear*')) ? sprintf('{%s}',$x::shortid()) : '').str_repeat('*',16))
|
? (((($x=$this->hash($pw)) && ($x::id() !== '*clear*')) ? sprintf('{%s}',$x::shortid()) : '')
|
||||||
|
.str_repeat('*',16))
|
||||||
: NULL;
|
: NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -5,6 +5,7 @@ namespace App\Classes\LDAP\Export;
|
|||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
use App\Classes\LDAP\Export;
|
use App\Classes\LDAP\Export;
|
||||||
|
use App\Ldap\Entry;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Export from LDAP using an LDIF format
|
* Export from LDAP using an LDIF format
|
||||||
@ -55,8 +56,8 @@ class LDIF extends Export
|
|||||||
foreach ($tagvalues as $value) {
|
foreach ($tagvalues as $value) {
|
||||||
$result .= $this->multiLineDisplay(
|
$result .= $this->multiLineDisplay(
|
||||||
Str::isAscii($value)
|
Str::isAscii($value)
|
||||||
? sprintf('%s: %s',$ao->name.($tag ? ';'.$tag : ''),$value)
|
? sprintf('%s: %s',$ao->name.(($tag !== Entry::TAG_NOTAG) ? ';'.$tag : ''),$value)
|
||||||
: sprintf('%s:: %s',$ao->name.($tag ? ';'.$tag : ''),base64_encode($value))
|
: sprintf('%s:: %s',$ao->name.(($tag !== Entry::TAG_NOTAG) ? ';'.$tag : ''),base64_encode($value))
|
||||||
,$this->br);
|
,$this->br);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,9 @@ use Illuminate\Support\Arr;
|
|||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
|
use App\Classes\LDAP\Attribute;
|
||||||
|
use App\Ldap\Entry;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents an LDAP AttributeType
|
* Represents an LDAP AttributeType
|
||||||
*
|
*
|
||||||
@ -341,6 +344,11 @@ final class AttributeType extends Base {
|
|||||||
$this->used_in_object_classes->put($name,$structural);
|
$this->used_in_object_classes->put($name,$structural);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function factory(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute\Factory::create(dn:'',attribute:$this->name,values:[]);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the names of attributes that are an alias for this attribute (if any).
|
* Gets the names of attributes that are an alias for this attribute (if any).
|
||||||
*
|
*
|
||||||
@ -548,6 +556,7 @@ final class AttributeType extends Base {
|
|||||||
{
|
{
|
||||||
// For each item in array, we need to get the OC hierarchy
|
// For each item in array, we need to get the OC hierarchy
|
||||||
$heirachy = collect($array)
|
$heirachy = collect($array)
|
||||||
|
->flatten()
|
||||||
->filter()
|
->filter()
|
||||||
->map(fn($item)=>config('server')
|
->map(fn($item)=>config('server')
|
||||||
->schema('objectclasses',$item)
|
->schema('objectclasses',$item)
|
||||||
@ -556,14 +565,17 @@ final class AttributeType extends Base {
|
|||||||
->flatten()
|
->flatten()
|
||||||
->unique();
|
->unique();
|
||||||
|
|
||||||
|
// Get any config validation
|
||||||
$validation = collect(Arr::get(config('ldap.validation'),$this->name_lc,[]));
|
$validation = collect(Arr::get(config('ldap.validation'),$this->name_lc,[]));
|
||||||
|
|
||||||
|
$nolangtag = sprintf('%s.%s.0',$this->name_lc,Entry::TAG_NOTAG);
|
||||||
|
|
||||||
// Add in schema required by conditions
|
// Add in schema required by conditions
|
||||||
if (($heirachy->intersect($this->required_by_object_classes->keys())->count() > 0)
|
if (($heirachy->intersect($this->required_by_object_classes->keys())->count() > 0)
|
||||||
&& (! collect($validation->get($this->name_lc))->contains('required'))) {
|
&& (! collect($validation->get($this->name_lc))->contains('required'))) {
|
||||||
$validation
|
$validation
|
||||||
->prepend(array_merge(['required','min:1'],$validation->get($this->name_lc.'.0',[])),$this->name_lc.'.0')
|
->prepend(array_merge(['required','min:1'],$validation->get($nolangtag,[])),$nolangtag)
|
||||||
->prepend(array_merge(['required','array','min:1'],$validation->get($this->name_lc,[])),$this->name_lc);
|
->prepend(array_merge(['required','array','min:1',($this->factory()->no_attr_tags ? 'max:1' : NULL)],$validation->get($this->name_lc,[])),$this->name_lc);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $validation->toArray();
|
return $validation->toArray();
|
||||||
|
@ -57,11 +57,12 @@ class HomeController extends Controller
|
|||||||
|
|
||||||
$o = new Entry;
|
$o = new Entry;
|
||||||
|
|
||||||
if (count(array_filter($x=old('objectclass',$request->objectclass)))) {
|
if (count($x=array_filter(old('objectclass',$request->objectclass)))) {
|
||||||
$o->objectclass = $x;
|
$o->objectclass = $x;
|
||||||
|
|
||||||
|
// Also add in our required attributes
|
||||||
foreach($o->getAvailableAttributes()->filter(fn($item)=>$item->required) as $ao)
|
foreach($o->getAvailableAttributes()->filter(fn($item)=>$item->required) as $ao)
|
||||||
$o->{$ao->name} = '';
|
$o->{$ao->name} = [Entry::TAG_NOTAG=>''];
|
||||||
|
|
||||||
$o->setRDNBase($key['dn']);
|
$o->setRDNBase($key['dn']);
|
||||||
}
|
}
|
||||||
@ -188,8 +189,6 @@ class HomeController extends Controller
|
|||||||
|
|
||||||
$result = (new Entry)
|
$result = (new Entry)
|
||||||
->query()
|
->query()
|
||||||
//->cache(Carbon::now()->addSeconds(Config::get('ldap.cache.time')))
|
|
||||||
//->select(['*'])
|
|
||||||
->setDn($dn)
|
->setDn($dn)
|
||||||
->recursive()
|
->recursive()
|
||||||
->get();
|
->get();
|
||||||
@ -269,19 +268,22 @@ class HomeController extends Controller
|
|||||||
// We need to process and encrypt the password
|
// We need to process and encrypt the password
|
||||||
if ($request->userpassword) {
|
if ($request->userpassword) {
|
||||||
$passwords = [];
|
$passwords = [];
|
||||||
foreach ($request->userpassword as $key => $value) {
|
$po = $o->getObject('userpassword');
|
||||||
|
foreach (Arr::dot($request->userpassword) as $dotkey => $value) {
|
||||||
// If the password is still the MD5 of the old password, then it hasnt changed
|
// If the password is still the MD5 of the old password, then it hasnt changed
|
||||||
if (($old=Arr::get($o->userpassword,$key)) && ($value === md5($old))) {
|
if (($old=Arr::get($po,$dotkey)) && ($value === md5($old))) {
|
||||||
array_push($passwords,$old);
|
$passwords[$dotkey] = $value;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($value) {
|
if ($value) {
|
||||||
$type = Arr::get($request->userpassword_hash,$key);
|
$type = Arr::get($request->userpassword_hash,$dotkey);
|
||||||
array_push($passwords,Password::hash_id($type)->encode($value));
|
$passwords[$dotkey] = Password::hash_id($type)
|
||||||
|
->encode($value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$o->userpassword = $passwords;
|
|
||||||
|
$o->userpassword = Arr::undot($passwords);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! $o->getDirty())
|
if (! $o->getDirty())
|
||||||
@ -374,8 +376,7 @@ class HomeController extends Controller
|
|||||||
// If we are rendering a DN, rebuild our object
|
// If we are rendering a DN, rebuild our object
|
||||||
$o = config('server')->fetch($key['dn']);
|
$o = config('server')->fetch($key['dn']);
|
||||||
|
|
||||||
// @todo We need to dynamically exclude request items, so we dont need to add them here
|
foreach (collect(old())->except(['key','step','_token','userpassword_hash']) as $attr => $value)
|
||||||
foreach (collect(old())->except(['dn','_token','userpassword_hash']) as $attr => $value)
|
|
||||||
$o->{$attr} = $value;
|
$o->{$attr} = $value;
|
||||||
|
|
||||||
return match ($key['cmd']) {
|
return match ($key['cmd']) {
|
||||||
|
@ -34,10 +34,11 @@ class EntryAddRequest extends FormRequest
|
|||||||
if (request()->method() === 'GET')
|
if (request()->method() === 'GET')
|
||||||
return [];
|
return [];
|
||||||
|
|
||||||
|
$r = request() ?: collect();
|
||||||
return config('server')
|
return config('server')
|
||||||
->schema('attributetypes')
|
->schema('attributetypes')
|
||||||
->intersectByKeys($this->request)
|
->intersectByKeys($r->all())
|
||||||
->map(fn($item)=>$item->validation(request()->get('objectclass')))
|
->map(fn($item)=>$item->validation($r->get('objectclass',[])))
|
||||||
->filter()
|
->filter()
|
||||||
->flatMap(fn($item)=>$item)
|
->flatMap(fn($item)=>$item)
|
||||||
->merge([
|
->merge([
|
||||||
@ -60,6 +61,12 @@ class EntryAddRequest extends FormRequest
|
|||||||
'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',
|
||||||
|
'array',
|
||||||
|
'min:1',
|
||||||
|
'max:1',
|
||||||
|
],
|
||||||
|
'objectclass._null_'=>[
|
||||||
'required',
|
'required',
|
||||||
'array',
|
'array',
|
||||||
'min:1',
|
'min:1',
|
||||||
|
@ -13,10 +13,12 @@ class EntryRequest extends FormRequest
|
|||||||
*/
|
*/
|
||||||
public function rules(): array
|
public function rules(): array
|
||||||
{
|
{
|
||||||
|
$r = request() ?: collect();
|
||||||
|
|
||||||
return config('server')
|
return config('server')
|
||||||
->schema('attributetypes')
|
->schema('attributetypes')
|
||||||
->intersectByKeys($this->request)
|
->intersectByKeys($r->all())
|
||||||
->map(fn($item)=>$item->validation(request()?->get('objectclass') ?: []))
|
->map(fn($item)=>$item->validation($r->get('objectclass',[])))
|
||||||
->filter()
|
->filter()
|
||||||
->flatMap(fn($item)=>$item)
|
->flatMap(fn($item)=>$item)
|
||||||
->toArray();
|
->toArray();
|
||||||
|
@ -23,6 +23,7 @@ class Entry extends Model
|
|||||||
{
|
{
|
||||||
private const TAG_CHARS = 'a-zA-Z0-9-';
|
private const TAG_CHARS = 'a-zA-Z0-9-';
|
||||||
private const TAG_CHARS_LANG = 'lang-['.self::TAG_CHARS.']';
|
private const TAG_CHARS_LANG = 'lang-['.self::TAG_CHARS.']';
|
||||||
|
public const TAG_NOTAG = '_null_';
|
||||||
|
|
||||||
// Our Attribute objects
|
// Our Attribute objects
|
||||||
private Collection $objects;
|
private Collection $objects;
|
||||||
@ -53,8 +54,9 @@ class Entry extends Model
|
|||||||
/**
|
/**
|
||||||
* This function overrides getAttributes to use our collection of Attribute objects instead of the models attributes.
|
* This function overrides getAttributes to use our collection of Attribute objects instead of the models attributes.
|
||||||
*
|
*
|
||||||
|
* This returns an array that should be consistent with $this->attributes
|
||||||
|
*
|
||||||
* @return array
|
* @return array
|
||||||
* @note $this->attributes may not be updated with changes
|
|
||||||
*/
|
*/
|
||||||
public function getAttributes(): array
|
public function getAttributes(): array
|
||||||
{
|
{
|
||||||
@ -63,7 +65,7 @@ class Entry extends Model
|
|||||||
($item->no_attr_tags)
|
($item->no_attr_tags)
|
||||||
? [strtolower($item->name)=>$item->values]
|
? [strtolower($item->name)=>$item->values]
|
||||||
: $item->values
|
: $item->values
|
||||||
->flatMap(fn($v,$k)=>[strtolower($item->name.($k ? ';'.$k : ''))=>$v]))
|
->flatMap(fn($v,$k)=>[strtolower($item->name.($k !== self::TAG_NOTAG ? ';'.$k : ''))=>$v]))
|
||||||
->toArray();
|
->toArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,12 +78,10 @@ class Entry extends Model
|
|||||||
{
|
{
|
||||||
$key = $this->normalizeAttributeKey($key);
|
$key = $this->normalizeAttributeKey($key);
|
||||||
|
|
||||||
// @todo Silently ignore keys of language tags - we should work with them
|
list($attribute,$tag) = $this->keytag($key);
|
||||||
if (str_contains($key,';'))
|
|
||||||
return TRUE;
|
|
||||||
|
|
||||||
return ((! array_key_exists($key,$this->original)) && (! $this->objects->has($key)))
|
return ((! array_key_exists($key,$this->original)) && (! $this->objects->has($attribute)))
|
||||||
|| (! $this->getObject($key)->isDirty());
|
|| (! $this->getObject($attribute)->isDirty());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function query(bool $noattrs=false): Builder
|
public static function query(bool $noattrs=false): Builder
|
||||||
@ -98,18 +98,22 @@ class Entry extends Model
|
|||||||
* As attribute values are updated, or new ones created, we need to mirror that
|
* As attribute values are updated, or new ones created, we need to mirror that
|
||||||
* into our $objects. This is called when we $o->key = $value
|
* into our $objects. This is called when we $o->key = $value
|
||||||
*
|
*
|
||||||
|
* This function should update $this->attributes and correctly reflect changes in $this->objects
|
||||||
|
*
|
||||||
* @param string $key
|
* @param string $key
|
||||||
* @param mixed $value
|
* @param mixed $value
|
||||||
* @return $this
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setAttribute(string $key,mixed $value): static
|
public function setAttribute(string $key,mixed $value): static
|
||||||
{
|
{
|
||||||
parent::setAttribute($key,$value);
|
foreach ($value as $k => $v)
|
||||||
|
parent::setAttribute($key.($k !== self::TAG_NOTAG ? ';'.$k : ''),$v);
|
||||||
|
|
||||||
$key = $this->normalizeAttributeKey($key);
|
$key = $this->normalizeAttributeKey($key);
|
||||||
|
list($attribute,$tags) = $this->keytag($key);
|
||||||
|
|
||||||
$o = $this->objects->get($key) ?: Factory::create($this->dn ?: '',$key,[],Arr::get($this->attributes,'objectclass',[]));
|
$o = $this->objects->get($attribute) ?: Factory::create($this->dn ?: '',$attribute,[],Arr::get($this->attributes,'objectclass',[]));
|
||||||
$o->values = collect($this->attributes[$key]);
|
$o->values = collect($value);
|
||||||
|
|
||||||
$this->objects->put($key,$o);
|
$this->objects->put($key,$o);
|
||||||
|
|
||||||
@ -173,25 +177,47 @@ class Entry extends Model
|
|||||||
$key = $this->normalizeAttributeKey(strtolower($key));
|
$key = $this->normalizeAttributeKey(strtolower($key));
|
||||||
|
|
||||||
// If the attribute name has tags
|
// If the attribute name has tags
|
||||||
$matches = [];
|
list($attribute,$tag) = $this->keytag($key);
|
||||||
if (preg_match(sprintf('/^([%s]+);+([%s;]+)/',self::TAG_CHARS,self::TAG_CHARS),$key,$matches)) {
|
|
||||||
$attribute = $matches[1];
|
|
||||||
$tags = $matches[2];
|
|
||||||
|
|
||||||
} else {
|
|
||||||
$attribute = $key;
|
|
||||||
$tags = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (! config('server')->schema('attributetypes')->has($attribute))
|
if (! config('server')->schema('attributetypes')->has($attribute))
|
||||||
throw new AttributeException(sprintf('Schema doesnt have attribute [%s]',$attribute));
|
throw new AttributeException(sprintf('Schema doesnt have attribute [%s]',$attribute));
|
||||||
|
|
||||||
$o = $this->objects->get($attribute) ?: Attribute\Factory::create($this->dn ?: '',$attribute,[]);
|
$o = $this->objects->get($attribute) ?: Attribute\Factory::create($this->dn ?: '',$attribute,[]);
|
||||||
$o->addValue($tags,$value);
|
$o->addValue($tag,[$value]);
|
||||||
|
|
||||||
$this->objects->put($attribute,$o);
|
$this->objects->put($attribute,$o);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Export this record
|
||||||
|
*
|
||||||
|
* @param string $method
|
||||||
|
* @param string $scope
|
||||||
|
* @return string
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
public function export(string $method,string $scope): string
|
||||||
|
{
|
||||||
|
// @todo To implement
|
||||||
|
switch ($scope) {
|
||||||
|
case 'base':
|
||||||
|
case 'one':
|
||||||
|
case 'sub':
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new \Exception('Export scope unknown:'.$scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ($method) {
|
||||||
|
case 'ldif':
|
||||||
|
return new LDIF(collect($this));
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new \Exception('Export method not implemented:'.$method);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert all our attribute values into an array of Objects
|
* Convert all our attribute values into an array of Objects
|
||||||
*
|
*
|
||||||
@ -203,16 +229,7 @@ class Entry extends Model
|
|||||||
$entry_oc = Arr::get($this->attributes,'objectclass',[]);
|
$entry_oc = Arr::get($this->attributes,'objectclass',[]);
|
||||||
|
|
||||||
foreach ($this->attributes as $attrtag => $values) {
|
foreach ($this->attributes as $attrtag => $values) {
|
||||||
// If the attribute name has tags
|
list($attribute,$tags) = $this->keytag($attrtag);
|
||||||
$matches = [];
|
|
||||||
if (preg_match(sprintf('/^([%s]+);+([%s;]+)/',self::TAG_CHARS,self::TAG_CHARS),$attrtag,$matches)) {
|
|
||||||
$attribute = $matches[1];
|
|
||||||
$tags = $matches[2];
|
|
||||||
|
|
||||||
} else {
|
|
||||||
$attribute = $attrtag;
|
|
||||||
$tags = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
$orig = Arr::get($this->original,$attrtag,[]);
|
$orig = Arr::get($this->original,$attrtag,[]);
|
||||||
|
|
||||||
@ -227,7 +244,8 @@ class Entry extends Model
|
|||||||
$entry_oc,
|
$entry_oc,
|
||||||
));
|
));
|
||||||
|
|
||||||
$o->values = $o->values->merge([$tags=>$values]);
|
$o->addValue($tags,$values);
|
||||||
|
$o->addValueOld($tags,Arr::get($this->original,$attrtag));
|
||||||
|
|
||||||
$result->put($attribute,$o);
|
$result->put($attribute,$o);
|
||||||
}
|
}
|
||||||
@ -270,7 +288,7 @@ class Entry extends Model
|
|||||||
{
|
{
|
||||||
$result = collect();
|
$result = collect();
|
||||||
|
|
||||||
foreach ($this->objectclass as $oc)
|
foreach ($this->getObject('objectclass')->values as $oc)
|
||||||
$result = $result->merge(config('server')->schema('objectclasses',$oc)->attributes);
|
$result = $result->merge(config('server')->schema('objectclasses',$oc)->attributes);
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
@ -309,7 +327,9 @@ class Entry extends Model
|
|||||||
->map(fn($item)=>$item
|
->map(fn($item)=>$item
|
||||||
->values
|
->values
|
||||||
->keys()
|
->keys()
|
||||||
->filter(fn($item)=>preg_match(sprintf('/%s+;?/',self::TAG_CHARS_LANG),$item)))
|
->filter(fn($item)=>preg_match(sprintf('/%s+;?/',self::TAG_CHARS_LANG),$item))
|
||||||
|
->map(fn($item)=>preg_replace('/lang-/','',$item))
|
||||||
|
)
|
||||||
->filter(fn($item)=>$item->count());
|
->filter(fn($item)=>$item->count());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -367,7 +387,8 @@ class Entry extends Model
|
|||||||
->filter(fn($item)=>
|
->filter(fn($item)=>
|
||||||
$item && collect(explode(';',$item))->filter(
|
$item && collect(explode(';',$item))->filter(
|
||||||
fn($item)=>
|
fn($item)=>
|
||||||
(! preg_match(sprintf('/^%s+$/',self::TAG_CHARS_LANG),$item))
|
(! preg_match(sprintf('/^%s$/',self::TAG_NOTAG),$item))
|
||||||
|
&& (! preg_match(sprintf('/^%s+$/',self::TAG_CHARS_LANG),$item))
|
||||||
&& (! preg_match('/^binary$/',$item))
|
&& (! preg_match('/^binary$/',$item))
|
||||||
)
|
)
|
||||||
->count())
|
->count())
|
||||||
@ -379,6 +400,9 @@ class Entry extends Model
|
|||||||
* Return a list of attributes without any values
|
* Return a list of attributes without any values
|
||||||
*
|
*
|
||||||
* @return Collection
|
* @return Collection
|
||||||
|
* @todo Dont show attributes that are not provided by an objectclass, make a new function to show those
|
||||||
|
* This is for dynamic list items eg: labeledURI, which are not editable.
|
||||||
|
* We can highlight those values that are as a result of a dynamic module
|
||||||
*/
|
*/
|
||||||
public function getMissingAttributes(): Collection
|
public function getMissingAttributes(): Collection
|
||||||
{
|
{
|
||||||
@ -399,12 +423,14 @@ class Entry extends Model
|
|||||||
/**
|
/**
|
||||||
* Return this list of user attributes
|
* Return this list of user attributes
|
||||||
*
|
*
|
||||||
|
* @param string|null $tag If null return all tags
|
||||||
* @return Collection
|
* @return Collection
|
||||||
*/
|
*/
|
||||||
public function getVisibleAttributes(): Collection
|
public function getVisibleAttributes(?string $tag=NULL): Collection
|
||||||
{
|
{
|
||||||
return $this->objects
|
return $this->objects
|
||||||
->filter(fn($item)=>! $item->is_internal);
|
->filter(fn($item)=>! $item->is_internal)
|
||||||
|
->filter(fn($item)=>is_null($tag) || count($item->tagValues($tag)) > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function hasAttribute(int|string $key): bool
|
public function hasAttribute(int|string $key): bool
|
||||||
@ -413,36 +439,6 @@ class Entry extends Model
|
|||||||
->has($key);
|
->has($key);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Export this record
|
|
||||||
*
|
|
||||||
* @param string $method
|
|
||||||
* @param string $scope
|
|
||||||
* @return string
|
|
||||||
* @throws \Exception
|
|
||||||
*/
|
|
||||||
public function export(string $method,string $scope): string
|
|
||||||
{
|
|
||||||
// @todo To implement
|
|
||||||
switch ($scope) {
|
|
||||||
case 'base':
|
|
||||||
case 'one':
|
|
||||||
case 'sub':
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
throw new \Exception('Export scope unknown:'.$scope);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch ($method) {
|
|
||||||
case 'ldif':
|
|
||||||
return new LDIF(collect($this));
|
|
||||||
|
|
||||||
default:
|
|
||||||
throw new \Exception('Export method not implemented:'.$method);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return an icon for a DN based on objectClass
|
* Return an icon for a DN based on objectClass
|
||||||
*
|
*
|
||||||
@ -450,65 +446,92 @@ class Entry extends Model
|
|||||||
*/
|
*/
|
||||||
public function icon(): string
|
public function icon(): string
|
||||||
{
|
{
|
||||||
$objectclasses = array_map('strtolower',$this->objectclass);
|
$objectclasses = $this->getObject('objectclass')
|
||||||
|
->tagValues()
|
||||||
|
->map(fn($item)=>strtolower($item));
|
||||||
|
|
||||||
// Return icon based upon objectClass value
|
// Return icon based upon objectClass value
|
||||||
if (in_array('person',$objectclasses) ||
|
if ($objectclasses->intersect([
|
||||||
in_array('organizationalperson',$objectclasses) ||
|
'account',
|
||||||
in_array('inetorgperson',$objectclasses) ||
|
'inetorgperson',
|
||||||
in_array('account',$objectclasses) ||
|
'organizationalperson',
|
||||||
in_array('posixaccount',$objectclasses))
|
'person',
|
||||||
|
'posixaccount',
|
||||||
|
])->count())
|
||||||
return 'fas fa-user';
|
return 'fas fa-user';
|
||||||
|
|
||||||
elseif (in_array('organization',$objectclasses))
|
elseif ($objectclasses->contains('organization'))
|
||||||
return 'fas fa-university';
|
return 'fas fa-university';
|
||||||
|
|
||||||
elseif (in_array('organizationalunit',$objectclasses))
|
elseif ($objectclasses->contains('organizationalunit'))
|
||||||
return 'fas fa-object-group';
|
return 'fas fa-object-group';
|
||||||
|
|
||||||
elseif (in_array('posixgroup',$objectclasses) ||
|
elseif ($objectclasses->intersect([
|
||||||
in_array('groupofnames',$objectclasses) ||
|
'posixgroup',
|
||||||
in_array('groupofuniquenames',$objectclasses) ||
|
'groupofnames',
|
||||||
in_array('group',$objectclasses))
|
'groupofuniquenames',
|
||||||
|
'group',
|
||||||
|
])->count())
|
||||||
return 'fas fa-users';
|
return 'fas fa-users';
|
||||||
|
|
||||||
elseif (in_array('dcobject',$objectclasses) ||
|
elseif ($objectclasses->intersect([
|
||||||
in_array('domainrelatedobject',$objectclasses) ||
|
'dcobject',
|
||||||
in_array('domain',$objectclasses) ||
|
'domainrelatedobject',
|
||||||
in_array('builtindomain',$objectclasses))
|
'domain',
|
||||||
|
'builtindomain',
|
||||||
|
])->count())
|
||||||
return 'fas fa-network-wired';
|
return 'fas fa-network-wired';
|
||||||
|
|
||||||
elseif (in_array('alias',$objectclasses))
|
elseif ($objectclasses->contains('alias'))
|
||||||
return 'fas fa-theater-masks';
|
return 'fas fa-theater-masks';
|
||||||
|
|
||||||
elseif (in_array('country',$objectclasses))
|
elseif ($objectclasses->contains('country'))
|
||||||
return sprintf('flag %s',strtolower(Arr::get($this->c ?: [],0)));
|
return sprintf('flag %s',strtolower(Arr::get($this->c ?: [],0)));
|
||||||
|
|
||||||
elseif (in_array('device',$objectclasses))
|
elseif ($objectclasses->contains('device'))
|
||||||
return 'fas fa-mobile-alt';
|
return 'fas fa-mobile-alt';
|
||||||
|
|
||||||
elseif (in_array('document',$objectclasses))
|
elseif ($objectclasses->contains('document'))
|
||||||
return 'fas fa-file-alt';
|
return 'fas fa-file-alt';
|
||||||
|
|
||||||
elseif (in_array('iphost',$objectclasses))
|
elseif ($objectclasses->contains('iphost'))
|
||||||
return 'fas fa-wifi';
|
return 'fas fa-wifi';
|
||||||
|
|
||||||
elseif (in_array('room',$objectclasses))
|
elseif ($objectclasses->contains('room'))
|
||||||
return 'fas fa-door-open';
|
return 'fas fa-door-open';
|
||||||
|
|
||||||
elseif (in_array('server',$objectclasses))
|
elseif ($objectclasses->contains('server'))
|
||||||
return 'fas fa-server';
|
return 'fas fa-server';
|
||||||
|
|
||||||
elseif (in_array('openldaprootdse',$objectclasses))
|
elseif ($objectclasses->contains('openldaprootdse'))
|
||||||
return 'fas fa-info';
|
return 'fas fa-info';
|
||||||
|
|
||||||
// Default
|
// Default
|
||||||
return 'fa-fw fas fa-cog';
|
return 'fa-fw fas fa-cog';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given an LDAP attribute, this will return the attribute name and the tag
|
||||||
|
* eg: description;lang-cn will return [description,lang-cn]
|
||||||
|
*
|
||||||
|
* @param string $key
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function keytag(string $key): array
|
||||||
|
{
|
||||||
|
$matches = [];
|
||||||
|
if (preg_match(sprintf('/^([%s]+);+([%s;]+)/',self::TAG_CHARS,self::TAG_CHARS),$key,$matches)) {
|
||||||
|
$attribute = $matches[1];
|
||||||
|
$tags = $matches[2];
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$attribute = $key;
|
||||||
|
$tags = self::TAG_NOTAG;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [$attribute,$tags];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dont convert our $this->attributes to $this->objects when creating a new Entry::class
|
* Dont convert our $this->attributes to $this->objects when creating a new Entry::class
|
||||||
*
|
*
|
||||||
|
@ -20,7 +20,7 @@ class HasStructuralObjectClass implements ValidationRule
|
|||||||
*/
|
*/
|
||||||
public function validate(string $attribute,mixed $value,Closure $fail): void
|
public function validate(string $attribute,mixed $value,Closure $fail): void
|
||||||
{
|
{
|
||||||
foreach ($value as $item)
|
foreach (collect($value)->dot() as $item)
|
||||||
if ($item && config('server')->schema('objectclasses',$item)->isStructural())
|
if ($item && config('server')->schema('objectclasses',$item)->isStructural())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -11,8 +11,8 @@ trait MD5Updates
|
|||||||
{
|
{
|
||||||
public function isDirty(): bool
|
public function isDirty(): bool
|
||||||
{
|
{
|
||||||
foreach ($this->values->diff($this->values_old) as $key => $value)
|
foreach ($this->values_old->dot()->keys()->merge($this->values->dot()->keys())->unique() as $dotkey)
|
||||||
if (md5(Arr::get($this->values_old,$key)) !== $value)
|
if (md5(Arr::get($this->values_old->dot(),$dotkey)) !== Arr::get($this->values->dot(),$dotkey))
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
@ -5,6 +5,7 @@ namespace App\View\Components;
|
|||||||
use Illuminate\View\Component;
|
use Illuminate\View\Component;
|
||||||
|
|
||||||
use App\Classes\LDAP\Attribute as LDAPAttribute;
|
use App\Classes\LDAP\Attribute as LDAPAttribute;
|
||||||
|
use App\Ldap\Entry;
|
||||||
|
|
||||||
class Attribute extends Component
|
class Attribute extends Component
|
||||||
{
|
{
|
||||||
@ -12,17 +13,19 @@ class Attribute extends Component
|
|||||||
public bool $edit;
|
public bool $edit;
|
||||||
public bool $new;
|
public bool $new;
|
||||||
public bool $old;
|
public bool $old;
|
||||||
public ?string $na;
|
public string $langtag;
|
||||||
|
public ?string $na; // Text to render if the LDAPAttribute is null
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new component instance.
|
* Create a new component instance.
|
||||||
*/
|
*/
|
||||||
public function __construct(?LDAPAttribute $o,bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,?string $na=NULL)
|
public function __construct(?LDAPAttribute $o,bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,string $langtag=Entry::TAG_NOTAG,?string $na=NULL)
|
||||||
{
|
{
|
||||||
$this->o = $o;
|
$this->o = $o;
|
||||||
$this->edit = $edit;
|
$this->edit = $edit;
|
||||||
$this->old = $old;
|
$this->old = $old;
|
||||||
$this->new = $new;
|
$this->new = $new;
|
||||||
|
$this->langtag = $langtag;
|
||||||
$this->na = $na;
|
$this->na = $na;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,23 +4,25 @@ namespace App\View\Components;
|
|||||||
|
|
||||||
use Closure;
|
use Closure;
|
||||||
use Illuminate\Contracts\View\View;
|
use Illuminate\Contracts\View\View;
|
||||||
use Illuminate\Support\Collection;
|
|
||||||
use Illuminate\View\Component;
|
use Illuminate\View\Component;
|
||||||
|
|
||||||
use App\Classes\LDAP\Attribute as LDAPAttribute;
|
use App\Classes\LDAP\Attribute as LDAPAttribute;
|
||||||
|
use App\Ldap\Entry;
|
||||||
|
|
||||||
class AttributeType extends Component
|
class AttributeType extends Component
|
||||||
{
|
{
|
||||||
private LDAPAttribute $o;
|
private LDAPAttribute $o;
|
||||||
private bool $new;
|
private bool $new;
|
||||||
|
private string $langtag;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new component instance.
|
* Create a new component instance.
|
||||||
*/
|
*/
|
||||||
public function __construct(LDAPAttribute $o,bool $new=FALSE)
|
public function __construct(LDAPAttribute $o,bool $new=FALSE,string $langtag=Entry::TAG_NOTAG)
|
||||||
{
|
{
|
||||||
$this->o = $o;
|
$this->o = $o;
|
||||||
$this->new = $new;
|
$this->new = $new;
|
||||||
|
$this->langtag = $langtag;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -30,6 +32,7 @@ class AttributeType extends Component
|
|||||||
{
|
{
|
||||||
return view('components.attribute-type')
|
return view('components.attribute-type')
|
||||||
->with('o',$this->o)
|
->with('o',$this->o)
|
||||||
->with('new',$this->new);
|
->with('new',$this->new)
|
||||||
|
->with('langtag',$this->langtag);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -122,47 +122,47 @@ return [
|
|||||||
*/
|
*/
|
||||||
'validation' => [
|
'validation' => [
|
||||||
'objectclass' => [
|
'objectclass' => [
|
||||||
'objectclass'=>[
|
'objectclass.*'=>[
|
||||||
new HasStructuralObjectClass,
|
new HasStructuralObjectClass,
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
'gidnumber' => [
|
'gidnumber' => [
|
||||||
'gidnumber'=> [
|
'gidnumber.*'=> [
|
||||||
'sometimes',
|
'sometimes',
|
||||||
'max:1'
|
'max:1'
|
||||||
],
|
],
|
||||||
'gidnumber.*' => [
|
'gidnumber.*.*' => [
|
||||||
'nullable',
|
'nullable',
|
||||||
'integer',
|
'integer',
|
||||||
'max:65535'
|
'max:65535'
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
'mail' => [
|
'mail' => [
|
||||||
'mail'=>[
|
'mail.*'=>[
|
||||||
'sometimes',
|
'sometimes',
|
||||||
'min:1'
|
'min:1'
|
||||||
],
|
],
|
||||||
'mail.*' => [
|
'mail.*.*' => [
|
||||||
'nullable',
|
'nullable',
|
||||||
'email'
|
'email'
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
'userpassword' => [
|
'userpassword' => [
|
||||||
'userpassword' => [
|
'userpassword.*' => [
|
||||||
'sometimes',
|
'sometimes',
|
||||||
'min:1'
|
'min:1'
|
||||||
],
|
],
|
||||||
'userpassword.*' => [
|
'userpassword.*.*' => [
|
||||||
'nullable',
|
'nullable',
|
||||||
'min:8'
|
'min:8'
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
'uidnumber' => [
|
'uidnumber' => [
|
||||||
'uidnumber' => [
|
'uidnumber.*' => [
|
||||||
'sometimes',
|
'sometimes',
|
||||||
'max:1'
|
'max:1'
|
||||||
],
|
],
|
||||||
'uidnumber.*' => [
|
'uidnumber.*.*' => [
|
||||||
'nullable',
|
'nullable',
|
||||||
'integer',
|
'integer',
|
||||||
'max:65535'
|
'max:65535'
|
||||||
|
@ -1 +1 @@
|
|||||||
v2.0.3-rel
|
v2.1.0-dev
|
||||||
|
3
public/css/custom.css
vendored
3
public/css/custom.css
vendored
@ -30,7 +30,10 @@ input.form-control.input-group-end {
|
|||||||
|
|
||||||
.custom-tooltip-danger {
|
.custom-tooltip-danger {
|
||||||
--bs-tooltip-bg: var(--bs-danger);
|
--bs-tooltip-bg: var(--bs-danger);
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-tooltip {
|
||||||
|
--bs-tooltip-bg: var(--bs-gray-900);
|
||||||
}
|
}
|
||||||
|
|
||||||
.tooltip {
|
.tooltip {
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<x-attribute :o="$o" :edit="true" :new="$new ?? FALSE"/>
|
<x-attribute :o="$o" :edit="true" :new="$new ?? FALSE" :langtag="$langtag"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -1,17 +1,10 @@
|
|||||||
<!-- $o=Attribute::class -->
|
<!-- $o=Attribute::class -->
|
||||||
<x-attribute.layout :edit="$edit ?? FALSE" :new="$new ?? FALSE" :o="$o">
|
<x-attribute.layout :edit="$edit ?? FALSE" :new="$new ?? FALSE" :o="$o">
|
||||||
@foreach(old($o->name_lc,($new ?? FALSE) ? [NULL] : $o->values) as $tag=>$tagvalues)
|
|
||||||
<div class="row p-2 border rounded">
|
|
||||||
<div class="col-2">
|
|
||||||
{{ $tag }}
|
|
||||||
</div>
|
|
||||||
<div class="col-10">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
@foreach($tagvalues as $value)
|
@foreach(Arr::get(old($o->name_lc,[$langtag=>($new ?? FALSE) ? [NULL] : $o->tagValues($langtag)]),$langtag) as $key => $value)
|
||||||
@if(($edit ?? FALSE) && ! $o->is_rdn)
|
@if(($edit ?? FALSE) && ! $o->is_rdn)
|
||||||
<div class="input-group has-validation">
|
<div class="input-group has-validation">
|
||||||
<input type="text" @class(['form-control','is-invalid'=>($e=$errors->get($o->name_lc.'.'.$loop->index)),'mb-1','border-focus'=>($o->values->contains($value))]) name="{{ $o->name_lc }}[]" value="{{ $value }}" placeholder="{{ ! is_null($x=Arr::get($o->values,$loop->index)) ? $x : '['.__('NEW').']' }}" @readonly(! ($new ?? FALSE))>
|
<input type="text" @class(['form-control','is-invalid'=>($e=$errors->get($o->name_lc.'.'.$langtag.'.'.$loop->index)),'mb-1','border-focus'=>! ($tv=$o->tagValuesOld($langtag))->contains($value)]) name="{{ $o->name_lc }}[{{ $langtag }}][]" value="{{ $value }}" placeholder="{{ ! is_null($x=$tv->get($loop->index)) ? $x : '['.__('NEW').']' }}" @readonly(! ($new ?? FALSE))>
|
||||||
|
|
||||||
<div class="invalid-feedback pb-2">
|
<div class="invalid-feedback pb-2">
|
||||||
@if($e)
|
@if($e)
|
||||||
@ -19,13 +12,10 @@
|
|||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@else
|
@else
|
||||||
{{ $value }}
|
<input type="text" class="form-control mb-1" value="{{ $value }}" disabled>
|
||||||
@endif
|
@endif
|
||||||
@endforeach
|
@endforeach
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@endforeach
|
|
||||||
</x-attribute.layout>
|
</x-attribute.layout>
|
@ -1,17 +1,17 @@
|
|||||||
<!-- @todo We are not handling redirect backs yet with updated photos -->
|
<!-- @todo We are not handling redirect backs yet with updated photos -->
|
||||||
<!-- $o=Binary\JpegPhoto::class -->
|
<!-- $o=Binary\JpegPhoto::class -->
|
||||||
<x-attribute.layout :edit="$edit" :new="false" :o="$o">
|
<x-attribute.layout :edit="$edit ?? FALSE" :new="$new ?? FALSE" :o="$o" :langtag="$langtag">
|
||||||
<table class="table table-borderless p-0 m-0">
|
<table class="table table-borderless p-0 m-0">
|
||||||
@foreach ($o->values_old as $value)
|
@foreach($o->tagValuesOld() as $key => $value)
|
||||||
<tr>
|
<tr>
|
||||||
@switch ($x=$f->buffer($value,FILEINFO_MIME_TYPE))
|
@switch($x=$f->buffer($value,FILEINFO_MIME_TYPE))
|
||||||
@case('image/jpeg')
|
@case('image/jpeg')
|
||||||
@default
|
@default
|
||||||
<td>
|
<td>
|
||||||
<input type="hidden" name="{{ $o->name_lc }}[]" value="{{ md5($value) }}">
|
<input type="hidden" name="{{ $o->name_lc }}[{{ $langtag }}][]" value="{{ md5($value) }}">
|
||||||
<img @class(['border','rounded','p-2','m-0','is-invalid'=>($e=$errors->get($o->name_lc.'.'.$loop->index))]) src="data:{{ $x }};base64, {{ base64_encode($value) }}" />
|
<img alt="{{ $o->dn }}" @class(['border','rounded','p-2','m-0','is-invalid'=>($e=$errors->get($o->name_lc.'.'.$langtag.'.'.$loop->index))]) src="data:{{ $x }};base64, {{ base64_encode($value) }}" />
|
||||||
|
|
||||||
@if ($edit)
|
@if($edit)
|
||||||
<br>
|
<br>
|
||||||
<!-- @todo TO IMPLEMENT -->
|
<!-- @todo TO IMPLEMENT -->
|
||||||
<button class="btn btn-sm btn-danger deletable d-none mt-3" disabled><i class="fas fa-trash-alt"></i> @lang('Delete')</button>
|
<button class="btn btn-sm btn-danger deletable d-none mt-3" disabled><i class="fas fa-trash-alt"></i> @lang('Delete')</button>
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
<!-- @todo We are not handling redirect backs yet with updated passwords -->
|
<!-- @todo We are not handling redirect backs yet with updated passwords -->
|
||||||
<!-- $o=KrbPrincipleKey::class -->
|
<!-- $o=KrbPrincipleKey::class -->
|
||||||
<x-attribute.layout :edit="$edit ?? FALSE" :new="$new ?? FALSE" :o="$o">
|
<x-attribute.layout :edit="$edit ?? FALSE" :new="$new ?? FALSE" :o="$o" :langtag="$langtag">
|
||||||
@foreach($o->values_old as $value)
|
@foreach($o->tagValuesOld($langtag) as $key => $value)
|
||||||
@if($edit)
|
@if($edit)
|
||||||
<div class="input-group has-validation mb-3">
|
<div class="input-group has-validation mb-3">
|
||||||
<input type="password" @class(['form-control','is-invalid'=>($e=$errors->get($o->name_lc.'.'.$loop->index)),'mb-1','border-focus'=>$o->values->contains($value)]) name="{{ $o->name_lc }}[]" value="{{ md5($value) }}" @readonly(true)>
|
<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)]) name="{{ $o->name_lc }}[{{ $langtag }}][]" value="{{ md5($value) }}" @readonly(true)>
|
||||||
|
|
||||||
<div class="invalid-feedback pb-2">
|
<div class="invalid-feedback pb-2">
|
||||||
@if($e)
|
@if($e)
|
||||||
@ -13,7 +13,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@else
|
@else
|
||||||
{{ str_repeat('*',16) }}
|
{{ $o->render_item_old($langtag.'.'.$key) }}
|
||||||
@endif
|
@endif
|
||||||
@endforeach
|
@endforeach
|
||||||
</x-attribute.layout>
|
</x-attribute.layout>
|
@ -1,21 +1,21 @@
|
|||||||
<!-- $o=KrbTicketFlags::class -->
|
<!-- $o=KrbTicketFlags::class -->
|
||||||
<x-attribute.layout :edit="$edit ?? FALSE" :new="$new ?? FALSE" :o="$o">
|
<x-attribute.layout :edit="$edit ?? FALSE" :new="$new ?? FALSE" :o="$o">
|
||||||
@foreach(($o->values->count() ? $o->values : ($new ? [0] : NULL)) as $value)
|
@foreach(Arr::get(old($o->name_lc,[$langtag=>$o->tagValues($langtag)]),$langtag,[]) as $key => $value)
|
||||||
@if($edit)
|
@if($edit)
|
||||||
<div id="32"></div>
|
<div id="32"></div>
|
||||||
<div id="16"></div>
|
<div id="16"></div>
|
||||||
|
|
||||||
<div class="input-group has-validation mb-3">
|
<div class="input-group has-validation mb-3">
|
||||||
<input type="hidden" @class(['form-control','is-invalid'=>($e=$errors->get($o->name_lc.'.'.$loop->index)),'mb-1','border-focus'=>$o->values->contains($value)]) name="{{ $o->name_lc }}[]" value="{{ $value }}" @readonly(true)>
|
<input type="hidden" name="{{ $o->name_lc }}[{{ $langtag }}][]" value="{{ $value }}" @readonly(true)>
|
||||||
|
|
||||||
<div class="invalid-feedback pb-2">
|
<div class="invalid-feedback pb-2">
|
||||||
@if($e)
|
@if($e=$errors->get($o->name_lc.'.'.$langtag.'.'.$loop->index))
|
||||||
{{ join('|',$e) }}
|
{{ join('|',$e) }}
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@else
|
@else
|
||||||
{{ $value }}
|
{{ $o->render_item_old($langtag.'.'.$key) }}
|
||||||
@endif
|
@endif
|
||||||
@endforeach
|
@endforeach
|
||||||
</x-attribute.layout>
|
</x-attribute.layout>
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
<!-- $o=Attribute::class -->
|
<!-- $o=Attribute/ObjectClass::class -->
|
||||||
<x-attribute.layout :edit="$edit" :new="$new" :o="$o">
|
<x-attribute.layout :edit="$edit" :new="$new" :o="$o" :langtag="$langtag">
|
||||||
@foreach(old($o->name_lc,$o->values) as $value)
|
@foreach(Arr::get(old($o->name_lc,[$langtag=>($new ?? FALSE) ? [NULL] : $o->tagValues($langtag)]),$langtag) as $key => $value)
|
||||||
@if($edit)
|
@if($edit)
|
||||||
<x-attribute.widget.objectclass :o="$o" :edit="$edit" :new="$new" :loop="$loop" :value="$value"/>
|
<x-attribute.widget.objectclass :o="$o" :edit="$edit" :new="$new" :loop="$loop" :value="$value" :langtag="$langtag"/>
|
||||||
@else
|
@else
|
||||||
{{ $value }}
|
{{ $o->render_item_old($langtag.'.'.$key) }}
|
||||||
@if ($o->isStructural($value))
|
@if ($o->isStructural($value))
|
||||||
<input type="hidden" name="{{ $o->name_lc }}[]" value="{{ $value }}">
|
<input type="hidden" name="{{ $o->name_lc }}[{{ $langtag }}][]" value="{{ $value }}">
|
||||||
<span class="float-end">@lang('structural')</span>
|
<span class="float-end">@lang('structural')</span>
|
||||||
@endif
|
@endif
|
||||||
<br>
|
<br>
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
<!-- @todo We are not handling redirect backs yet with updated passwords -->
|
<!-- @todo We are not handling redirect backs yet with updated passwords -->
|
||||||
<!-- $o=Password::class -->
|
<!-- $o=Password::class -->
|
||||||
<x-attribute.layout :edit="$edit ?? FALSE" :new="$new ?? FALSE" :o="$o">
|
<x-attribute.layout :edit="$edit ?? FALSE" :new="$new ?? FALSE" :o="$o" :langtag="$langtag">
|
||||||
@foreach($o->values_old as $value)
|
@foreach($o->tagValuesOld($langtag) as $key => $value)
|
||||||
@if($edit)
|
@if($edit)
|
||||||
<div class="input-group has-validation mb-3">
|
<div class="input-group has-validation mb-3">
|
||||||
<x-form.select id="userpassword_hash_{{$loop->index}}" name="userpassword_hash[]" :value="$o->hash($value)->id()" :options="$helpers" allowclear="false" :disabled="true"/>
|
<x-form.select id="userpassword_hash_{{$loop->index}}" name="userpassword_hash[{{ $langtag }}][]" :value="$o->hash($value)->id()" :options="$helpers" allowclear="false" :disabled="true"/>
|
||||||
<input type="password" @class(['form-control','is-invalid'=>($e=$errors->get($o->name_lc.'.'.$loop->index)),'mb-1','border-focus'=>$o->values->contains($value)]) name="{{ $o->name_lc }}[]" value="{{ md5($value) }}" @readonly(true)>
|
<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)]) name="{{ $o->name_lc }}[{{ $langtag }}][]" value="{{ md5($value) }}" @readonly(true)>
|
||||||
|
|
||||||
<div class="invalid-feedback pb-2">
|
<div class="invalid-feedback pb-2">
|
||||||
@if($e)
|
@if($e)
|
||||||
@ -14,7 +14,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@else
|
@else
|
||||||
{{ (($x=$o->hash($value)) && ($x::id() !== '*clear*')) ? sprintf('{%s}',$x::shortid()) : '' }}{{ str_repeat('*',16) }}
|
{{ $o->render_item_old($langtag.'.'.$key) }}
|
||||||
@endif
|
@endif
|
||||||
@endforeach
|
@endforeach
|
||||||
</x-attribute.layout>
|
</x-attribute.layout>
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
<span id="objectclass_{{$value}}">
|
<span id="objectclass_{{$value}}">
|
||||||
<div class="input-group has-validation">
|
<div class="input-group has-validation">
|
||||||
<!-- @todo Have an "x" to remove the entry, we need an event to process the removal, removing any attribute values along the way -->
|
<!-- @todo Have an "x" to remove the entry, we need an event to process the removal, removing any attribute values along the way -->
|
||||||
<input type="text" @class(['form-control','input-group-end','is-invalid'=>($e=$errors->get($o->name_lc.'.'.$loop->index)),'mb-1','border-focus'=>$o->values->contains($value)]) name="{{ $o->name_lc }}[]" value="{{ $value }}" placeholder="{{ Arr::get($o->values,$loop->index,'['.__('NEW').']') }}" @readonly(true)>
|
<input type="text" @class(['form-control','input-group-end','is-invalid'=>($e=$errors->get($o->name_lc.'.'.$langtag.'.'.$loop->index)),'mb-1','border-focus'=>! $o->tagValuesOld($langtag)->contains($value)]) name="{{ $o->name_lc }}[{{ $langtag }}][]" value="{{ $value }}" placeholder="{{ Arr::get($o->values,$loop->index,'['.__('NEW').']') }}" @readonly(true)>
|
||||||
@if ($o->isStructural($value))
|
@if ($o->isStructural($value))
|
||||||
<span class="input-group-end text-black-50">structural</span>
|
<span class="input-group-end text-black-50">@lang('structural')</span>
|
||||||
@else
|
@else
|
||||||
<span class="input-group-end"><i class="fas fa-fw fa-xmark"></i></span>
|
<span class="input-group-end"><i class="fas fa-fw fa-xmark"></i></span>
|
||||||
@endif
|
@endif
|
||||||
|
@ -3,8 +3,7 @@
|
|||||||
@php($clone=FALSE)
|
@php($clone=FALSE)
|
||||||
<span class="p-0 m-0">
|
<span class="p-0 m-0">
|
||||||
@if($o->is_rdn)
|
@if($o->is_rdn)
|
||||||
<br/>
|
<button class="btn btn-sm btn-outline-focus mt-3" disabled><i class="fas fa-fw fa-exchange"></i> @lang('Rename')</button>
|
||||||
<span class="btn btn-sm btn-outline-focus mt-3" disabled><i class="fas fa-fw fa-exchange"></i> @lang('Rename')</span>
|
|
||||||
@elseif($edit && $o->can_addvalues)
|
@elseif($edit && $o->can_addvalues)
|
||||||
@switch(get_class($o))
|
@switch(get_class($o))
|
||||||
@case(JpegPhoto::class)
|
@case(JpegPhoto::class)
|
||||||
@ -229,8 +228,11 @@
|
|||||||
// Create a new entry when Add Value clicked
|
// Create a new entry when Add Value clicked
|
||||||
$('#{{ $o->name }}-addnew.addable').click(function (item) {
|
$('#{{ $o->name }}-addnew.addable').click(function (item) {
|
||||||
var cln = $(this).parent().parent().find('input:last').parent().clone();
|
var cln = $(this).parent().parent().find('input:last').parent().clone();
|
||||||
cln.find('input:last').attr('value','').attr('placeholder', '[@lang('NEW')]');
|
cln.find('input:last')
|
||||||
cln.appendTo('#'+item.currentTarget.id.replace('-addnew',''));
|
.attr('value','')
|
||||||
|
.attr('placeholder', '[@lang('NEW')]')
|
||||||
|
.addClass('border-focus')
|
||||||
|
.appendTo('#'+item.currentTarget.id.replace('-addnew',''));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
<!-- $o=Attribute::class -->
|
<!-- $o=Attribute::class -->
|
||||||
<x-attribute.layout :edit="false" :new="false" :detail="true" :o="$o">
|
<x-attribute.layout :edit="false" :new="false" :detail="true" :o="$o">
|
||||||
@foreach(old($o->name_lc,($new ?? FALSE) ? [NULL] : $o->values) as $value)
|
@foreach(Arr::get(old($o->name_lc,[$langtag=>$o->tagValues($langtag)]),$langtag,[]) as $value)
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input type="text" @class(['form-control','mb-1']) name="{{ $o->name_lc }}[]" value="{{ \Carbon\Carbon::createFromTimestamp(strtotime($value))->format(config('pla.datetime_format','Y-m-d H:i:s')) }}" @disabled(true)>
|
<input type="text" class="form-control mb-1" value="{{ \Carbon\Carbon::createFromTimestamp(strtotime($value))->format(config('pla.datetime_format','Y-m-d H:i:s')) }}" disabled>
|
||||||
</div>
|
</div>
|
||||||
@endforeach
|
@endforeach
|
||||||
</x-attribute.layout>
|
</x-attribute.layout>
|
@ -1,8 +1,8 @@
|
|||||||
<!-- $o=Attribute::class -->
|
<!-- $o=Attribute::class -->
|
||||||
<x-attribute.layout :edit="false" :new="false" :detail="true" :o="$o">
|
<x-attribute.layout :edit="false" :new="false" :detail="true" :o="$o">
|
||||||
@foreach(old($o->name_lc,($new ?? FALSE) ? [NULL] : $o->values) as $value)
|
@foreach(Arr::get(old($o->name_lc,[$langtag=>$o->tagValues($langtag)]),$langtag,[]) as $value)
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input type="text" @class(['form-control','mb-1']) name="{{ $o->name_lc }}[]" value="{{ $value }}" @disabled(true)>
|
<input type="text" class="form-control mb-1" value="{{ $value }}" disabled>
|
||||||
</div>
|
</div>
|
||||||
@endforeach
|
@endforeach
|
||||||
</x-attribute.layout>
|
</x-attribute.layout>
|
@ -26,10 +26,10 @@
|
|||||||
<x-attribute :o="$o->getObject('entryuuid')" :na="__('Unknown')"/>
|
<x-attribute :o="$o->getObject('entryuuid')" :na="__('Unknown')"/>
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
@if(($x=$o->getLangTags())->count())
|
@if($langtags->count())
|
||||||
<tr class="mt-1">
|
<tr class="mt-1">
|
||||||
<td class="p-0 pe-2">Tags</td>
|
<td class="p-0 pe-2">Tags</td>
|
||||||
<th class="p-0">{{ $x->flatMap(fn($item)=>$item->values())->unique()->join(', ') }}</th>
|
<th class="p-0">{{ $langtags->join(', ') }}</th>
|
||||||
</tr>
|
</tr>
|
||||||
@endif
|
@endif
|
||||||
</table>
|
</table>
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
<div class="row">
|
<div class="row">
|
||||||
|
|
||||||
<div class="col-12 col-xl-3">
|
<div class="col-12 col-xl-3">
|
||||||
<select id="attributetype" class="form-control">
|
<select id="attributetype" class="form-control">
|
||||||
<option value="-all-">-all-</option>
|
<option value="-all-">-all-</option>
|
||||||
|
@ -1,7 +1,12 @@
|
|||||||
|
@use(App\Ldap\Entry)
|
||||||
|
|
||||||
@extends('layouts.dn')
|
@extends('layouts.dn')
|
||||||
|
|
||||||
@section('page_title')
|
@section('page_title')
|
||||||
@include('fragment.dn.header',['o'=>($oo=$server->fetch(old('container',$container)))])
|
@include('fragment.dn.header',[
|
||||||
|
'o'=>($oo=$server->fetch(old('container',$container))),
|
||||||
|
'langtags'=>collect(),
|
||||||
|
])
|
||||||
@endsection
|
@endsection
|
||||||
|
|
||||||
@section('main-content')
|
@section('main-content')
|
||||||
@ -28,7 +33,7 @@
|
|||||||
<div class="col-12 col-md-6">
|
<div class="col-12 col-md-6">
|
||||||
<x-form.select
|
<x-form.select
|
||||||
id="objectclass"
|
id="objectclass"
|
||||||
name="objectclass[]"
|
name="objectclass[{{ Entry::TAG_NOTAG }}][]"
|
||||||
:label="__('Select a Structural ObjectClass...')"
|
:label="__('Select a Structural ObjectClass...')"
|
||||||
:options="($oc=$server->schema('objectclasses'))
|
:options="($oc=$server->schema('objectclasses'))
|
||||||
->filter(fn($item)=>$item->isStructural())
|
->filter(fn($item)=>$item->isStructural())
|
||||||
|
@ -1,7 +1,15 @@
|
|||||||
|
@use(App\Ldap\Entry)
|
||||||
|
|
||||||
@extends('layouts.dn')
|
@extends('layouts.dn')
|
||||||
|
|
||||||
@section('page_title')
|
@section('page_title')
|
||||||
@include('fragment.dn.header',['o'=>($o ?? $o=$server->fetch($dn))])
|
@include('fragment.dn.header',[
|
||||||
|
'o'=>($o ?? $o=$server->fetch($dn)),
|
||||||
|
'langtags'=>($langtags=$o->getLangTags()
|
||||||
|
->flatMap(fn($item)=>$item->values())
|
||||||
|
->unique()
|
||||||
|
->sort())
|
||||||
|
])
|
||||||
@endsection
|
@endsection
|
||||||
|
|
||||||
@section('page_actions')
|
@section('page_actions')
|
||||||
@ -54,10 +62,6 @@
|
|||||||
<div class="ms-4 mt-4 alert alert-danger p-2" style="max-width: 30em; font-size: 0.80em;">
|
<div class="ms-4 mt-4 alert alert-danger p-2" style="max-width: 30em; font-size: 0.80em;">
|
||||||
This entry has multi-language tags used by [<strong>{!! $x->keys()->join('</strong>, <strong>') !!}</strong>] that cant be managed by PLA. You can though manage those lang tags with an LDIF import.
|
This entry has multi-language tags used by [<strong>{!! $x->keys()->join('</strong>, <strong>') !!}</strong>] that cant be managed by PLA. You can though manage those lang tags with an LDIF import.
|
||||||
</div>
|
</div>
|
||||||
@elseif(($x=$o->getLangTags())->count())
|
|
||||||
<div class="ms-4 mt-4 alert alert-warning p-2" style="max-width: 30em; font-size: 0.80em;">
|
|
||||||
This entry has language tags used by [<strong>{!! $x->keys()->join('</strong>, <strong>') !!}</strong>] that cant be managed by PLA yet. You can though manage those lang tags with an LDIF import.
|
|
||||||
</div>
|
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -71,12 +75,9 @@
|
|||||||
<div class="main-card mb-3 card">
|
<div class="main-card mb-3 card">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="card-header-tabs">
|
<div class="card-header-tabs">
|
||||||
<ul class="nav nav-tabs">
|
<ul class="nav nav-tabs mb-0">
|
||||||
<li class="nav-item"><a data-bs-toggle="tab" href="#attributes" class="nav-link active">@lang('Attributes')</a></li>
|
<li class="nav-item"><a data-bs-toggle="tab" href="#attributes" class="nav-link active">@lang('Attributes')</a></li>
|
||||||
<li class="nav-item"><a data-bs-toggle="tab" href="#internal" class="nav-link">@lang('Internal')</a></li>
|
<li class="nav-item"><a data-bs-toggle="tab" href="#internal" class="nav-link">@lang('Internal')</a></li>
|
||||||
@env(['local'])
|
|
||||||
<li class="nav-item"><a data-bs-toggle="tab" href="#debug" class="nav-link">@lang('Debug')</a></li>
|
|
||||||
@endenv
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<div class="tab-content">
|
<div class="tab-content">
|
||||||
@ -86,10 +87,57 @@
|
|||||||
@csrf
|
@csrf
|
||||||
|
|
||||||
<input type="hidden" name="dn" value="">
|
<input type="hidden" name="dn" value="">
|
||||||
|
<div class="card-header border-bottom-0">
|
||||||
|
<div class="btn-actions-pane-right">
|
||||||
|
<div role="group" class="btn-group-sm nav btn-group">
|
||||||
|
@foreach($langtags->prepend(Entry::TAG_NOTAG)->push('+') as $tag)
|
||||||
|
<a data-bs-toggle="tab" href="#tab-lang-{{ $tag ?: '_default' }}" class="btn btn-outline-light border-dark-subtle @if(! $loop->index) active @endif @if($loop->last)ndisabled @endif">
|
||||||
|
@switch($tag)
|
||||||
|
@case(Entry::TAG_NOTAG)
|
||||||
|
<i class="fas fa-fw fa-border-none" data-bs-toggle="tooltip" data-bs-custom-class="custom-tooltip" title="@lang('No Lang Tag')"></i>
|
||||||
|
@break
|
||||||
|
|
||||||
@foreach ($o->getVisibleAttributes() as $ao)
|
@case('+')
|
||||||
<x-attribute-type :edit="true" :o="$ao"/>
|
<!-- @todo To implement -->
|
||||||
|
<i class="fas fa-fw fa-plus text-dark" data-bs-toggle="tooltip" data-bs-custom-class="custom-tooltip" title="@lang('Add Lang Tag')"></i>
|
||||||
|
@break
|
||||||
|
|
||||||
|
@default
|
||||||
|
<span class="f16" data-bs-toggle="tooltip" data-bs-custom-class="custom-tooltip" title="{{ strtoupper($tag) }}"><i class="flag {{ $tag }}"></i></span>
|
||||||
|
@endswitch
|
||||||
|
</a>
|
||||||
@endforeach
|
@endforeach
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="tab-content">
|
||||||
|
@foreach($langtags as $tag)
|
||||||
|
<div class="tab-pane @if(! $loop->index) active @endif" id="tab-lang-{{ $tag ?: '_default' }}" role="tabpanel">
|
||||||
|
@switch($tag)
|
||||||
|
@case(Entry::TAG_NOTAG)
|
||||||
|
@foreach ($o->getVisibleAttributes($tag) as $ao)
|
||||||
|
<x-attribute-type :edit="true" :o="$ao" :langtag="$tag"/>
|
||||||
|
@endforeach
|
||||||
|
@break
|
||||||
|
|
||||||
|
@case('+')
|
||||||
|
<div class="ms-auto mt-4 alert alert-warning p-2" style="max-width: 30em; font-size: 0.80em;">
|
||||||
|
It is not possible to create new language tags at the moment. This functionality should come soon.<br>
|
||||||
|
You can create them with an LDIF import though.
|
||||||
|
</div>
|
||||||
|
@break
|
||||||
|
|
||||||
|
@default
|
||||||
|
@foreach ($o->getVisibleAttributes($langtag=sprintf('lang-%s',$tag)) as $ao)
|
||||||
|
<x-attribute-type :edit="true" :o="$ao" :langtag="$langtag"/>
|
||||||
|
@endforeach
|
||||||
|
@endswitch
|
||||||
|
</div>
|
||||||
|
@endforeach
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
@include('fragment.dn.add_attr')
|
@include('fragment.dn.add_attr')
|
||||||
</form>
|
</form>
|
||||||
@ -103,26 +151,11 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Internal Attributes -->
|
<!-- Internal Attributes -->
|
||||||
<div class="tab-pane" 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"/>
|
<x-attribute-type :o="$ao"/>
|
||||||
@endforeach
|
@endforeach
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Debug -->
|
|
||||||
<div class="tab-pane" id="debug" role="tabpanel">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-4">
|
|
||||||
@dump($o)
|
|
||||||
</div>
|
|
||||||
<div class="col-4">
|
|
||||||
@dump($o->getAttributes())
|
|
||||||
</div>
|
|
||||||
<div class="col-4">
|
|
||||||
@dump(['available'=>$o->getAvailableAttributes()->pluck('name'),'missing'=>$o->getMissingAttributes()->pluck('name')])
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,7 +1,12 @@
|
|||||||
@extends('home')
|
@extends('home')
|
||||||
|
|
||||||
@section('page_title')
|
@section('page_title')
|
||||||
@include('fragment.dn.header')
|
@include('fragment.dn.header',[
|
||||||
|
'langtags'=>($langtags=$o->getLangTags()
|
||||||
|
->flatMap(fn($item)=>$item->values())
|
||||||
|
->unique()
|
||||||
|
->sort())
|
||||||
|
])
|
||||||
@endsection
|
@endsection
|
||||||
|
|
||||||
@section('main-content')
|
@section('main-content')
|
||||||
@ -23,6 +28,7 @@
|
|||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Attribute</th>
|
<th>Attribute</th>
|
||||||
|
<th>Tag</th>
|
||||||
<th>OLD</th>
|
<th>OLD</th>
|
||||||
<th>NEW</th>
|
<th>NEW</th>
|
||||||
</tr>
|
</tr>
|
||||||
@ -31,17 +37,22 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
@foreach ($o->getObjects()->filter(fn($item)=>$item->isDirty()) as $key => $oo)
|
@foreach ($o->getObjects()->filter(fn($item)=>$item->isDirty()) as $key => $oo)
|
||||||
<tr>
|
<tr>
|
||||||
<th rowspan="{{ $x=max($oo->values->keys()->max(),$oo->values_old->keys()->max())+1}}">
|
<th rowspan="{{ $x=max($oo->values->dot()->keys()->count(),$oo->values_old->dot()->keys()->count())+1}}">
|
||||||
<abbr title="{{ $oo->description }}">{{ $oo->name }}</abbr>
|
<abbr title="{{ $oo->description }}">{{ $oo->name }}</abbr>
|
||||||
</th>
|
</th>
|
||||||
@for($xx=0;$xx<$x;$xx++)
|
|
||||||
@if($xx)
|
@foreach($oo->values->dot()->keys()->merge($oo->values_old->dot()->keys())->unique() as $dotkey)
|
||||||
|
@if($loop->index)
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
<td>{{ (($r=$oo->render_item_old($xx)) !== NULL) ? $r : '['.strtoupper(__('New Value')).']' }}</td>
|
<th>
|
||||||
<td>{{ (($r=$oo->render_item_new($xx)) !== NULL) ? $r : '['.strtoupper(__('Deleted')).']' }}<input type="hidden" name="{{ $key }}[]" value="{{ Arr::get($oo->values,$xx) }}"></td>
|
{{ $dotkey }}
|
||||||
@endfor
|
</th>
|
||||||
|
|
||||||
|
<td>{{ (($r=$oo->render_item_old($dotkey)) !== NULL) ? $r : '['.strtoupper(__('New Value')).']' }}</td>
|
||||||
|
<td>{{ (($r=$oo->render_item_new($dotkey)) !== NULL) ? $r : '['.strtoupper(__('Deleted')).']' }}<input type="hidden" name="{{ $key }}[{{ collect(explode('.',$dotkey))->first() }}][]" value="{{ Arr::get($oo,$dotkey) }}"></td>
|
||||||
|
@endforeach
|
||||||
</tr>
|
</tr>
|
||||||
@endforeach
|
@endforeach
|
||||||
</tbody>
|
</tbody>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user