Handle no attribute tags at an Attribute::class level, added form/disabled components

This commit is contained in:
Deon George 2025-03-16 19:29:08 +11:00
parent 1470170928
commit 81e0e58650
22 changed files with 113 additions and 79 deletions

View File

@ -19,6 +19,7 @@ class Attribute implements \Countable, \ArrayAccess, \Iterator
// Is this attribute an internal attribute // Is this attribute an internal attribute
protected(set) bool $is_internal = FALSE; protected(set) bool $is_internal = FALSE;
protected(set) bool $no_attr_tags = FALSE;
// MIN/MAX number of values // MIN/MAX number of values
protected(set) int $min_values_count = 0; protected(set) int $min_values_count = 0;
@ -34,9 +35,9 @@ class Attribute implements \Countable, \ArrayAccess, \Iterator
// The DN this object is in // The DN this object is in
protected(set) string $dn; protected(set) string $dn;
// The old values for this attribute - helps with isDirty() to determine if there is an update pending // The old values for this attribute - helps with isDirty() to determine if there is an update pending
protected(set) Collection $values_old; private Collection $_values_old;
// Current Values // Current Values
protected Collection $values; private Collection $_values;
// The objectclasses of the entry that has this attribute // The objectclasses of the entry that has this attribute
protected(set) Collection $oc; protected(set) Collection $oc;
@ -153,7 +154,10 @@ 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->values, 'values' => $this->no_attr_tags ? collect($this->_values->first()) : $this->_values,
// The original attribute values
'values_old' => $this->no_attr_tags ? collect($this->_values_old->first()) : $this->_values_old,
default => throw new \Exception('Unknown key:' . $key), default => throw new \Exception('Unknown key:' . $key),
}; };
@ -163,8 +167,11 @@ class Attribute implements \Countable, \ArrayAccess, \Iterator
{ {
switch ($key) { switch ($key) {
case 'values': case 'values':
if (is_null($values)) throw new \Exception('values is null?'); $this->_values = $values;
$this->values = $values; break;
case 'values_old':
$this->_values_old = $values;
break; break;
default: default:

View File

@ -28,6 +28,11 @@ class Factory
'entrydn' => Internal\DN::class, 'entrydn' => Internal\DN::class,
'entryuuid' => Internal\UUID::class, 'entryuuid' => Internal\UUID::class,
'etag' => Internal\Etag::class, 'etag' => Internal\Etag::class,
'krblastfailedauth' => Attribute\NoAttrTags\Generic::class,
'krblastpwdchange' => Attribute\NoAttrTags\Generic::class,
'krblastsuccessfulauth' => Attribute\NoAttrTags\Generic::class,
'krbpasswordexpiration' => Attribute\NoAttrTags\Generic::class,
'krbloginfailedcount' => Attribute\NoAttrTags\Generic::class,
'krbprincipalkey' => KrbPrincipalKey::class, 'krbprincipalkey' => KrbPrincipalKey::class,
'krbticketflags' => KrbTicketFlags::class, 'krbticketflags' => KrbTicketFlags::class,
'gidnumber' => GidNumber::class, 'gidnumber' => GidNumber::class,

View File

@ -9,4 +9,5 @@ use App\Classes\LDAP\Attribute;
*/ */
final class GidNumber extends Attribute final class GidNumber extends Attribute
{ {
protected(set) bool $no_attr_tags = FALSE;
} }

View File

@ -12,15 +12,7 @@ use App\Classes\LDAP\Attribute;
abstract class Internal extends Attribute abstract class Internal extends Attribute
{ {
protected(set) bool $is_internal = TRUE; protected(set) bool $is_internal = TRUE;
protected(set) bool $no_attr_tags = TRUE;
public function __get(string $key): mixed
{
return match ($key) {
// Internal items shouldnt have language tags, so our values should only have 1 key
'values'=>collect($this->values->first()),
default => parent::__get($key),
};
}
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): View
{ {

View File

@ -15,6 +15,8 @@ final class KrbPrincipalKey extends Attribute
{ {
use MD5Updates; use MD5Updates;
protected(set) bool $no_attr_tags = TRUE;
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): View
{ {
return view('components.attribute.krbprincipalkey') return view('components.attribute.krbprincipalkey')

View File

@ -13,6 +13,8 @@ use Illuminate\Support\Collection;
*/ */
final class KrbTicketFlags extends Attribute final class KrbTicketFlags extends Attribute
{ {
protected(set) bool $no_attr_tags = TRUE;
private const DISALLOW_POSTDATED = 0x00000001; private const DISALLOW_POSTDATED = 0x00000001;
private const DISALLOW_FORWARDABLE = 0x00000002; private const DISALLOW_FORWARDABLE = 0x00000002;
private const DISALLOW_TGT_BASED = 0x00000004; private const DISALLOW_TGT_BASED = 0x00000004;

View File

@ -0,0 +1,13 @@
<?php
namespace App\Classes\LDAP\Attribute\NoAttrTags;
use App\Classes\LDAP\Attribute;
/**
* Represents an Attribute that doesnt have Lang Tags
*/
class Generic extends Attribute
{
protected(set) bool $no_attr_tags = TRUE;
}

View File

@ -12,6 +12,8 @@ use App\Classes\LDAP\Attribute;
*/ */
final class ObjectClass extends Attribute final class ObjectClass extends Attribute
{ {
protected(set) bool $no_attr_tags = TRUE;
// The schema ObjectClasses for this objectclass of a DN // The schema ObjectClasses for this objectclass of a DN
protected Collection $oc_schema; protected Collection $oc_schema;
@ -21,7 +23,7 @@ final class ObjectClass extends Attribute
* @param string $dn DN this attribute is used in * @param string $dn DN this attribute is used in
* @param string $name Name of the attribute * @param string $name Name of the attribute
* @param array $values Current Values * @param array $values Current Values
* @param array $oc The objectclasses that the DN of this attribute has * @param array $oc The objectclasses that the DN of this attribute has (ignored for objectclasses)
*/ */
public function __construct(string $dn,string $name,array $values,array $oc=[]) public function __construct(string $dn,string $name,array $values,array $oc=[])
{ {
@ -29,7 +31,7 @@ final class ObjectClass extends Attribute
$this->oc_schema = config('server') $this->oc_schema = config('server')
->schema('objectclasses') ->schema('objectclasses')
->filter(fn($item)=>$this->values->merge($this->values_old)->unique()->contains($item->name)); ->filter(fn($item)=>$this->values_old->contains($item->name));
} }
public function __get(string $key): mixed public function __get(string $key): mixed

View File

@ -15,6 +15,9 @@ use App\Traits\MD5Updates;
final class Password extends Attribute final class Password extends Attribute
{ {
use MD5Updates; use MD5Updates;
protected(set) bool $no_attr_tags = TRUE;
private const password_helpers = 'Classes/LDAP/Attribute/Password'; private const password_helpers = 'Classes/LDAP/Attribute/Password';
public const commands = 'App\\Classes\\LDAP\\Attribute\\Password\\'; public const commands = 'App\\Classes\\LDAP\\Attribute\\Password\\';

View File

@ -14,6 +14,7 @@ use App\Classes\LDAP\Attribute;
abstract class Schema extends Attribute abstract class Schema extends Attribute
{ {
protected bool $internal = TRUE; protected bool $internal = TRUE;
protected(set) bool $no_attr_tags = TRUE;
protected static function _get(string $filename,string $string,string $key): ?string protected static function _get(string $filename,string $string,string $key): ?string
{ {
@ -52,15 +53,6 @@ abstract class Schema extends Attribute
__('No description available, can you help with one?')); __('No description available, can you help with one?'));
} }
public function __get(string $key): mixed
{
return match ($key) {
// Schema items shouldnt have language tags, so our values should only have 1 key
'values'=>collect($this->values->first()),
default => parent::__get($key),
};
}
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): View
{ {
// @note Schema attributes cannot be edited // @note Schema attributes cannot be edited

View File

@ -282,6 +282,7 @@ class Entry extends Model
public function getLangTags(): Collection public function getLangTags(): Collection
{ {
return $this->getObjects() return $this->getObjects()
->filter(fn($item)=>! $item->no_attr_tags)
->map(fn($item)=>$item ->map(fn($item)=>$item
->values ->values
->keys() ->keys()
@ -336,6 +337,7 @@ class Entry extends Model
public function getOtherTags(): Collection public function getOtherTags(): Collection
{ {
return $this->getObjects() return $this->getObjects()
->filter(fn($item)=>! $item->no_attr_tags)
->map(fn($item)=>$item ->map(fn($item)=>$item
->values ->values
->keys() ->keys()

View File

@ -1,19 +1,31 @@
<!-- $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 $value) @foreach(old($o->name_lc,($new ?? FALSE) ? [NULL] : $o->values) as $tag=>$tagvalues)
@if (($edit ?? FALSE) && ! $o->is_rdn) <div class="row p-2 border rounded">
<div class="input-group has-validation"> <div class="col-2">
<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))> {{ $tag }}
</div>
<div class="col-10">
<div class="row">
<div class="col-12">
@foreach($tagvalues as $value)
@if(($edit ?? FALSE) && ! $o->is_rdn)
<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))>
<div class="invalid-feedback pb-2"> <div class="invalid-feedback pb-2">
@if($e) @if($e)
{{ join('|',$e) }} {{ join('|',$e) }}
@endif @endif
</div>
</div>
@else
{{ $value }}
@endif
@endforeach
</div>
</div> </div>
</div> </div>
</div>
@else
{{ $value }}
@endif
@endforeach @endforeach
</x-attribute.layout> </x-attribute.layout>

View File

@ -1,8 +1,2 @@
<!-- $o=Attribute::class --> <!-- $o=NoAttrTags/Generic::class -->
<x-attribute.layout :edit="false" :new="false" :detail="true" :o="$o"> @include('components.form.disabled.datetime')
@foreach(old($o->name_lc,($new ?? FALSE) ? [NULL] : $o->values) as $value)
<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)>
</div>
@endforeach
</x-attribute.layout>

View File

@ -1 +1,2 @@
@include('components.attribute.krblastfailedauth') <!-- $o=NoAttrTags/Generic::class -->
@include('components.form.disabled.datetime')

View File

@ -1 +1,2 @@
@include('components.attribute.krblastfailedauth') <!-- $o=NoAttrTags/Generic::class -->
@include('components.form.disabled.datetime')

View File

@ -1,8 +1,2 @@
<!-- $o=Attribute::class --> <!-- $o=NoAttrTags/Generic::class -->
<x-attribute.layout :edit="false" :new="false" :detail="true" :o="$o"> @include('components.form.disabled.input')
@foreach(old($o->name_lc,($new ?? FALSE) ? [NULL] : $o->values) as $value)
<div class="input-group">
<input type="text" @class(['form-control','mb-1']) name="{{ $o->name_lc }}[]" value="{{ $value }}" @disabled(true)>
</div>
@endforeach
</x-attribute.layout>

View File

@ -1 +1,2 @@
@include('components.attribute.krblastfailedauth') <!-- $o=NoAttrTags/Generic::class -->
@include('components.form.disabled.datetime')

View File

@ -1,5 +1,5 @@
<!-- @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=KrbPrincipleKey::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_old as $value) @foreach($o->values_old as $value)
@if($edit) @if($edit)

View File

@ -1,29 +1,23 @@
<!-- $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">
<!-- krbticketflags cannot handle multivalue tags --> @foreach(($o->values->count() ? $o->values : ($new ? [0] : NULL)) as $value)
@if($o->values->keys()->count() <= 1) @if($edit)
@foreach((count($o->values->first()) ? $o->values->first() : ($new ? [0] : NULL)) as $value) <div id="32"></div>
@if($edit) <div id="16"></div>
<div id="32"></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" @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)>
<div class="invalid-feedback pb-2"> <div class="invalid-feedback pb-2">
@if($e) @if($e)
{{ join('|',$e) }} {{ join('|',$e) }}
@endif @endif
</div>
</div> </div>
@else </div>
{{ $value }} @else
@endif {{ $value }}
@endforeach @endif
@endforeach
@else
<x-alert.attribute_tags_cant_manage :tags="$o->values->keys()"/>
@endif
</x-attribute.layout> </x-attribute.layout>
@section($o->name_lc.'-scripts') @section($o->name_lc.'-scripts')

View File

@ -1,7 +1,7 @@
<!-- $o=Attribute::class --> <!-- $o=Attribute::class -->
<x-attribute.layout :edit="$edit" :new="$new" :o="$o"> <x-attribute.layout :edit="$edit" :new="$new" :o="$o">
@foreach(old($o->name_lc,$o->values) as $value) @foreach(old($o->name_lc,$o->values) as $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"/>
@else @else
{{ $value }} {{ $value }}

View File

@ -0,0 +1,8 @@
<!-- $o=Attribute::class -->
<x-attribute.layout :edit="false" :new="false" :detail="true" :o="$o">
@foreach(old($o->name_lc,($new ?? FALSE) ? [NULL] : $o->values) as $value)
<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)>
</div>
@endforeach
</x-attribute.layout>

View File

@ -0,0 +1,8 @@
<!-- $o=Attribute::class -->
<x-attribute.layout :edit="false" :new="false" :detail="true" :o="$o">
@foreach(old($o->name_lc,($new ?? FALSE) ? [NULL] : $o->values) as $value)
<div class="input-group">
<input type="text" @class(['form-control','mb-1']) name="{{ $o->name_lc }}[]" value="{{ $value }}" @disabled(true)>
</div>
@endforeach
</x-attribute.layout>