Compare commits
17 Commits
6d55b52cd4
...
b08de519d4
Author | SHA1 | Date | |
---|---|---|---|
b08de519d4 | |||
6599bb7f4f | |||
d623f3c26d | |||
bd40ab0e84 | |||
3fcb8707d9 | |||
c6e1640752 | |||
917a3c1a0d | |||
148d19bbce | |||
6c501cc29d | |||
2ce0ed8974 | |||
9a6d80986a | |||
fa989b8f10 | |||
4e991db8b1 | |||
181971acc4 | |||
3493504720 | |||
54f27d3d16 | |||
3c0eb876e4 |
43
.env.testing
43
.env.testing
@ -1,50 +1,17 @@
|
||||
APP_NAME=Laravel
|
||||
APP_ENV=dev
|
||||
APP_KEY=base64:KvIecx8zoy6RjcbJM8s98ZKs9IDGUHFVqBRn3Awfmso=
|
||||
APP_ENV=local
|
||||
APP_KEY=
|
||||
APP_DEBUG=true
|
||||
APP_URL=http://localhost
|
||||
|
||||
LOG_CHANNEL=stack
|
||||
LOG_CHANNEL=stderr
|
||||
|
||||
DB_CONNECTION=mysql
|
||||
DB_HOST=127.0.0.1
|
||||
DB_PORT=3306
|
||||
DB_DATABASE=homestead
|
||||
DB_USERNAME=homestead
|
||||
DB_PASSWORD=secret
|
||||
|
||||
BROADCAST_DRIVER=log
|
||||
CACHE_DRIVER=file
|
||||
CACHE_DRIVER=array
|
||||
QUEUE_CONNECTION=sync
|
||||
SESSION_DRIVER=file
|
||||
SESSION_LIFETIME=120
|
||||
|
||||
REDIS_HOST=127.0.0.1
|
||||
REDIS_PASSWORD=null
|
||||
REDIS_PORT=6379
|
||||
|
||||
MAIL_DRIVER=smtp
|
||||
MAIL_HOST=smtp.mailtrap.io
|
||||
MAIL_PORT=2525
|
||||
MAIL_USERNAME=null
|
||||
MAIL_PASSWORD=null
|
||||
MAIL_ENCRYPTION=null
|
||||
|
||||
AWS_ACCESS_KEY_ID=
|
||||
AWS_SECRET_ACCESS_KEY=
|
||||
AWS_DEFAULT_REGION=us-east-1
|
||||
AWS_BUCKET=
|
||||
|
||||
PUSHER_APP_ID=
|
||||
PUSHER_APP_KEY=
|
||||
PUSHER_APP_SECRET=
|
||||
PUSHER_APP_CLUSTER=mt1
|
||||
|
||||
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
|
||||
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
|
||||
|
||||
LDAP_HOST=test_ldap
|
||||
LDAP_PORT=389
|
||||
LDAP_HOST=openldap
|
||||
LDAP_BASE_DN="dc=Test"
|
||||
LDAP_USERNAME="cn=admin,dc=Test"
|
||||
LDAP_PASSWORD="test"
|
||||
|
@ -3,7 +3,7 @@ run-name: ${{ gitea.actor }} Building Docker Image 🐳
|
||||
on: [push]
|
||||
env:
|
||||
DOCKER_HOST: tcp://127.0.0.1:2375
|
||||
ASSETS: 10eca55
|
||||
ASSETS: 3fcb8707
|
||||
|
||||
jobs:
|
||||
test:
|
||||
|
@ -106,11 +106,17 @@ class Attribute implements \Countable, \ArrayAccess
|
||||
$this->_values = collect($values);
|
||||
$this->_values_old = collect($values);
|
||||
|
||||
$this->oc = collect($oc);
|
||||
|
||||
$this->schema = (new Server)
|
||||
$this->schema = config('server')
|
||||
->schema('attributetypes',$name);
|
||||
|
||||
$this->oc = collect();
|
||||
|
||||
// Get the objectclass heirarchy for required attribute determination
|
||||
foreach ($oc as $objectclass) {
|
||||
$this->oc->push($objectclass);
|
||||
$this->oc = $this->oc->merge(config('server')->schema('objectclasses',$objectclass)->getParents()->pluck('name'));
|
||||
}
|
||||
|
||||
/*
|
||||
# Should this attribute be hidden
|
||||
if ($server->isAttrHidden($this->name))
|
||||
@ -142,6 +148,13 @@ class Attribute implements \Countable, \ArrayAccess
|
||||
'description' => $this->schema ? $this->schema->{$key} : NULL,
|
||||
// Attribute hints
|
||||
'hints' => $this->hints(),
|
||||
// Attribute language tags
|
||||
'langtags' => ($this->no_attr_tags || (! $this->_values->count()))
|
||||
? collect(Entry::TAG_NOTAG)
|
||||
: $this->_values
|
||||
->keys()
|
||||
->filter(fn($item)=>($item === Entry::TAG_NOTAG) || preg_match(sprintf('/%s;?/',Entry::TAG_CHARS_LANG),$item))
|
||||
->sortBy(fn($item)=>($item === Entry::TAG_NOTAG) ? NULL : $item),
|
||||
// Can this attribute be edited
|
||||
'is_editable' => $this->schema ? $this->schema->{$key} : NULL,
|
||||
// Is this an internal attribute
|
||||
@ -161,7 +174,7 @@ class Attribute implements \Countable, \ArrayAccess
|
||||
// The current attribute values
|
||||
'values' => ($this->no_attr_tags || $this->is_internal) ? $this->tagValues() : $this->_values,
|
||||
// The original attribute values
|
||||
'values_old' => $this->no_attr_tags ? $this->tagValuesOld() : $this->_values_old,
|
||||
'values_old' => ($this->no_attr_tags || $this->is_internal) ? $this->tagValuesOld() : $this->_values_old,
|
||||
|
||||
default => throw new \Exception('Unknown key:' . $key),
|
||||
};
|
||||
@ -192,17 +205,23 @@ class Attribute implements \Countable, \ArrayAccess
|
||||
|
||||
public function count(): int
|
||||
{
|
||||
return $this->_values->dot()->count();
|
||||
return $this->_values
|
||||
->dot()
|
||||
->count();
|
||||
}
|
||||
|
||||
public function offsetExists(mixed $offset): bool
|
||||
{
|
||||
return $this->_values->dot()->has($offset);
|
||||
return $this->_values
|
||||
->dot()
|
||||
->has($offset);
|
||||
}
|
||||
|
||||
public function offsetGet(mixed $offset): mixed
|
||||
{
|
||||
return $this->_values->dot()->get($offset);
|
||||
return $this->_values
|
||||
->dot()
|
||||
->get($offset);
|
||||
}
|
||||
|
||||
public function offsetSet(mixed $offset, mixed $value): void
|
||||
@ -309,11 +328,10 @@ class Attribute implements \Countable, \ArrayAccess
|
||||
* @param bool $edit Render an edit form
|
||||
* @param bool $old Use old value
|
||||
* @param bool $new Enable adding values
|
||||
* @param string $langtag Langtag to use when rendering these attribute values
|
||||
* @param bool $updated Has the entry been updated (uses rendering highlights))
|
||||
* @return View
|
||||
*/
|
||||
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,string $langtag=Entry::TAG_NOTAG,bool $updated=FALSE): View
|
||||
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,bool $updated=FALSE): View
|
||||
{
|
||||
if ($this->is_internal)
|
||||
// @note Internal attributes cannot be edited
|
||||
@ -334,10 +352,15 @@ class Attribute implements \Countable, \ArrayAccess
|
||||
->with('edit',$edit)
|
||||
->with('old',$old)
|
||||
->with('new',$new)
|
||||
->with('langtag',$langtag)
|
||||
->with('updated',$updated);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the value of the original old values
|
||||
*
|
||||
* @param string $dotkey
|
||||
* @return string|null
|
||||
*/
|
||||
public function render_item_old(string $dotkey): ?string
|
||||
{
|
||||
return match ($this->schema->syntax_oid) {
|
||||
@ -348,6 +371,12 @@ class Attribute implements \Countable, \ArrayAccess
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the value of the new values, which would include any pending udpates
|
||||
*
|
||||
* @param string $dotkey
|
||||
* @return string|null
|
||||
*/
|
||||
public function render_item_new(string $dotkey): ?string
|
||||
{
|
||||
return Arr::get($this->values->dot(),$dotkey);
|
||||
@ -358,7 +387,7 @@ class Attribute implements \Countable, \ArrayAccess
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function required(): Collection
|
||||
private function required(): Collection
|
||||
{
|
||||
// If we dont have any objectclasses then we cant know if it is required
|
||||
return $this->oc->count()
|
||||
@ -366,6 +395,12 @@ class Attribute implements \Countable, \ArrayAccess
|
||||
: collect();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the new values for this attribute, which would include any pending updates
|
||||
*
|
||||
* @param string $tag
|
||||
* @return Collection
|
||||
*/
|
||||
public function tagValues(string $tag=Entry::TAG_NOTAG): Collection
|
||||
{
|
||||
return collect($this->_values
|
||||
@ -373,6 +408,12 @@ class Attribute implements \Countable, \ArrayAccess
|
||||
->get($tag,[]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the original values for this attribute, as stored in the LDAP server
|
||||
*
|
||||
* @param string $tag
|
||||
* @return Collection
|
||||
*/
|
||||
public function tagValuesOld(string $tag=Entry::TAG_NOTAG): Collection
|
||||
{
|
||||
return collect($this->_values_old
|
||||
|
@ -15,14 +15,13 @@ final class JpegPhoto extends Binary
|
||||
{
|
||||
use MD5Updates;
|
||||
|
||||
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,string $langtag=Entry::TAG_NOTAG,bool $updated=FALSE): View
|
||||
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,bool $updated=FALSE): View
|
||||
{
|
||||
return view('components.attribute.binary.jpegphoto')
|
||||
->with('o',$this)
|
||||
->with('edit',$edit)
|
||||
->with('old',$old)
|
||||
->with('new',$new)
|
||||
->with('langtag',$langtag)
|
||||
->with('updated',$updated)
|
||||
->with('f',new \finfo);
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ use App\Ldap\Entry;
|
||||
*/
|
||||
final class Timestamp extends Internal
|
||||
{
|
||||
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,string $langtag=Entry::TAG_NOTAG,bool $updated=FALSE): View
|
||||
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,bool $updated=FALSE): View
|
||||
{
|
||||
// @note Internal attributes cannot be edited
|
||||
return view('components.attribute.internal.timestamp')
|
||||
|
@ -17,7 +17,7 @@ final class KrbPrincipalKey extends Attribute
|
||||
|
||||
protected(set) bool $no_attr_tags = TRUE;
|
||||
|
||||
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,string $langtag=Entry::TAG_NOTAG,bool $updated=FALSE): View
|
||||
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,bool $updated=FALSE): View
|
||||
{
|
||||
return view('components.attribute.krbprincipalkey')
|
||||
->with('o',$this)
|
||||
|
@ -50,7 +50,7 @@ final class KrbTicketFlags extends Attribute
|
||||
return $helpers;
|
||||
}
|
||||
|
||||
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,string $langtag=Entry::TAG_NOTAG,bool $updated=FALSE): View
|
||||
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,bool $updated=FALSE): View
|
||||
{
|
||||
return view('components.attribute.krbticketflags')
|
||||
->with('o',$this)
|
||||
|
@ -70,7 +70,7 @@ final class ObjectClass extends Attribute
|
||||
->contains($value);
|
||||
}
|
||||
|
||||
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,string $langtag=Entry::TAG_NOTAG,bool $updated=FALSE): View
|
||||
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,bool $updated=FALSE): View
|
||||
{
|
||||
return view('components.attribute.objectclass')
|
||||
->with('o',$this)
|
||||
|
@ -80,7 +80,7 @@ final class Password extends Attribute
|
||||
return ($helpers=static::helpers())->has($id) ? new ($helpers->get($id)) : NULL;
|
||||
}
|
||||
|
||||
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,string $langtag=Entry::TAG_NOTAG,bool $updated=FALSE): View
|
||||
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,bool $updated=FALSE): View
|
||||
{
|
||||
return view('components.attribute.password')
|
||||
->with('o',$this)
|
||||
|
@ -14,6 +14,9 @@ use App\Ldap\Entry;
|
||||
final class RDN extends Attribute
|
||||
{
|
||||
private string $base;
|
||||
|
||||
protected(set) bool $no_attr_tags = TRUE;
|
||||
|
||||
private Collection $attrs;
|
||||
|
||||
public function __get(string $key): mixed
|
||||
@ -32,7 +35,7 @@ final class RDN extends Attribute
|
||||
]);
|
||||
}
|
||||
|
||||
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,string $langtag=Entry::TAG_NOTAG,bool $updated=FALSE): View
|
||||
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,bool $updated=FALSE): View
|
||||
{
|
||||
return view('components.attribute.rdn')
|
||||
->with('o',$this);
|
||||
|
@ -54,7 +54,7 @@ abstract class Schema extends Attribute
|
||||
__('No description available, can you help with one?'));
|
||||
}
|
||||
|
||||
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,string $langtag=Entry::TAG_NOTAG,bool $updated=FALSE): View
|
||||
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,bool $updated=FALSE): View
|
||||
{
|
||||
// @note Schema attributes cannot be edited
|
||||
return view('components.attribute.internal')
|
||||
|
@ -12,7 +12,7 @@ use App\Ldap\Entry;
|
||||
*/
|
||||
class Generic extends Schema
|
||||
{
|
||||
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,string $langtag=Entry::TAG_NOTAG,bool $updated=FALSE): View
|
||||
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,bool $updated=FALSE): View
|
||||
{
|
||||
// @note Schema attributes cannot be edited
|
||||
return view('components.attribute.schema.generic')
|
||||
|
@ -34,7 +34,7 @@ final class Mechanisms extends Schema
|
||||
return parent::_get(config_path('ldap_supported_saslmechanisms.txt'),$string,$key);
|
||||
}
|
||||
|
||||
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,string $langtag=Entry::TAG_NOTAG,bool $updated=FALSE): View
|
||||
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,bool $updated=FALSE): View
|
||||
{
|
||||
// @note Schema attributes cannot be edited
|
||||
return view('components.attribute.schema.mechanisms')
|
||||
|
@ -35,7 +35,7 @@ final class OID extends Schema
|
||||
return parent::_get(config_path('ldap_supported_oids.txt'),$string,$key);
|
||||
}
|
||||
|
||||
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,string $langtag=Entry::TAG_NOTAG,bool $updated=FALSE): View
|
||||
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,bool $updated=FALSE): View
|
||||
{
|
||||
// @note Schema attributes cannot be edited
|
||||
return view('components.attribute.schema.oid')
|
||||
|
@ -3,6 +3,7 @@
|
||||
namespace App\Classes\LDAP;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use LdapRecord\LdapRecordException;
|
||||
|
||||
use App\Exceptions\Import\GeneralException;
|
||||
@ -16,6 +17,8 @@ use App\Ldap\Entry;
|
||||
*/
|
||||
abstract class Import
|
||||
{
|
||||
private const LOGKEY = 'aI-';
|
||||
|
||||
// Valid LDIF commands
|
||||
protected const LDAP_IMPORT_ADD = 1;
|
||||
protected const LDAP_IMPORT_DELETE = 2;
|
||||
@ -57,6 +60,8 @@ abstract class Import
|
||||
$o->save();
|
||||
|
||||
} catch (LdapRecordException $e) {
|
||||
Log::error(sprintf('%s:Import Commit Error',self::LOGKEY),['e'=>$e->getMessage(),'detailed'=>$e->getDetailedError()]);
|
||||
|
||||
if ($e->getDetailedError())
|
||||
return collect([
|
||||
'dn'=>$o->getDN(),
|
||||
@ -76,6 +81,8 @@ abstract class Import
|
||||
]);
|
||||
}
|
||||
|
||||
Log::debug(sprintf('%s:Import Commited',self::LOGKEY));
|
||||
|
||||
return collect(['dn'=>$o->getDN(),'result'=>__('Created')]);
|
||||
|
||||
default:
|
||||
|
@ -35,7 +35,7 @@ class LDIF extends Import
|
||||
// @todo When renaming DNs, the hotlink should point to the new entry on success, or the old entry on failure.
|
||||
foreach (preg_split('/(\r?\n|\r)/',$this->input) as $line) {
|
||||
$c++;
|
||||
Log::debug(sprintf('%s: LDIF Line [%s]',self::LOGKEY,$line));
|
||||
Log::debug(sprintf('%s:LDIF Line [%s]',self::LOGKEY,$line));
|
||||
$line = trim($line);
|
||||
|
||||
// If the line starts with a comment, ignore it
|
||||
@ -48,7 +48,7 @@ class LDIF extends Import
|
||||
// Add the last attribute;
|
||||
$o->addAttributeItem($attribute,$base64encoded ? base64_decode($value) : $value);
|
||||
|
||||
Log::debug(sprintf('%s: Committing Entry [%s]',self::LOGKEY,$o->getDN()));
|
||||
Log::debug(sprintf('%s:- Committing Entry [%s]',self::LOGKEY,$o->getDN()));
|
||||
|
||||
// Commit
|
||||
$result->push($this->commit($o,$action));
|
||||
@ -95,7 +95,7 @@ class LDIF extends Import
|
||||
// If $m is NULL, then this is the 2nd (or more) line of a base64 encoded value
|
||||
if (! $m) {
|
||||
$value .= $line;
|
||||
Log::debug(sprintf('%s: Attribute [%s] adding [%s] (%d)',self::LOGKEY,$attribute,$line,$c));
|
||||
Log::debug(sprintf('%s:- Attribute [%s] adding [%s] (%d)',self::LOGKEY,$attribute,$line,$c));
|
||||
|
||||
// add to last attr value
|
||||
continue 2;
|
||||
@ -108,7 +108,7 @@ class LDIF extends Import
|
||||
throw new GeneralException(sprintf('Previous Entry not complete? (line %d)',$c));
|
||||
|
||||
$dn = $base64encoded ? base64_decode($value) : $value;
|
||||
Log::debug(sprintf('%s: Creating new entry:',self::LOGKEY,$dn));
|
||||
Log::debug(sprintf('%s:Creating new entry:',self::LOGKEY,$dn));
|
||||
//$o = Entry::find($dn);
|
||||
|
||||
// If it doesnt exist, we'll create it
|
||||
@ -120,7 +120,7 @@ class LDIF extends Import
|
||||
$action = self::LDAP_IMPORT_ADD;
|
||||
|
||||
} else {
|
||||
Log::debug(sprintf('%s: Adding Attribute [%s] value [%s] (%d)',self::LOGKEY,$attribute,$value,$c));
|
||||
Log::debug(sprintf('%s:Adding Attribute [%s] value [%s] (%d)',self::LOGKEY,$attribute,$value,$c));
|
||||
|
||||
if ($value)
|
||||
$o->addAttributeItem($attribute,$base64encoded ? base64_decode($value) : $value);
|
||||
@ -134,7 +134,7 @@ class LDIF extends Import
|
||||
$attribute = $m[1];
|
||||
$value = $m[3];
|
||||
|
||||
Log::debug(sprintf('%s: New Attribute [%s] with [%s] (%d)',self::LOGKEY,$attribute,$value,$c));
|
||||
Log::debug(sprintf('%s:- New Attribute [%s] with [%s] (%d)',self::LOGKEY,$attribute,$value,$c));
|
||||
}
|
||||
|
||||
if ($version !== 1)
|
||||
@ -146,7 +146,7 @@ class LDIF extends Import
|
||||
// Add the last attribute;
|
||||
$o->addAttributeItem($attribute,$base64encoded ? base64_decode($value) : $value);
|
||||
|
||||
Log::debug(sprintf('%s: Committing Entry [%s]',self::LOGKEY,$o->getDN()));
|
||||
Log::debug(sprintf('%s:- Committing Entry [%s]',self::LOGKEY,$o->getDN()));
|
||||
|
||||
// Commit
|
||||
$result->push($this->commit($o,$action));
|
||||
|
@ -204,7 +204,7 @@ final class Server
|
||||
default => TRUE,
|
||||
};
|
||||
|
||||
Log::debug(sprintf('%s:%s - %s',self::LOGKEY,$cache ? 'Caching' : 'Not Cached',$dn));
|
||||
Log::debug(sprintf('%s:%s - %s',self::LOGKEY,$cache ? 'DN CACHEABLE' : 'DN NOT cacheable',$dn));
|
||||
return $cache;
|
||||
}
|
||||
|
||||
@ -216,7 +216,7 @@ final class Server
|
||||
private static function cachetime(): Carbon
|
||||
{
|
||||
return Carbon::now()
|
||||
->addSeconds(Config::get('ldap.cache.time'));
|
||||
->addSeconds(Config::get('ldap.cache.time') ?: 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -232,7 +232,8 @@ final class Server
|
||||
->setDN($dn)
|
||||
->cache(
|
||||
until: self::cachetime(),
|
||||
flush: self::cacheflush($dn))
|
||||
flush: self::cacheflush($dn)
|
||||
)
|
||||
->select($attrs);
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,7 @@ use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
use Illuminate\Support\Facades\File;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Redirect;
|
||||
use LdapRecord\Exceptions\InsufficientAccessException;
|
||||
use LdapRecord\LdapRecordException;
|
||||
@ -114,7 +115,7 @@ class HomeController extends Controller
|
||||
$o = new Entry;
|
||||
$o->setDn($dn);
|
||||
|
||||
foreach ($request->except(['_token','key','step','rdn','rdn_value']) as $key => $value)
|
||||
foreach ($request->except(['_token','key','step','rdn','rdn_value','userpassword_hash']) as $key => $value)
|
||||
$o->{$key} = array_filter($value);
|
||||
|
||||
try {
|
||||
@ -355,7 +356,9 @@ class HomeController extends Controller
|
||||
return Redirect::to('/')
|
||||
->withInput()
|
||||
->with('updated',collect($dirty)
|
||||
->map(fn($item,$key)=>$o->getObject(collect(explode(';',$key))->first())));
|
||||
->map(fn($item,$key)=>$o->getObject(collect(explode(';',$key))->first()))
|
||||
->values()
|
||||
->unique());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -435,6 +438,7 @@ class HomeController extends Controller
|
||||
switch ($type) {
|
||||
case 'ldif':
|
||||
$import = new LDIFImport($x=($request->text ?: $request->file->get()));
|
||||
Log::debug('Processing LDIF import',['data'=>$x,'import'=>$import]);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -6,7 +6,6 @@ use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
use LdapRecord\Support\Arr;
|
||||
use LdapRecord\Models\Model;
|
||||
use LdapRecord\Query\Model\Builder;
|
||||
|
||||
use App\Classes\LDAP\Attribute;
|
||||
use App\Classes\LDAP\Attribute\Factory;
|
||||
@ -22,11 +21,16 @@ use App\Exceptions\InvalidUsage;
|
||||
class Entry extends Model
|
||||
{
|
||||
private const TAG_CHARS = 'a-zA-Z0-9-';
|
||||
private const TAG_CHARS_LANG = 'lang-['.self::TAG_CHARS.']';
|
||||
public const LANG_TAG_PREFIX = 'lang-';
|
||||
public const TAG_CHARS_LANG = self::LANG_TAG_PREFIX.'['.self::TAG_CHARS.']+';
|
||||
public const TAG_NOTAG = '_null_';
|
||||
|
||||
// Our Attribute objects
|
||||
private Collection $objects;
|
||||
|
||||
// Templates that apply to this entry
|
||||
private(set) Collection $templates;
|
||||
|
||||
// For new entries, this is the container that this entry will be stored in
|
||||
private string $rdnbase;
|
||||
|
||||
@ -35,6 +39,7 @@ class Entry extends Model
|
||||
public function __construct(array $attributes = [])
|
||||
{
|
||||
$this->objects = collect();
|
||||
$this->templates = collect(['default'=>__('LDAP Entry')]);
|
||||
|
||||
parent::__construct($attributes);
|
||||
}
|
||||
@ -309,14 +314,7 @@ class Entry extends Model
|
||||
public function getLangTags(): Collection
|
||||
{
|
||||
return $this->getObjects()
|
||||
->filter(fn($item)=>! $item->no_attr_tags)
|
||||
->map(fn($item)=>$item
|
||||
->values
|
||||
->keys()
|
||||
->filter(fn($item)=>preg_match(sprintf('/%s+;?/',self::TAG_CHARS_LANG),$item))
|
||||
->map(fn($item)=>preg_replace('/lang-/','',$item))
|
||||
)
|
||||
->filter(fn($item)=>$item->count());
|
||||
->map(fn($item)=>$item->langtags);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -374,7 +372,7 @@ class Entry extends Model
|
||||
$item && collect(explode(';',$item))->filter(
|
||||
fn($item)=>
|
||||
(! preg_match(sprintf('/^%s$/',self::TAG_NOTAG),$item))
|
||||
&& (! preg_match(sprintf('/^%s+$/',self::TAG_CHARS_LANG),$item))
|
||||
&& (! preg_match(sprintf('/^%s$/',self::TAG_CHARS_LANG),$item))
|
||||
)
|
||||
->count())
|
||||
)
|
||||
|
@ -17,7 +17,10 @@ class LoginObjectclassRule implements Rule
|
||||
public function passes(LdapRecord $user,?Eloquent $model=NULL): bool
|
||||
{
|
||||
if ($x=config('pla.login.objectclass')) {
|
||||
return count(array_intersect($user->objectclass,$x));
|
||||
return count(array_intersect(
|
||||
array_map('strtolower',$user?->objectclass ?: []),
|
||||
array_map('strtolower',$x)
|
||||
));
|
||||
|
||||
// Otherwise allow the user to login
|
||||
} else {
|
||||
|
@ -6,7 +6,6 @@ use Illuminate\Contracts\View\View;
|
||||
use Illuminate\View\Component;
|
||||
|
||||
use App\Classes\LDAP\Attribute as LDAPAttribute;
|
||||
use App\Ldap\Entry;
|
||||
|
||||
class Attribute extends Component
|
||||
{
|
||||
@ -14,18 +13,17 @@ class Attribute extends Component
|
||||
public bool $edit;
|
||||
public bool $new;
|
||||
public bool $old;
|
||||
public string $langtag;
|
||||
public bool $updated;
|
||||
|
||||
/**
|
||||
* Create a new component instance.
|
||||
*/
|
||||
public function __construct(?LDAPAttribute $o,bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,string $langtag=Entry::TAG_NOTAG,bool $updated=FALSE)
|
||||
public function __construct(?LDAPAttribute $o,bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE,bool $updated=FALSE)
|
||||
{
|
||||
$this->o = $o;
|
||||
$this->edit = $edit;
|
||||
$this->old = $old;
|
||||
$this->new = $new;
|
||||
$this->langtag = $langtag;
|
||||
$this->updated = $updated;
|
||||
}
|
||||
|
||||
@ -38,7 +36,7 @@ class Attribute extends Component
|
||||
{
|
||||
return $this->o
|
||||
? $this->o
|
||||
->render(edit: $this->edit,old: $this->old,new: $this->new,langtag: $this->langtag,updated: $this->updated)
|
||||
->render(edit: $this->edit,old: $this->old,new: $this->new,updated: $this->updated)
|
||||
: __('Unknown');
|
||||
}
|
||||
}
|
@ -16,8 +16,8 @@ return Application::configure(basePath: dirname(__DIR__))
|
||||
$middleware->appendToGroup(
|
||||
group: 'web',
|
||||
middleware: [
|
||||
AllowAnonymous::class,
|
||||
ApplicationSession::class,
|
||||
AllowAnonymous::class,
|
||||
SwapinAuthUser::class,
|
||||
ViewVariables::class,
|
||||
CheckUpdate::class,
|
||||
|
@ -10,7 +10,7 @@
|
||||
"ext-openssl": "*",
|
||||
"php": "^8.4",
|
||||
"directorytree/ldaprecord-laravel": "^3.0",
|
||||
"laravel/framework": "^11.9",
|
||||
"laravel/framework": "^12.0",
|
||||
"laravel/sanctum": "^4.0",
|
||||
"laravel/ui": "^4.5"
|
||||
},
|
||||
|
584
composer.lock
generated
584
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@ -7,7 +7,6 @@ php=${PHP_DIR:-/app}
|
||||
composer=${COMPOSER_HOME:-/var/cache/composer}
|
||||
|
||||
SITE_USER=${SITE_USER:-www-data}
|
||||
MEMCACHED_START=${MEMCACHED_START:-FALSE}
|
||||
RUN_USER=$(id -u)
|
||||
[ "${RUN_USER}" = "0" ] && USE_SU=1
|
||||
|
||||
@ -40,12 +39,6 @@ echo "* Started with [$@]"
|
||||
# Run any container setup
|
||||
[ -x /sbin/init-container ] && /sbin/init-container
|
||||
|
||||
# General Setup
|
||||
if [ -x /usr/bin/memcached -a "${MEMCACHED_START}" == "TRUE" ]; then
|
||||
echo "* Starting MEMCACHED..."
|
||||
/usr/bin/memcached -d -P /run/memcached/memcached.pid -u memcached
|
||||
fi
|
||||
|
||||
# Laravel Specific
|
||||
if [ -r artisan -a -e ${php}/.env ]; then
|
||||
echo "* Laravel Setup..."
|
||||
|
1082
package-lock.json
generated
1082
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -1 +1 @@
|
||||
v2.1.3-rel
|
||||
v2.2.0-dev
|
||||
|
20
public/css/custom.css
vendored
20
public/css/custom.css
vendored
@ -1,23 +1,24 @@
|
||||
/** ensure our userpassword has select is next to the password input */
|
||||
attribute#userPassword .select2-container--bootstrap-5 .select2-selection {
|
||||
attribute#userpassword .select2-container--bootstrap-5 .select2-selection {
|
||||
font-size: inherit;
|
||||
width: 9em;
|
||||
border: var(--bs-gray-500) 1px solid;
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
|
||||
.input-group:first-child .select2-container--bootstrap-5 .select2-selection {
|
||||
border-bottom-right-radius: unset;
|
||||
border-top-right-radius: unset;
|
||||
}
|
||||
|
||||
attribute#objectClass .input-group-end:not(input.form-control) {
|
||||
/* render the structural inside the input box */
|
||||
attribute#objectclass .input-group-end:not(input.form-control) {
|
||||
position: absolute;
|
||||
right: 1em;
|
||||
top: 0.5em;
|
||||
z-index: 5;
|
||||
}
|
||||
|
||||
.input-group:first-child .select2-container--bootstrap-5 .select2-selection {
|
||||
border-bottom-right-radius: unset;
|
||||
border-top-right-radius: unset;
|
||||
}
|
||||
|
||||
input.form-control.input-group-end {
|
||||
border-bottom-right-radius: 4px !important;
|
||||
border-top-right-radius: 4px !important;
|
||||
@ -82,4 +83,9 @@ input.form-control.input-group-end {
|
||||
|
||||
.page-title-wrapper .page-title-items .page-title-status .alert {
|
||||
font-size: 0.80em;
|
||||
}
|
||||
|
||||
/* Square UL items */
|
||||
ul.square {
|
||||
list-style-type: square;
|
||||
}
|
@ -90,6 +90,14 @@
|
||||
font-size: 1.3rem !important;
|
||||
}
|
||||
|
||||
.font-size-xs {
|
||||
font-size: .6rem !important;
|
||||
}
|
||||
|
||||
.font-size-sm {
|
||||
font-size: .8rem !important;
|
||||
}
|
||||
|
||||
.font-size-md {
|
||||
font-size: .9rem !important;
|
||||
}
|
||||
|
@ -46,13 +46,13 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if (count($errors) > 0)
|
||||
@if(count($errors) > 0)
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="alert alert-danger m-3">
|
||||
<strong>Whoops!</strong> Something went wrong?<br><br>
|
||||
<ul>
|
||||
@foreach ($errors->all() as $error)
|
||||
@foreach($errors->all() as $error)
|
||||
<li>{{ $error }}</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
|
@ -16,7 +16,7 @@
|
||||
<div class="app-main__outer">
|
||||
<div class="app-main__inner">
|
||||
<div class="main-content">
|
||||
@if (trim($__env->yieldContent('page_title')))
|
||||
@if(trim($__env->yieldContent('page_title')))
|
||||
@include('architect::layouts.partials.contentheader')
|
||||
@endif
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
<div class="app-page-title">
|
||||
<div class="page-title-wrapper bg-white">
|
||||
<div class="page-title-heading">
|
||||
@if (trim($__env->yieldContent('page_icon')))
|
||||
@if(trim($__env->yieldContent('page_icon')))
|
||||
<div class="page-title-icon f32">
|
||||
<i class="@yield('page_icon','')"></i>
|
||||
</div>
|
||||
|
@ -38,7 +38,7 @@
|
||||
<span></span>
|
||||
<div id="searching" class="d-none"><i class="fas fa-fw fa-spinner fa-pulse text-light"></i></div>
|
||||
</button>
|
||||
<div id="search_results" style="height: 300px; overflow: scroll"></div>
|
||||
<div id="search_results" class="overflow-scroll" style="height: 300px;"></div>
|
||||
</div>
|
||||
<button class="btn-close"></button>
|
||||
</div>
|
||||
@ -139,10 +139,10 @@
|
||||
<div class="btn-group">
|
||||
<a data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false" class="p-0 btn">
|
||||
<i class="fas fa-angle-down ms-2 opacity-8"></i>
|
||||
<img width="35" height="35" class="rounded-circle" src="{{ url('user/image') }}" alt="" style="background-color: #eee;padding: 2px;">
|
||||
<img width="35" height="35" class="rounded-circle p-1 bg-light" src="{{ url('user/image') }}" alt="">
|
||||
</a>
|
||||
<div tabindex="-1" role="menu" aria-hidden="true" class="dropdown-menu dropdown-menu-right">
|
||||
@if ($user->exists)
|
||||
@if($user->exists)
|
||||
<h6 tabindex="-1" class="dropdown-header text-center">User Menu</h6>
|
||||
<div tabindex="-1" class="dropdown-divider"></div>
|
||||
<a href="{{ url('logout') }}" tabindex="0" class="dropdown-item">
|
||||
|
@ -1,4 +1,4 @@
|
||||
<div class="alert alert-danger p-0" style="font-size: .80em;">
|
||||
<div class="alert alert-danger font-size-sm p-0">
|
||||
<table class="table table-borderless table-danger p-0 m-0">
|
||||
<tr>
|
||||
<td class="align-top" style="width: 5%;"><i class="fas fa-fw fa-2x fa-exclamation-triangle"></i></td>
|
||||
|
@ -1,23 +1,53 @@
|
||||
@use(App\Ldap\Entry)
|
||||
|
||||
<div class="row pb-3">
|
||||
<div class="col-12 col-sm-1 col-md-2"></div>
|
||||
<div class="col-12 col-sm-10 col-md-8">
|
||||
<div class="col-12 offset-lg-1 col-lg-10">
|
||||
<div class="row">
|
||||
<div class="col-12 bg-light text-dark p-2">
|
||||
<strong><abbr title="{{ $o->description }}">{{ $o->name }}</abbr></strong>
|
||||
<!-- Attribute Hints -->
|
||||
@if($updated)
|
||||
<span class="float-end small text-success ms-2" data-bs-toggle="tooltip" data-bs-custom-class="custom-tooltip-success" title="@lang('Updated')"><i class="fas fa-fw fa-marker"></i> </span>
|
||||
@endif
|
||||
<span class="float-end small">
|
||||
@foreach($o->hints as $name => $description)
|
||||
@if ($loop->index),@endif
|
||||
<abbr title="{{ $description }}">{{ $name }}</abbr>
|
||||
@endforeach
|
||||
<div class="col-12 bg-light text-dark p-2 rounded-2">
|
||||
<span class="d-flex justify-content-between">
|
||||
<span style="width: 20em;">
|
||||
<strong class="align-middle"><abbr title="{{ $o->description }}">{{ $o->name }}</abbr></strong>
|
||||
@if($o->hints->count())
|
||||
<sup>
|
||||
[
|
||||
@foreach($o->hints as $name => $description)
|
||||
@if($loop->index),@endif
|
||||
<abbr title="{{ $description }}">{{ $name }}</abbr>
|
||||
@endforeach
|
||||
]
|
||||
</sup>
|
||||
@endif
|
||||
|
||||
<!-- Attribute Hints -->
|
||||
@if($updated)
|
||||
<span class=" small text-success ms-2" data-bs-toggle="tooltip" data-bs-custom-class="custom-tooltip-success" title="@lang('Updated')"><i class="fas fa-fw fa-marker"></i> </span>
|
||||
@endif
|
||||
</span>
|
||||
|
||||
<div role="group" class="btn-group-sm nav btn-group">
|
||||
@if((! $o->no_attr_tags) && ($has_default=$o->langtags->contains(Entry::TAG_NOTAG)))
|
||||
<span data-bs-toggle="tab" href="#langtag-{{ $o->name_lc }}-{{ Entry::TAG_NOTAG }}" @class(['btn','btn-outline-light','border-dark-subtle','active','addable d-none'=>$o->langtags->count() === 1])>
|
||||
<i class="fas fa-fw fa-border-none" data-bs-toggle="tooltip" data-bs-custom-class="custom-tooltip" aria-label="No Lang Tag" data-bs-original-title="No Lang Tag"></i>
|
||||
</span>
|
||||
@endif
|
||||
|
||||
@if((! $o->no_attr_tags) && (! $o->is_rdn))
|
||||
<span data-bs-toggle="tab" href="#langtag-{{ $o->name_lc }}-+" class="bg-primary-subtle btn btn-outline-primary border-primary addable d-none">
|
||||
<i class="fas fa-fw fa-plus text-dark" data-bs-toggle="tooltip" data-bs-custom-class="custom-tooltip" aria-label="Add Lang Tag" data-bs-original-title="Add Lang Tag"></i>
|
||||
</span>
|
||||
@endif
|
||||
|
||||
@foreach(($langtags=$o->langtags->filter(fn($item)=>$item !== Entry::TAG_NOTAG)) as $langtag)
|
||||
<span data-bs-toggle="tab" href="#langtag-{{ $o->name_lc }}-{{ $langtag }}" @class(['btn','btn-outline-light','border-dark-subtle','active'=>(! isset($has_default)) || (! $has_default) ])>
|
||||
<span class="f16" data-bs-toggle="tooltip" data-bs-custom-class="custom-tooltip" aria-label="{{ $langtag }}" data-bs-original-title="{{ ($x=preg_replace('/'.Entry::LANG_TAG_PREFIX.'/','',$langtag)) }}"><i class="flag {{ $x }}"></i></span>
|
||||
</span>
|
||||
@endforeach
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<x-attribute :o="$o" :edit="$edit" :new="$new" :langtag="$langtag" :updated="$updated"/>
|
||||
<x-attribute :o="$o" :edit="$edit" :new="$new" :updated="$updated"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -1,23 +1,36 @@
|
||||
@use(App\Ldap\Entry)
|
||||
|
||||
<!-- $o=Attribute::class -->
|
||||
<x-attribute.layout :edit="$edit=($edit ?? FALSE)" :new="$new=($new ?? FALSE)" :o="$o">
|
||||
<div class="col-12">
|
||||
@foreach(Arr::get(old($o->name_lc,[$langtag=>$new ? [NULL] : $o->tagValues($langtag)]),$langtag,[]) as $key => $value)
|
||||
@if($edit && (! $o->is_rdn))
|
||||
<div class="input-group has-validation">
|
||||
<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),'bg-success-subtle'=>$updated]) name="{{ $o->name_lc }}[{{ $langtag }}][]" value="{{ $value }}" placeholder="{{ ! is_null($x=$tv->get($loop->index)) ? $x : '['.__('NEW').']' }}" @readonly(! $new) @disabled($o->isDynamic())>
|
||||
<div class="tab-content">
|
||||
@foreach($o->langtags as $langtag)
|
||||
<span @class(['tab-pane','active'=>$loop->index === 0]) id="langtag-{{ $o->name_lc }}-{{ $langtag }}" role="tabpanel">
|
||||
@foreach(Arr::get(old($o->name_lc,[$langtag=>$new ? [NULL] : $o->tagValues($langtag)]),$langtag,[]) as $key => $value)
|
||||
@if($edit && (! $o->is_rdn))
|
||||
<div class="input-group has-validation">
|
||||
<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),'bg-success-subtle'=>$updated]) name="{{ $o->name_lc }}[{{ $langtag }}][]" value="{{ $value }}" placeholder="{{ ! is_null($x=$tv->get($loop->index)) ? $x : '['.__('NEW').']' }}" @readonly(! $new) @disabled($o->isDynamic())>
|
||||
|
||||
<div class="invalid-feedback pb-2">
|
||||
@if($e)
|
||||
{{ join('|',$e) }}
|
||||
<div class="invalid-feedback pb-2">
|
||||
@if($e)
|
||||
{{ join('|',$e) }}
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@else
|
||||
<input type="text" @class(['form-control','mb-1','bg-success-subtle'=>$updated]) value="{{ $value }}" disabled>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</span>
|
||||
@endforeach
|
||||
|
||||
@else
|
||||
<input type="text" @class(['form-control','mb-1','bg-success-subtle'=>$updated]) value="{{ $value }}" disabled>
|
||||
@if($edit && (! $o->is_rdn))
|
||||
<span @class(['tab-pane']) id="langtag-{{ $o->name_lc }}-+" role="tabpanel">
|
||||
<span class="d-flex font-size-sm alert alert-warning p-2">
|
||||
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.
|
||||
</span>
|
||||
</span>
|
||||
@endif
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
</x-attribute.layout>
|
@ -1,3 +1,5 @@
|
||||
@use(App\Ldap\Entry)
|
||||
|
||||
<!-- @todo We are not handling redirect backs yet with updated photos -->
|
||||
<!-- $o=Binary\JpegPhoto::class -->
|
||||
<x-attribute.layout :edit="$edit" :new="$new" :o="$o">
|
||||
@ -8,8 +10,8 @@
|
||||
@case('image/jpeg')
|
||||
@default
|
||||
<td>
|
||||
<input type="hidden" name="{{ $o->name_lc }}[{{ $langtag }}][]" value="{{ md5($value) }}">
|
||||
<img alt="{{ $o->dn }}" @class(['border','rounded','p-2','m-0','is-invalid'=>($e=$errors->get($o->name_lc.'.'.$langtag.'.'.$loop->index)),'bg-success-subtle'=>$updated]) src="data:{{ $x }};base64, {{ base64_encode($value) }}" />
|
||||
<input type="hidden" name="{{ $o->name_lc }}[{{ Entry::TAG_NOTAG }}][]" value="{{ md5($value) }}">
|
||||
<img alt="{{ $o->dn }}" @class(['border','rounded','p-2','m-0','is-invalid'=>($e=$errors->get($o->name_lc.'.'.Entry::TAG_NOTAG.'.'.$loop->index)),'bg-success-subtle'=>$updated]) src="data:{{ $x }};base64, {{ base64_encode($value) }}" />
|
||||
|
||||
@if($edit)
|
||||
<br>
|
||||
|
@ -1,19 +1,20 @@
|
||||
<!-- @todo We are not handling redirect backs yet with updated passwords -->
|
||||
<!-- $o=KrbPrincipleKey::class -->
|
||||
<x-attribute.layout :edit="$edit" :new="$new" :o="$o">
|
||||
@foreach($o->tagValuesOld($langtag) as $key => $value)
|
||||
@if($edit)
|
||||
<div class="input-group has-validation mb-3">
|
||||
<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),'bg-success-subtle'=>$updated]) name="{{ $o->name_lc }}[{{ $langtag }}][]" value="{{ md5($value) }}" @readonly(! $new)>
|
||||
@foreach($o->langtags as $langtag)
|
||||
@foreach(($o->tagValues($langtag)->count() ? $o->tagValues($langtag) : [$langtag => NULL]) as $key => $value)
|
||||
@if($edit)
|
||||
<div class="input-group has-validation mb-3">
|
||||
<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),'bg-success-subtle'=>$updated]) name="{{ $o->name_lc }}[{{ $langtag }}][]" value="{{ Arr::get(old($o->name_lc),$langtag.'.'.$loop->index,$value ? md5($value) : '') }}" @readonly(! $new)>
|
||||
|
||||
<div class="invalid-feedback pb-2">
|
||||
@if($e)
|
||||
{{ join('|',$e) }}
|
||||
@endif
|
||||
<div class="invalid-feedback pb-2">
|
||||
@if($e)
|
||||
{{ join('|',$e) }}
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@else
|
||||
{{ $o->render_item_old($langtag.'.'.$key) }}
|
||||
@endif
|
||||
@else
|
||||
{{ $o->render_item_old($langtag.'.'.$key) }}
|
||||
@endif
|
||||
@endforeach
|
||||
@endforeach
|
||||
</x-attribute.layout>
|
@ -1,22 +1,24 @@
|
||||
<!-- $o=KrbTicketFlags::class -->
|
||||
<x-attribute.layout :edit="$edit" :new="$new" :o="$o">
|
||||
@foreach(Arr::get(old($o->name_lc,[$langtag=>$o->tagValues($langtag)]),$langtag,[]) as $key => $value)
|
||||
@if($edit)
|
||||
<div id="32"></div>
|
||||
<div id="16"></div>
|
||||
@foreach($o->langtags as $langtag)
|
||||
@foreach(($o->tagValues($langtag)->count() ? $o->tagValues($langtag) : [$langtag => NULL]) as $key => $value)
|
||||
@if($edit)
|
||||
<div id="32"></div>
|
||||
<div id="16"></div>
|
||||
|
||||
<div class="input-group has-validation mb-3">
|
||||
<input type="hidden" name="{{ $o->name_lc }}[{{ $langtag }}][]" value="{{ $value }}" @readonly(true)>
|
||||
<div class="input-group has-validation mb-3">
|
||||
<input type="hidden" name="{{ $o->name_lc }}[{{ $langtag }}][]" value="{{ $value }}" @readonly(true)>
|
||||
|
||||
<div class="invalid-feedback pb-2">
|
||||
@if($e=$errors->get($o->name_lc.'.'.$langtag.'.'.$loop->index))
|
||||
{{ join('|',$e) }}
|
||||
@endif
|
||||
<div class="invalid-feedback pb-2">
|
||||
@if($e=$errors->get($o->name_lc.'.'.$langtag.'.'.$loop->index))
|
||||
{{ join('|',$e) }}
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@else
|
||||
{{ $o->render_item_old($langtag.'.'.$key) }}
|
||||
@endif
|
||||
@else
|
||||
{{ $o->render_item_old($langtag.'.'.$key) }}
|
||||
@endif
|
||||
@endforeach
|
||||
@endforeach
|
||||
</x-attribute.layout>
|
||||
|
||||
@ -48,7 +50,7 @@
|
||||
$('div#32').append(binary(31,16));
|
||||
$('div#16').append(binary(15,0));
|
||||
|
||||
$('attribute#krbTicketFlags').find('i')
|
||||
$('attribute#krbticketflags').find('i')
|
||||
.on('click',function() {
|
||||
var item = $(this);
|
||||
if ($('form#dn-edit').attr('readonly'))
|
||||
@ -91,7 +93,7 @@
|
||||
item.data('old',null);
|
||||
}
|
||||
|
||||
$('attribute#krbTicketFlags').find('input').val(value);
|
||||
$('attribute#krbticketflags').find('input').val(value);
|
||||
});
|
||||
}
|
||||
|
||||
@ -102,7 +104,7 @@
|
||||
} else {
|
||||
krbticketflags();
|
||||
|
||||
$('attribute#krbTicketFlags').find('i')
|
||||
$('attribute#krbticketflags').find('i')
|
||||
.tooltip();
|
||||
}
|
||||
</script>
|
||||
|
@ -1,7 +1,7 @@
|
||||
<div class="row pt-2">
|
||||
<div @class(['col-1','d-none'=>(! $edit) && (! ($detail ?? FALSE))])></div>
|
||||
<div class="col-10">
|
||||
<attribute id="{{ $o->name }}">
|
||||
<attribute id="{{ $o->name_lc }}">
|
||||
{{ $slot }}
|
||||
</attribute>
|
||||
|
||||
|
@ -1,15 +1,17 @@
|
||||
<!-- $o=Attribute/ObjectClass::class -->
|
||||
<x-attribute.layout :edit="$edit" :new="$new" :o="$o">
|
||||
@foreach(Arr::get(old($o->name_lc,[$langtag=>$new ? [NULL] : $o->tagValues($langtag)]),$langtag,[]) as $key => $value)
|
||||
@if($edit)
|
||||
<x-attribute.widget.objectclass :o="$o" :edit="$edit" :new="$new" :langtag="$langtag" :updated="$updated" :value="$value" :loop="$loop" />
|
||||
@else
|
||||
{{ $o->render_item_old($key) }}
|
||||
@if ($o->isStructural($value))
|
||||
<input type="hidden" name="{{ $o->name_lc }}[{{ $langtag }}][]" value="{{ $value }}">
|
||||
<span class="float-end">@lang('structural')</span>
|
||||
@foreach($o->langtags as $langtag)
|
||||
@foreach(($o->tagValues($langtag)->count() ? $o->tagValues($langtag) : [$langtag => NULL]) as $key => $value)
|
||||
@if($edit)
|
||||
<x-attribute.widget.objectclass :o="$o" :edit="$edit" :new="$new" :langtag="$langtag" :updated="$updated" :value="$value" :loop="$loop" />
|
||||
@else
|
||||
{{ $o->render_item_old($key) }}
|
||||
@if($o->isStructural($value))
|
||||
<input type="hidden" name="{{ $o->name_lc }}[{{ $langtag }}][]" value="{{ $value }}">
|
||||
<span class="float-end">@lang('structural')</span>
|
||||
@endif
|
||||
<br>
|
||||
@endif
|
||||
<br>
|
||||
@endif
|
||||
@endforeach
|
||||
@endforeach
|
||||
</x-attribute.layout>
|
@ -1,21 +1,22 @@
|
||||
<!-- @todo We are not handling redirect backs yet with updated passwords -->
|
||||
<!-- $o=Password::class -->
|
||||
<x-attribute.layout :edit="$edit" :new="$new" :o="$o">
|
||||
@foreach(Arr::get(old($o->name_lc,[$langtag=>$new ? [NULL] : $o->tagValues($langtag)]),$langtag,[]) as $key => $value)
|
||||
@if($edit)
|
||||
<div class="input-group has-validation mb-3">
|
||||
<x-form.select id="userpassword_hash_{{$loop->index}}" name="userpassword_hash[{{ $langtag }}][]" :value="$o->hash($new ? '' : $value)->id()" :options="$helpers" allowclear="false" :disabled="! $new"/>
|
||||
<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),'bg-success-subtle'=>$updated]) name="{{ $o->name_lc }}[{{ $langtag }}][]" value="{{ md5($value) }}" @readonly(! $new)>
|
||||
@foreach($o->langtags as $langtag)
|
||||
@foreach(($o->tagValues($langtag)->count() ? $o->tagValues($langtag) : [$langtag => NULL]) as $key => $value)
|
||||
@if($edit)
|
||||
<div class="input-group has-validation mb-3">
|
||||
<x-form.select id="userpassword_hash_{{$loop->index}}" name="userpassword_hash[{{ $langtag }}][]" :value="$o->hash($new ? '' : $value)->id()" :options="$helpers" allowclear="false" :disabled="! $new"/>
|
||||
<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),'bg-success-subtle'=>$updated]) name="{{ $o->name_lc }}[{{ $langtag }}][]" value="{{ Arr::get(old($o->name_lc),$langtag.'.'.$loop->index,$value ? md5($value) : '') }}" @readonly(! $new)>
|
||||
|
||||
<div class="invalid-feedback pb-2">
|
||||
@if($e)
|
||||
{{ join('|',$e) }}
|
||||
@endif
|
||||
<div class="invalid-feedback pb-2">
|
||||
@if($e)
|
||||
{{ join('|',$e) }}
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@else
|
||||
{{ $o->render_item_old($langtag.'.'.$key) }}
|
||||
@endif
|
||||
@else
|
||||
{{ $o->render_item_old($langtag.'.'.$key) }}
|
||||
@endif
|
||||
@endforeach
|
||||
@endforeach
|
||||
</x-attribute.layout>
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
<!-- $o=RDN::class -->
|
||||
<x-attribute.layout :edit="$edit" :new="$new" :o="$o">
|
||||
@foreach(($o->values->count() ? $o->values : ['']) as $value)
|
||||
@foreach(($o->values->count() ? $o->values : [NULL]) as $value)
|
||||
@if($edit)
|
||||
<div class="input-group has-validation mb-3">
|
||||
<select class="form-select @error('rdn')is-invalid @enderror" id="rdn" name="rdn">
|
||||
|
@ -2,7 +2,7 @@
|
||||
<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 -->
|
||||
<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),'bg-success-subtle'=>$updated]) 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">@lang('structural')</span>
|
||||
@else
|
||||
<span class="input-group-end"><i class="fas fa-fw fa-xmark"></i></span>
|
||||
|
@ -11,11 +11,11 @@
|
||||
@switch(get_class($o))
|
||||
@case(Certificate::class)
|
||||
@case(CertificateList::class)
|
||||
<span @class(['btn','btn-sm','btn-outline-primary','mt-3','addable','d-none'=>(! $new)]) id="{{ $o->name }}-replace" disabled><i class="fas fa-fw fa-certificate"></i> @lang('Replace')</span>
|
||||
<span @class(['btn','btn-sm','btn-outline-primary','mt-3','addable','d-none'=>(! $new)]) id="{{ $o->name_lc }}-replace" disabled><i class="fas fa-fw fa-certificate"></i> @lang('Replace')</span>
|
||||
@section('page-scripts')
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
$('#{{ $o->name }}-replace.addable').click(function(e) {
|
||||
$('attribute#{{ $o->name_lc }}-replace.addable').click(function(e) {
|
||||
alert('Sorry, not implemented yet');
|
||||
e.preventDefault();
|
||||
return false;
|
||||
@ -55,7 +55,7 @@
|
||||
var rendered = false;
|
||||
var newadded = [];
|
||||
|
||||
var oc = $('attribute#objectClass input[type=text]')
|
||||
var oc = $('attribute#objectclass input[type=text]')
|
||||
.map((key,item)=>{return $(item).val()}).toArray();
|
||||
|
||||
if (newadded.length)
|
||||
@ -81,7 +81,7 @@
|
||||
},
|
||||
cache: false,
|
||||
success: function(data) {
|
||||
$('#{{ $o->name }}').append(data);
|
||||
$('attribute#{{ $o->name_lc }}').append(data);
|
||||
},
|
||||
error: function(e) {
|
||||
if (e.status !== 412)
|
||||
@ -98,13 +98,13 @@
|
||||
// Render any must attributes
|
||||
if (data.must.length) {
|
||||
data.must.forEach(function(item) {
|
||||
if ($('attribute#'+item).length)
|
||||
if ($('attribute#'+item.toLowerCase()).length)
|
||||
return;
|
||||
|
||||
// Add attribute to the page
|
||||
$.ajax({
|
||||
method: 'POST',
|
||||
url: '{{ url('entry/attr/add') }}/'+item,
|
||||
url: '{{ url('entry/attr/add') }}/'+item.toLowerCase(),
|
||||
data: {
|
||||
value: item,
|
||||
objectclasses: oc,
|
||||
@ -237,11 +237,11 @@
|
||||
@break
|
||||
|
||||
@case(JpegPhoto::class)
|
||||
<span @class(['btn','btn-sm','btn-outline-primary','mt-3','addable','d-none'=>(! $new)]) id="{{ $o->name }}-upload" disabled><i class="fas fa-fw fa-file-arrow-up"></i> @lang('Upload JpegPhoto')</span>
|
||||
<span @class(['btn','btn-sm','btn-outline-primary','mt-3','addable','d-none'=>(! $new)]) id="{{ $o->name_lc }}-upload" disabled><i class="fas fa-fw fa-file-arrow-up"></i> @lang('Upload JpegPhoto')</span>
|
||||
@section('page-scripts')
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
$('#{{ $o->name }}-upload.addable').click(function(e) {
|
||||
$('#{{ $o->name_lc }}-upload.addable').click(function(e) {
|
||||
alert('Sorry, not implemented yet');
|
||||
e.preventDefault();
|
||||
return false;
|
||||
@ -256,7 +256,7 @@
|
||||
@if($o->isDynamic()) @break @endif
|
||||
@php($clone=TRUE)
|
||||
@if($o->values_old->count())
|
||||
<span @class(['btn','btn-sm','btn-outline-primary','mt-3','addable','d-none'=>(! $new)]) id="{{ $o->name }}-addnew"><i class="fas fa-fw fa-plus"></i> @lang('Add Value')</span>
|
||||
<span @class(['btn','btn-sm','btn-outline-primary','mt-3','addable','d-none'=>(! $new)]) data-attribute="{{ $o->name }}" id="{{ $o->name_lc }}-addnew"><i class="fas fa-fw fa-plus"></i> @lang('Add Value')</span>
|
||||
@endif
|
||||
|
||||
@section('page-scripts')
|
||||
@ -264,13 +264,16 @@
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
// Create a new entry when Add Value clicked
|
||||
$('#{{ $o->name }}-addnew.addable').click(function (item) {
|
||||
var cln = $(this).parent().parent().find('input:last').parent().clone();
|
||||
cln.find('input:last')
|
||||
$('#{{ $o->name_lc }}-addnew.addable').click(function(item) {
|
||||
var attribute = $(this).data('attribute');
|
||||
var active = $('attribute[id='+attribute+']').find('.tab-pane.active');
|
||||
|
||||
active.find('input:last')
|
||||
.clone()
|
||||
.attr('value','')
|
||||
.attr('placeholder', '[@lang('NEW')]')
|
||||
.attr('placeholder','[@lang('NEW')]')
|
||||
.addClass('border-focus')
|
||||
.appendTo('#'+item.currentTarget.id.replace('-addnew',''));
|
||||
.appendTo(active);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
@ -1,8 +1,10 @@
|
||||
<!-- $o=Attribute::class -->
|
||||
<x-attribute.layout :edit="false" :new="false" :o="$o" :detail="true">
|
||||
@foreach(Arr::get(old($o->name_lc,[$langtag=>$o->tagValues($langtag)]),$langtag,[]) as $value)
|
||||
<div class="input-group">
|
||||
<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>
|
||||
@foreach($o->langtags as $langtag)
|
||||
@foreach(Arr::get(old($o->name_lc,[$langtag=>$o->tagValues($langtag)]),$langtag,[]) as $value)
|
||||
<div class="input-group">
|
||||
<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>
|
||||
@endforeach
|
||||
@endforeach
|
||||
</x-attribute.layout>
|
@ -1,8 +1,10 @@
|
||||
<!-- $o=Attribute::class -->
|
||||
<x-attribute.layout :edit="false" :new="false" :o="$o" :detail="true">
|
||||
@foreach(Arr::get(old($o->name_lc,[$langtag=>$o->tagValues($langtag)]),$langtag,[]) as $value)
|
||||
<div class="input-group">
|
||||
<input type="text" class="form-control mb-1" value="{{ $value }}" disabled>
|
||||
</div>
|
||||
@foreach($o->langtags as $langtag)
|
||||
@foreach(Arr::get(old($o->name_lc,[$langtag=>$o->tagValues($langtag)]),$langtag,[]) as $value)
|
||||
<div class="input-group">
|
||||
<input type="text" class="form-control mb-1" value="{{ $value }}" disabled>
|
||||
</div>
|
||||
@endforeach
|
||||
@endforeach
|
||||
</x-attribute.layout>
|
@ -2,8 +2,8 @@
|
||||
<div class="alert alert-success">
|
||||
<h4 class="alert-heading"><i class="fas fa-fw fa-thumbs-up"></i> Success!</h4>
|
||||
<hr>
|
||||
<ul style="list-style-type: square;">
|
||||
@foreach (session()->get('success') as $item)
|
||||
<ul class="square">
|
||||
@foreach(session()->get('success') as $item)
|
||||
<li>{{ $item }}</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
|
@ -8,10 +8,10 @@
|
||||
<input type="hidden" name="name={{ $o->name_lc }}[binary][]" value="{{ md5($value) }}">
|
||||
|
||||
<div class="input-group has-validation mb-3">
|
||||
<textarea class="form-control mb-1 font-monospace" rows="{{ count(explode("\n",$x=$o->certificate())) }}" style="overflow: hidden; font-size: 90%;" disabled>{{ $x }}</textarea>
|
||||
<textarea class="form-control mb-1 font-size-md font-monospace overflow-hidden" rows="{{ count(explode("\n",$x=$o->certificate())) }}" disabled>{{ $x }}</textarea>
|
||||
|
||||
<div class="invalid-feedback pb-2">
|
||||
@if($e=$errors->get($o->name_lc.'.'.$langtag.'.'.$loop->index))
|
||||
@if($e=$errors->get($o->name_lc.'.binary.'.$loop->index))
|
||||
{{ join('|',$e) }}
|
||||
@endif
|
||||
</div>
|
||||
|
@ -1,19 +1,20 @@
|
||||
<div id="newattrs"></div>
|
||||
|
||||
<hr class="opacity-05">
|
||||
|
||||
<!-- Add new attributes -->
|
||||
<div class="row">
|
||||
<div class="col-12 col-sm-1 col-md-2"></div>
|
||||
<div class="col-12 col-sm-10 col-md-8">
|
||||
<div class="d-none" id="newattr-select">
|
||||
<div class="col-12 offset-lg-1 col-lg-10">
|
||||
<div class="d-none round" id="newattr-select">
|
||||
<div class="row">
|
||||
<div class="col-12 bg-dark text-light p-2">
|
||||
<div class="col-12 bg-dark text-light p-2 rounded-2">
|
||||
<i class="fas fa-plus-circle"></i> Add New Attribute
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-12 pt-2">
|
||||
<x-form.select id="newattr" label="Select from..." :options="$o->getMissingAttributes()->sortBy('name')->unique('name')->map(fn($item)=>['id'=>$item->name,'value'=>$item->name_lc])"/>
|
||||
<x-form.select id="newattr" label="Select from..." :options="$o->getMissingAttributes()->sortBy('name')->unique('name')->map(fn($item)=>['id'=>$item->name,'value'=>$item->name])"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,3 +1,5 @@
|
||||
@use(App\Ldap\Entry)
|
||||
|
||||
<table class="table table-borderless">
|
||||
<tr class="border-bottom line-height-2">
|
||||
<td class="p-1 pt-0" rowspan="2">
|
||||
@ -6,7 +8,7 @@
|
||||
<td class="text-end align-bottom pb-0 mb-0 pt-2 pe-3 {{ $x ? 'ps-3' : '' }}"><strong class="user-select-all">{{ $o->getDn() }}</strong></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="align-bottom" style="font-size: 55%" colspan="2">
|
||||
<td class="align-bottom font-size-xs" colspan="2">
|
||||
<table class="table table-condensed table-borderless w-100">
|
||||
<tr class="mt-1">
|
||||
<td class="p-0 pe-2">Created</td>
|
||||
@ -26,10 +28,17 @@
|
||||
<x-attribute :o="$o->getObject('entryuuid')"/>
|
||||
</th>
|
||||
</tr>
|
||||
@if($langtags->count())
|
||||
<!-- It is assumed that langtags contains at least Entry::TAG_NOTAG -->
|
||||
@if(($x=$o->getLangTags()
|
||||
->flatMap(fn($item)=>$item->values())
|
||||
->unique()
|
||||
->sort()
|
||||
->filter(fn($item)=>($item !== Entry::TAG_NOTAG))
|
||||
->map(fn($item)=>preg_replace('/'.Entry::LANG_TAG_PREFIX.'/','',$item)))
|
||||
->count())
|
||||
<tr class="mt-1">
|
||||
<td class="p-0 pe-2">Tags</td>
|
||||
<th class="p-0">{{ $langtags->join(', ') }}</th>
|
||||
<th class="p-0">{{ $x->join(', ') }}</th>
|
||||
</tr>
|
||||
@endif
|
||||
</table>
|
||||
|
@ -2,14 +2,14 @@
|
||||
<div class="col-12 col-xl-3">
|
||||
<select id="attributetype" class="form-control">
|
||||
<option value="-all-">-all-</option>
|
||||
@foreach ($attributetypes as $o)
|
||||
@foreach($attributetypes as $o)
|
||||
<option value="{{ $o->name_lc }}">{{ $o->name }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-xl-9">
|
||||
@foreach ($attributetypes as $o)
|
||||
@foreach($attributetypes as $o)
|
||||
<span id="at-{{ $o->name_lc }}">
|
||||
<table class="schema table table-sm table-bordered table-striped">
|
||||
<thead>
|
||||
@ -30,16 +30,16 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<td>@lang('Inherits from')</td>
|
||||
<td><strong>@if ($o->sup_attribute)<a class="attributetype" id="{{ strtolower($o->sup_attribute) }}" href="#{{ strtolower($o->sup_attribute) }}">{{ $o->sup_attribute }}</a>@else @lang('(none)')@endif</strong></td>
|
||||
<td><strong>@if($o->sup_attribute)<a class="attributetype" id="{{ strtolower($o->sup_attribute) }}" href="#{{ strtolower($o->sup_attribute) }}">{{ $o->sup_attribute }}</a>@else @lang('(none)')@endif</strong></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>@lang('Parent to')</td>
|
||||
<td>
|
||||
<strong>
|
||||
@if (! $o->children->count())
|
||||
@if(! $o->children->count())
|
||||
@lang('(none)')
|
||||
@else
|
||||
@foreach ($o->children->sort() as $child)
|
||||
@foreach($o->children->sort() as $child)
|
||||
@if($loop->index)</strong> <strong>@endif
|
||||
<a class="attributetype" id="{{ strtolower($child) }}" href="#{{ strtolower($child) }}">{{ $child }}</a>
|
||||
@endforeach
|
||||
@ -77,9 +77,9 @@
|
||||
<tr>
|
||||
<td>@lang('Aliases')</td>
|
||||
<td><strong>
|
||||
@if ($o->aliases->count())
|
||||
@foreach ($o->aliases as $alias)
|
||||
@if ($loop->index)</strong> <strong>@endif
|
||||
@if($o->aliases->count())
|
||||
@foreach($o->aliases as $alias)
|
||||
@if($loop->index)</strong> <strong>@endif
|
||||
<a class="attributetype" id="{{ strtolower($alias) }}" href="#{{ strtolower($alias) }}">{{ $alias }}</a>
|
||||
@endforeach
|
||||
@else
|
||||
@ -90,8 +90,8 @@
|
||||
<tr>
|
||||
<td>@lang('Used by ObjectClasses')</td>
|
||||
<td>
|
||||
@if ($o->used_in_object_classes->count())
|
||||
@foreach ($o->used_in_object_classes as $class => $structural)
|
||||
@if($o->used_in_object_classes->count())
|
||||
@foreach($o->used_in_object_classes as $class => $structural)
|
||||
@if($structural)
|
||||
<strong>
|
||||
@endif
|
||||
@ -108,8 +108,8 @@
|
||||
<tr>
|
||||
<td>@lang('Required by ObjectClasses')</td>
|
||||
<td>
|
||||
@if ($o->required_by_object_classes->count())
|
||||
@foreach ($o->required_by_object_classes as $class => $structural)
|
||||
@if($o->required_by_object_classes->count())
|
||||
@foreach($o->required_by_object_classes as $class => $structural)
|
||||
@if($structural)
|
||||
<strong>
|
||||
@endif
|
||||
|
@ -9,14 +9,14 @@
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
@foreach ($ldapsyntaxes as $o)
|
||||
@foreach($ldapsyntaxes as $o)
|
||||
<tr>
|
||||
<td>
|
||||
<abbr title="{{ $o->line }}">{{ $o->description }}</abbr>
|
||||
@if ($o->binary_transfer_required)
|
||||
@if($o->binary_transfer_required)
|
||||
<span class="float-end"><i class="fas fa-fw fa-file-download"></i></span>
|
||||
@endif
|
||||
@if ($o->is_not_human_readable)
|
||||
@if($o->is_not_human_readable)
|
||||
<span class="float-end"><i class="fas fa-fw fa-tools"></i></span>
|
||||
@endif
|
||||
</td>
|
||||
|
@ -2,14 +2,14 @@
|
||||
<div class="col-12 col-xl-3">
|
||||
<select id="matchingrule" class="form-control">
|
||||
<option value="-all-">-all-</option>
|
||||
@foreach ($matchingrules as $o)
|
||||
@foreach($matchingrules as $o)
|
||||
<option value="{{ $o->name_lc }}">{{ $o->name }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-xl-9">
|
||||
@foreach ($matchingrules as $o)
|
||||
@foreach($matchingrules as $o)
|
||||
<span id="me-{{ $o->name_lc }}">
|
||||
<table class="schema table table-sm table-bordered table-striped">
|
||||
<thead>
|
||||
@ -32,10 +32,10 @@
|
||||
<td>@lang('Used by Attributes')</td>
|
||||
<td>
|
||||
<strong>
|
||||
@if ($o->used_by_attrs->count() === 0)
|
||||
@if($o->used_by_attrs->count() === 0)
|
||||
@lang('(none)')
|
||||
@else
|
||||
@foreach ($o->used_by_attrs as $attr)
|
||||
@foreach($o->used_by_attrs as $attr)
|
||||
@if($loop->index)</strong> <strong>@endif
|
||||
<a class="attributetype" id="{{ strtolower($attr) }}" href="#at-{{ strtolower($attr) }}">{{ $attr }}</a>
|
||||
@endforeach
|
||||
|
@ -77,7 +77,7 @@
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<ul class="ps-3" style="list-style-type: square;">
|
||||
<ul class="ps-3 square">
|
||||
@foreach($o->getMustAttrs(TRUE) as $oo)
|
||||
<li>{{ $oo->name }} @if($oo->source !== $o->name)[<strong><a class="objectclass" id="{{ strtolower($oo->source) }}" href="#{{ strtolower($oo->source) }}">{{ $oo->source }}</a></strong>]@endif</li>
|
||||
@endforeach
|
||||
@ -99,7 +99,7 @@
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<ul class="ps-3" style="list-style-type: square;">
|
||||
<ul class="ps-3 square">
|
||||
@foreach($o->getMayAttrs(TRUE) as $oo)
|
||||
<li>{{ $oo->name }} @if($oo->source !== $o->name)[<strong><a class="objectclass" id="{{ strtolower($oo->source) }}" href="#{{ strtolower($oo->source) }}">{{ $oo->source }}</a></strong>]@endif</li>
|
||||
@endforeach
|
||||
|
@ -3,10 +3,7 @@
|
||||
@extends('layouts.dn')
|
||||
|
||||
@section('page_title')
|
||||
@include('fragment.dn.header',[
|
||||
'o'=>($oo=$server->fetch(old('container',$container))),
|
||||
'langtags'=>collect(),
|
||||
])
|
||||
@include('fragment.dn.header',['o'=>($oo=$server->fetch(old('container',$container)))])
|
||||
@endsection
|
||||
|
||||
@section('page_status')
|
||||
@ -50,10 +47,10 @@
|
||||
@break
|
||||
|
||||
@case(2)
|
||||
<x-attribute-type :o="$o->getObject('rdn')" :edit="TRUE" :new="FALSE" :langtag="Entry::TAG_NOTAG" :updated="FALSE"/>
|
||||
<x-attribute-type :o="$o->getObject('rdn')" :edit="TRUE" :new="FALSE" :updated="FALSE"/>
|
||||
|
||||
@foreach ($o->getVisibleAttributes() as $ao)
|
||||
<x-attribute-type :o="$ao" :edit="TRUE" :new="FALSE" :langtag="Entry::TAG_NOTAG" :updated="FALSE"/>
|
||||
@foreach($o->getVisibleAttributes() as $ao)
|
||||
<x-attribute-type :o="$ao" :edit="TRUE" :new="FALSE" :updated="FALSE"/>
|
||||
@endforeach
|
||||
|
||||
@include('fragment.dn.add_attr')
|
||||
@ -82,7 +79,7 @@
|
||||
function editmode() {
|
||||
// Find all input items and turn off readonly
|
||||
$('input.form-control').each(function() {
|
||||
// Except for objectClass - @todo show an "X" instead
|
||||
// Except for objectClass
|
||||
if ($(this)[0].name.match(/^objectclass/))
|
||||
return;
|
||||
|
||||
@ -94,7 +91,7 @@
|
||||
});
|
||||
|
||||
// Our password type
|
||||
$('attribute#userPassword .form-select').each(function() {
|
||||
$('attribute#userpassword .form-select').each(function() {
|
||||
$(this).prop('disabled',false);
|
||||
})
|
||||
|
||||
@ -107,7 +104,7 @@
|
||||
$(document).ready(function() {
|
||||
@if($step === 2)
|
||||
$('#newattr').on('change',function(item) {
|
||||
var oc = $('attribute#objectClass input[type=text]')
|
||||
var oc = $('attribute#objectclass input[type=text]')
|
||||
.map((key,item)=>{return $(item).val()}).toArray();
|
||||
|
||||
$.ajax({
|
||||
|
@ -1,15 +1,7 @@
|
||||
@use(App\Ldap\Entry)
|
||||
|
||||
@extends('layouts.dn')
|
||||
|
||||
@section('page_title')
|
||||
@include('fragment.dn.header',[
|
||||
'o'=>($o ?? $o=$server->fetch($dn)),
|
||||
'langtags'=>($langtags=$o->getLangTags()
|
||||
->flatMap(fn($item)=>$item->values())
|
||||
->unique()
|
||||
->sort())
|
||||
])
|
||||
@include('fragment.dn.header',['o'=>($o ?? $o=$server->fetch($dn))])
|
||||
@endsection
|
||||
|
||||
@section('page_actions')
|
||||
@ -82,71 +74,52 @@
|
||||
<div class="tab-content">
|
||||
<!-- All Attributes -->
|
||||
<div class="tab-pane active" id="attributes" role="tabpanel">
|
||||
<form id="dn-edit" method="POST" class="needs-validation" action="{{ url('entry/update/pending') }}" novalidate readonly>
|
||||
@csrf
|
||||
|
||||
<input type="hidden" name="dn" value="">
|
||||
<div class="card-header border-bottom-0">
|
||||
<div class="btn-actions-pane-right">
|
||||
<div role="group" class="btn-group-sm nav btn-group">
|
||||
@php
|
||||
$langtags->prepend(Entry::TAG_NOTAG);
|
||||
if (isset($page_actions) && $page_actions->get('edit'))
|
||||
$langtags->push('+');
|
||||
@endphp
|
||||
|
||||
@foreach($langtags as $tag)
|
||||
<a data-bs-toggle="tab" href="#tab-lang-{{ $tag ?: '_default' }}" @class(['btn','btn-outline-light','border-dark-subtle','active'=>!$loop->index])>
|
||||
@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
|
||||
|
||||
@case('+')
|
||||
<!-- @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
|
||||
<div class="row pt-3">
|
||||
<div class="col-12">
|
||||
<div class="d-flex justify-content-center">
|
||||
<div role="group" class="btn-group btn-group-sm nav pb-3">
|
||||
<!-- It is assumed that the entry has atleast 1 template "default" -->
|
||||
@if($o->templates->count() > 1)
|
||||
@foreach($o->templates as $template => $name)
|
||||
<span data-bs-toggle="tab" href="#template-{{$template}}" @class(['btn','btn-outline-focus','active'=>$loop->index === 0])>{{ $name }}</span>
|
||||
@endforeach
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-body">
|
||||
<div class="tab-content">
|
||||
@php($up=(session()->pull('updated') ?: collect()))
|
||||
@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 :o="$ao" :edit="TRUE" :new="FALSE" :langtag="$tag" :updated="$up->contains($ao->name_lc)"/>
|
||||
@endforeach
|
||||
@break
|
||||
@foreach($o->templates as $template => $name)
|
||||
@switch($template)
|
||||
@case('default')
|
||||
<div @class(['tab-pane','active'=>$loop->index === 0]) id="template-{{$template}}" role="tabpanel">
|
||||
<form id="dn-edit" method="POST" class="needs-validation" action="{{ url('entry/update/pending') }}" novalidate readonly>
|
||||
@csrf
|
||||
|
||||
@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
|
||||
<input type="hidden" name="dn" value="">
|
||||
|
||||
@default
|
||||
@foreach ($o->getVisibleAttributes($langtag=sprintf('lang-%s',$tag)) as $ao)
|
||||
<x-attribute-type :o="$ao" :edit="TRUE" :new="FALSE" :langtag="$langtag" :updated="$up->contains($ao->name_lc)"/>
|
||||
@endforeach
|
||||
@endswitch
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="tab-content">
|
||||
@php($up=(session()->pull('updated') ?: collect()))
|
||||
@foreach($o->getVisibleAttributes() as $ao)
|
||||
<x-attribute-type :o="$ao" :edit="TRUE" :new="FALSE" :updated="$up->contains($ao->name_lc)"/>
|
||||
@endforeach
|
||||
|
||||
@include('fragment.dn.add_attr')
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@break
|
||||
|
||||
@default
|
||||
<div @class(['tab-pane','active'=>$loop->index === 0]) id="template-{{$template}}" role="tabpanel">
|
||||
<p>{{$name}}</p>
|
||||
</div>
|
||||
@endswitch
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@include('fragment.dn.add_attr')
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="row d-none pt-3">
|
||||
<div class="col-12 offset-sm-2 col-sm-4 col-lg-2">
|
||||
@ -158,8 +131,8 @@
|
||||
|
||||
<!-- Internal Attributes -->
|
||||
<div class="tab-pane mt-3" id="internal" role="tabpanel">
|
||||
@foreach ($o->getInternalAttributes() as $ao)
|
||||
<x-attribute-type :o="$ao" :edit="FALSE" :new="FALSE" :langtag="Entry::TAG_NOTAG" :updated="FALSE"/>
|
||||
@foreach($o->getInternalAttributes() as $ao)
|
||||
<x-attribute-type :o="$ao" :edit="FALSE" :new="FALSE" :updated="FALSE"/>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
@ -201,7 +174,7 @@
|
||||
});
|
||||
|
||||
// Our password type
|
||||
$('attribute#userPassword .form-select').each(function() {
|
||||
$('attribute#userpassword .form-select').each(function() {
|
||||
$(this).prop('disabled',false);
|
||||
})
|
||||
|
||||
@ -230,7 +203,7 @@
|
||||
});
|
||||
|
||||
$('#newattr').on('change',function(item) {
|
||||
var oc = $('attribute#objectClass input[type=text]')
|
||||
var oc = $('attribute#objectclass input[type=text]')
|
||||
.map((key,item)=>{return $(item).val()}).toArray();
|
||||
|
||||
$.ajax({
|
||||
@ -278,7 +251,7 @@
|
||||
if (e.status !== 412)
|
||||
alert('That didnt work? Please try again....');
|
||||
},
|
||||
})
|
||||
});
|
||||
break;
|
||||
|
||||
case 'entry-export':
|
||||
|
@ -3,7 +3,7 @@
|
||||
@section('page_title')
|
||||
<table class="table table-borderless">
|
||||
<tr>
|
||||
<td style="border-radius: 5px;"><div class="page-title-icon f32"><i class="fas fa-upload"></i></div></td>
|
||||
<td><div class="page-title-icon f32"><i class="fas fa-upload"></i></div></td>
|
||||
<td class="top text-start align-text-top p-2"><strong>@lang('LDIF Import')</strong><br><small>@lang('To Server') <strong>{{ $server->name }}</strong></small></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
@ -1,7 +1,7 @@
|
||||
@section('page_title')
|
||||
<table class="table table-borderless">
|
||||
<tr>
|
||||
<td style="border-radius: 5px;"><div class="page-title-icon f32"><i class="fas fa-upload"></i></div></td>
|
||||
<td><div class="page-title-icon f32"><i class="fas fa-upload"></i></div></td>
|
||||
<td class="top text-start align-text-top p-0 pt-2"><strong>@lang('LDIF Import Result')</strong><br><small>@lang('To Server') <strong>{{ $server->name }}</strong></small></td>
|
||||
</tr>
|
||||
</table>
|
||||
@ -28,7 +28,7 @@
|
||||
<th class="text-end">@lang('Line')</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@foreach ($result as $item)
|
||||
@foreach($result as $item)
|
||||
<tr>
|
||||
<td>{{ $item->get('dn') }}</td>
|
||||
<td>{{ $item->get('result') }}</td>
|
||||
|
@ -3,7 +3,7 @@
|
||||
@section('page_title')
|
||||
<table class="table table-borderless">
|
||||
<tr>
|
||||
<td style="border-radius: 5px;"><div class="page-title-icon f32"><i class="fas fa-info"></i></div></td>
|
||||
<td><div class="page-title-icon f32"><i class="fas fa-info"></i></div></td>
|
||||
<td class="top text-end align-text-top p-2"><strong>@lang('Server Info')</strong><br><small>{{ $server->rootDSE()->entryuuid[0] ?? '' }}</small></td>
|
||||
</tr>
|
||||
</table>
|
||||
@ -13,7 +13,7 @@
|
||||
<div class="main-card mb-3 card">
|
||||
<div class="card-body">
|
||||
<table class="table">
|
||||
@foreach ($server->rootDSE()->getObjects() as $attribute => $ao)
|
||||
@foreach($server->rootDSE()->getObjects() as $attribute => $ao)
|
||||
<tr>
|
||||
<th class="w-25">
|
||||
{!! ($x=$server->schema('attributetypes',$attribute))
|
||||
|
@ -3,7 +3,7 @@
|
||||
@section('page_title')
|
||||
<table class="table table-borderless">
|
||||
<tr>
|
||||
<td style="border-radius: 5px;"><div class="page-title-icon f32"><i class="fas fa-fingerprint"></i></div></td>
|
||||
<td><div class="page-title-icon f32"><i class="fas fa-fingerprint"></i></div></td>
|
||||
<td class="top text-end align-text-top p-2"><strong>{{ $server->schemaDN() }}</strong></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
@ -62,7 +62,7 @@
|
||||
<i class="fas fa-fw fa-file-export me-2"></i> LDIF Import/Export
|
||||
</li>
|
||||
<li class="ps-0 p-1">
|
||||
<i class="fas fa-fw fa-clipboard-list me-2"></i> Build on RFC Standards
|
||||
<i class="fas fa-fw fa-clipboard-list me-2"></i> Built using RFC Standards
|
||||
</li>
|
||||
<li class="ps-0 p-1">
|
||||
<i class="fas fa-fw fa-pen-to-square me-2"></i> Open Source
|
||||
|
@ -1,4 +1,4 @@
|
||||
@if (trim($__env->yieldContent('page_title')))
|
||||
@if(trim($__env->yieldContent('page_title')))
|
||||
@include('architect::layouts.partials.contentheader')
|
||||
@endif
|
||||
|
||||
|
@ -1,12 +1,7 @@
|
||||
@extends('home')
|
||||
|
||||
@section('page_title')
|
||||
@include('fragment.dn.header',[
|
||||
'langtags'=>($langtags=$o->getLangTags()
|
||||
->flatMap(fn($item)=>$item->values())
|
||||
->unique()
|
||||
->sort())
|
||||
])
|
||||
@include('fragment.dn.header')
|
||||
@endsection
|
||||
|
||||
@section('page_status')
|
||||
@ -35,7 +30,7 @@
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
@foreach ($o->getObjects()->filter(fn($item)=>$item->isDirty()) as $key => $oo)
|
||||
@foreach($o->getObjects()->filter(fn($item)=>$item->isDirty()) as $key => $oo)
|
||||
<tr>
|
||||
<th rowspan="{{ $x=max($oo->values->dot()->keys()->count(),$oo->values_old->dot()->keys()->count())}}">
|
||||
<abbr title="{{ $oo->description }}">{{ $oo->name }}</abbr>
|
||||
|
242
tests/Feature/AttributeTagsTest.php
Normal file
242
tests/Feature/AttributeTagsTest.php
Normal file
@ -0,0 +1,242 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Classes\LDAP\Attribute;
|
||||
use App\Ldap\Entry;
|
||||
use Tests\TestCase;
|
||||
|
||||
/**
|
||||
* This unit will test Attributes that are:
|
||||
* + no_attr_tag attributes vs those with attr_tags, AND
|
||||
* + md5 attributes vs those that are not md5 attributes
|
||||
*
|
||||
* objectClass (a no_attr_tags_attribute)
|
||||
* userPassword (a no_attr_tags_attribute, and an md5 attribute)
|
||||
* certificate (a no_attr_tags attribute)
|
||||
* [internal attribute] (which is a no_attr_tags attribute)
|
||||
* mail (a normal attribute)
|
||||
*
|
||||
* => no_lang_tag attributes
|
||||
* + ->values returns a Collection of values
|
||||
* + ->values_old return a Collection of old values
|
||||
* + ->tagValues() returns a Collection of values
|
||||
* + ->tagValuesOld() return a Collection of old values
|
||||
* + ->render_old_item() should be the raw value (unless an md5attribute, then the md5 value)
|
||||
* + ->render_new_item() should be the raw value (unless an md5attribute, then the md5 value)
|
||||
* + ->_values is array with only 1 key _null_ with an array of values
|
||||
* + ->_values_old is array with only 1 key _null_ with an array of values
|
||||
* + ->isDirty processing when there is a new value in the _null_ key and in another key (it should be ignored for no_attr_tags attributes)
|
||||
* + ->isDirty processing when there is a new value, and its an md5 attribute
|
||||
*
|
||||
* The goal here is that
|
||||
* + no_attr_tags attributes return an array of values not indexed by an attr_tag
|
||||
* + attr_tag attributes are an array of values indexed by an attr_tag
|
||||
* + md5 attributes will render the md5 value, and compare the md5 value when determining if it has changed
|
||||
*
|
||||
* This will mean that our views then can render attributes with tagValues() and render_xxx_item() without just by calling
|
||||
* those methods with the langtag for the attribute rendering
|
||||
*
|
||||
* Attributes that are no_attr_tag attributes should not render anything in non-default langtag views
|
||||
*/
|
||||
class AttributeTagsTest extends TestCase
|
||||
{
|
||||
private function read()
|
||||
{
|
||||
static $o = NULL;
|
||||
|
||||
if (is_null($o)) {
|
||||
$dn = 'cn=Bart Simpson,ou=People,o=Simpsons';
|
||||
$this->assertTrue($this->login());
|
||||
$this->assertEquals($dn,$o=config('server')->fetch($dn));
|
||||
}
|
||||
|
||||
return $o;
|
||||
}
|
||||
|
||||
public function test_uid()
|
||||
{
|
||||
// Test UID, which can have attribute tags
|
||||
$o = $this->read();
|
||||
$new = ['newbart'];
|
||||
$o->uid = [
|
||||
'_null_' => $new,
|
||||
];
|
||||
|
||||
$oo = $o->getObject('uid');
|
||||
|
||||
$this->assertInstanceOf(Attribute::class,$oo);
|
||||
|
||||
// ->values returns a Collection of values
|
||||
// ->_values is array with only 1 key _null_ with an array of values
|
||||
$this->assertCount(1,$oo->values);
|
||||
$this->assertArrayHasKey(Entry::TAG_NOTAG,$oo->values);
|
||||
$this->assertCount(1,$oo->values[Entry::TAG_NOTAG]);
|
||||
|
||||
// ->values_old return a Collection of old values
|
||||
// ->_values_old is array with only 1 key _null_ with an array of values
|
||||
$this->assertCount(1,$oo->values_old);
|
||||
$this->assertArrayHasKey(Entry::TAG_NOTAG,$oo->values_old);
|
||||
$this->assertCount(1,$oo->values_old[Entry::TAG_NOTAG]);
|
||||
|
||||
// ->tagValues() returns a Collection of values
|
||||
$this->assertCount(1,$oo->tagValues());
|
||||
|
||||
// ->tagValuesOld() return a Collection of old values
|
||||
$this->assertCount(1,$oo->tagValuesOld());
|
||||
|
||||
// ->render_item_old() should be the raw value (unless an md5attribute, then the md5 value)
|
||||
$this->assertEquals('bart',$oo->render_item_old(Entry::TAG_NOTAG.'.0'));
|
||||
// ->render_item_new() should be the raw value (unless an md5attribute, then the md5 value)
|
||||
$this->assertEquals('newbart',$oo->render_item_new(Entry::TAG_NOTAG.'.0'));
|
||||
|
||||
// ->isDirty processing when there is a new value in the _null_ key and in another key (it should be ignored for no_attr_tags attributes)
|
||||
// ->isDirty processing when there is a new value, and its an md5 attribute
|
||||
$this->assertTrue($oo->isDirty());
|
||||
$this->assertCount(1,$x=$o->getDirty());
|
||||
$this->assertArrayHasKey('uid',$x);
|
||||
$this->assertCount(1,$x['uid']);
|
||||
$this->assertEquals($new,$x['uid']);
|
||||
}
|
||||
|
||||
public function test_objectclass()
|
||||
{
|
||||
// Test ObjectClass, which can NOT have attribute tags
|
||||
$o = $this->read();
|
||||
$newoc = [
|
||||
'inetOrgPerson',
|
||||
'posixAccount',
|
||||
'top',
|
||||
'shadowAccount',
|
||||
'inetLocalMailRecipient',
|
||||
];
|
||||
|
||||
$o->objectclass = [
|
||||
'_null_' => $newoc,
|
||||
];
|
||||
|
||||
$oo = $o->getObject('objectclass');
|
||||
|
||||
$this->assertInstanceOf(Attribute\ObjectClass::class,$oo);
|
||||
$this->assertTrue($oo->no_attr_tags);
|
||||
|
||||
// ->values returns a Collection of values
|
||||
// ->_values is array with only 1 key _null_ with an array of values
|
||||
$this->assertCount(5,$oo->values);
|
||||
$this->assertArrayNotHasKey(Entry::TAG_NOTAG,$oo->values);
|
||||
|
||||
// ->values_old return a Collection of old values
|
||||
// ->_values_old is array with only 1 key _null_ with an array of values
|
||||
$this->assertCount(4,$oo->values_old);
|
||||
$this->assertArrayNotHasKey(Entry::TAG_NOTAG,$oo->values_old);
|
||||
|
||||
// ->tagValues() returns a Collection of values
|
||||
$this->assertCount(5,$oo->tagValues());
|
||||
|
||||
// ->tagValuesOld() return a Collection of old values
|
||||
$this->assertCount(4,$oo->tagValuesOld());
|
||||
|
||||
// ->render_item_old() should be the raw value (unless an md5attribute, then the md5 value)
|
||||
$this->assertEquals('inetOrgPerson',$oo->render_item_old('0'));
|
||||
// ->render_item_new() should be the raw value (unless an md5attribute, then the md5 value)
|
||||
$this->assertEquals('inetLocalMailRecipient',$oo->render_item_new('4'));
|
||||
|
||||
// ->isDirty processing when there is a new value in the _null_ key and in another key (it should be ignored for no_attr_tags attributes)
|
||||
// ->isDirty processing when there is a new value, and its an md5 attribute
|
||||
$this->assertTrue($oo->isDirty());
|
||||
$this->assertCount(2,$x=$o->getDirty());
|
||||
$this->assertArrayHasKey('objectclass',$x);
|
||||
$this->assertCount(5,$x['objectclass']);
|
||||
$this->assertEquals($newoc,$x['objectclass']);
|
||||
}
|
||||
|
||||
public function test_userpassword()
|
||||
{
|
||||
// Test ObjectClass, which can NOT have attribute tags
|
||||
$o = $this->read();
|
||||
$new = [
|
||||
'test1234',
|
||||
];
|
||||
$o->userpassword = [
|
||||
'_null_' => $new,
|
||||
];
|
||||
|
||||
$oo = $o->getObject('userpassword');
|
||||
|
||||
$this->assertInstanceOf(Attribute\Password::class,$oo);
|
||||
$this->assertTrue($oo->no_attr_tags);
|
||||
|
||||
// ->values returns a Collection of values
|
||||
// ->_values is array with only 1 key _null_ with an array of values
|
||||
$this->assertCount(1,$oo->values);
|
||||
$this->assertArrayNotHasKey(Entry::TAG_NOTAG,$oo->values);
|
||||
|
||||
// ->values_old return a Collection of old values
|
||||
// ->_values_old is array with only 1 key _null_ with an array of values
|
||||
$this->assertCount(1,$oo->values_old);
|
||||
$this->assertArrayNotHasKey(Entry::TAG_NOTAG,$oo->values_old);
|
||||
|
||||
// ->tagValues() returns a Collection of values
|
||||
$this->assertCount(1,$oo->tagValues());
|
||||
|
||||
// ->tagValuesOld() return a Collection of old values
|
||||
$this->assertCount(1,$oo->tagValuesOld());
|
||||
|
||||
// ->render_item_old() should be the raw value (unless an md5attribute, then the md5 value)
|
||||
$this->assertEquals('{*clear*}****************',$oo->render_item_old('0'));
|
||||
// ->render_item_new() should be the raw value (unless an md5attribute, then the md5 value)
|
||||
$this->assertEquals('****************',$oo->render_item_new('0'));
|
||||
|
||||
// ->isDirty processing when there is a new value in the _null_ key and in another key (it should be ignored for no_attr_tags attributes)
|
||||
// ->isDirty processing when there is a new value, and its an md5 attribute
|
||||
$this->assertTrue($oo->isDirty());
|
||||
$this->assertCount(3,$x=$o->getDirty());
|
||||
$this->assertArrayHasKey('userpassword',$x);
|
||||
$this->assertCount(1,$x['userpassword']);
|
||||
$this->assertEquals($new,$x['userpassword']);
|
||||
}
|
||||
|
||||
public function test_userpassword_nochange()
|
||||
{
|
||||
// Test ObjectClass, which can NOT have attribute tags
|
||||
$o = $this->read();
|
||||
$new = [
|
||||
'd88d98df6727f87376c93e9676978146', // eatmyshorts
|
||||
];
|
||||
$o->userpassword = [
|
||||
'_null_' => $new,
|
||||
];
|
||||
|
||||
$oo = $o->getObject('userpassword');
|
||||
|
||||
$this->assertInstanceOf(Attribute\Password::class,$oo);
|
||||
$this->assertTrue($oo->no_attr_tags);
|
||||
|
||||
// ->values returns a Collection of values
|
||||
// ->_values is array with only 1 key _null_ with an array of values
|
||||
$this->assertCount(1,$oo->values);
|
||||
$this->assertArrayNotHasKey(Entry::TAG_NOTAG,$oo->values);
|
||||
|
||||
// ->values_old return a Collection of old values
|
||||
// ->_values_old is array with only 1 key _null_ with an array of values
|
||||
$this->assertCount(1,$oo->values_old);
|
||||
$this->assertArrayNotHasKey(Entry::TAG_NOTAG,$oo->values_old);
|
||||
|
||||
// ->tagValues() returns a Collection of values
|
||||
$this->assertCount(1,$oo->tagValues());
|
||||
|
||||
// ->tagValuesOld() return a Collection of old values
|
||||
$this->assertCount(1,$oo->tagValuesOld());
|
||||
|
||||
// ->render_item_old() should be the raw value (unless an md5attribute, then the md5 value)
|
||||
$this->assertEquals('{*clear*}****************',$oo->render_item_old('0'));
|
||||
// ->render_item_new() should be the raw value (unless an md5attribute, then the md5 value)
|
||||
$this->assertEquals('****************',$oo->render_item_new('0'));
|
||||
|
||||
// ->isDirty processing when there is a new value in the _null_ key and in another key (it should be ignored for no_attr_tags attributes)
|
||||
// ->isDirty processing when there is a new value, and its an md5 attribute
|
||||
$this->assertFalse($oo->isDirty());
|
||||
$this->assertCount(2,$x=$o->getDirty());
|
||||
$this->assertArrayNotHasKey('userpassword',$x);
|
||||
}
|
||||
}
|
@ -20,6 +20,6 @@ class GetBaseDNTest extends TestCase
|
||||
|
||||
$this->assertIsObject($o);
|
||||
$this->assertCount(6,$o->toArray());
|
||||
$this->assertEquals('dc=Test',$o->first()->getDn());
|
||||
$this->assertEquals('c=AU',$o->first()->getDn());
|
||||
}
|
||||
}
|
||||
}
|
48
tests/Feature/ImportTest.php
Normal file
48
tests/Feature/ImportTest.php
Normal file
@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use Illuminate\Http\UploadedFile;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
use Tests\TestCase;
|
||||
|
||||
class ImportTest extends TestCase
|
||||
{
|
||||
public function testLDIF_Import()
|
||||
{
|
||||
$dn = 'cn=Bart Simpson,ou=People,o=Simpsons';
|
||||
$import_file = __DIR__.'/data/ldif-import.ldif';
|
||||
|
||||
$this->assertTrue($this->login());
|
||||
$this->assertTrue(Auth::check());
|
||||
$this->actingAs(Auth::user());
|
||||
$this->assertFalse(config('ldap.cache.enabled'));
|
||||
|
||||
// Check that it exists
|
||||
$this->assertEquals($dn,$x=config('server')->fetch($dn));
|
||||
$this->assertTrue($x->exists);
|
||||
|
||||
// Delete the entry
|
||||
$x->delete();
|
||||
$this->assertEquals(NULL,config('server')->fetch($dn));
|
||||
|
||||
$file = new UploadedFile($import_file,'ldif-import.ldif',null,null,true);
|
||||
|
||||
$response = $this
|
||||
->actingAs(Auth::user())
|
||||
->from('/import')
|
||||
->post('/import/process/ldif',[
|
||||
'_token' => csrf_token(),
|
||||
'key'=>Crypt::encryptString('*import|_NOP'),
|
||||
'file' => $file,
|
||||
]);
|
||||
|
||||
//$response->dump();
|
||||
$response->assertSuccessful();
|
||||
|
||||
// Check that it hsa been created
|
||||
$this->assertEquals($dn,$x=config('server')->fetch($dn));
|
||||
$this->assertTrue($x->exists);
|
||||
}
|
||||
}
|
@ -2,8 +2,8 @@
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use LdapRecord\Container;
|
||||
use LdapRecord\Testing\DirectoryFake;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
use Tests\TestCase;
|
||||
|
||||
class LoginTest extends TestCase
|
||||
@ -18,12 +18,10 @@ class LoginTest extends TestCase
|
||||
|
||||
public function test_admin_dn_login()
|
||||
{
|
||||
$username = 'cn=Admin,dc=Test';
|
||||
$password = 'test';
|
||||
$this->assertTrue($this->login());
|
||||
$this->assertTrue(Auth::check());
|
||||
|
||||
//DirectoryFake::setup();
|
||||
|
||||
$connection = Container::getDefaultConnection();
|
||||
$this->assertTrue($connection->auth()->attempt($username,$password));
|
||||
$this->assertTrue(Session::has('username_encrypt'));
|
||||
$this->assertTrue(Session::has('password_encrypt'));
|
||||
}
|
||||
}
|
||||
}
|
83
tests/Feature/data/ldif-import.ldif
Normal file
83
tests/Feature/data/ldif-import.ldif
Normal file
@ -0,0 +1,83 @@
|
||||
# LDIF Export for cn=Bart Simpson,ou=People,o=Simpsons
|
||||
# Server: LDAP Server (ldap://ldap:389)
|
||||
# Total Entries: 1
|
||||
#
|
||||
# Generated by PLA (http://localhost) on January 12, 2024 12:39 pm
|
||||
# Exported by Anonymous
|
||||
# Version: v2.0.0-dev-00000000
|
||||
|
||||
version: 1
|
||||
# Entry 1: cn=Bart Simpson,ou=People,o=Simpsons
|
||||
dn: cn=Bart Simpson,ou=People,o=Simpsons
|
||||
audio: test
|
||||
cn: Bart Simpson
|
||||
gidNumber: 1000
|
||||
givenName: Bart
|
||||
homeDirectory: /home/users/simpsons/bart
|
||||
jpegPhoto:: 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
|
||||
l: Springfield
|
||||
mail: bart.simpson@example.com
|
||||
o: The Simpsons
|
||||
objectClass: inetOrgPerson
|
||||
objectClass: posixAccount
|
||||
objectClass: top
|
||||
objectClass: shadowAccount
|
||||
sn: Simpson
|
||||
st: 742 Evergreen Terrace
|
||||
telephoneNumber: +1 939 555 3126
|
||||
uid: bart
|
||||
uidNumber: 1000
|
||||
userPassword: eatmyshorts
|
@ -3,10 +3,20 @@
|
||||
namespace Tests;
|
||||
|
||||
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
|
||||
use App\Classes\LDAP\Server;
|
||||
|
||||
abstract class TestCase extends BaseTestCase
|
||||
{
|
||||
use CreatesApplication;
|
||||
use CreatesApplication;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
Config::set('server',new Server());
|
||||
}
|
||||
|
||||
/**
|
||||
* Hack to get testing working
|
||||
@ -19,4 +29,15 @@ abstract class TestCase extends BaseTestCase
|
||||
app()->instance('config', $config);
|
||||
app()->instance('events', $events);
|
||||
}
|
||||
|
||||
protected function login(): bool
|
||||
{
|
||||
//$username = 'cn=AdminUser,dc=Test';
|
||||
$username = 'admin';
|
||||
$password = 'password';
|
||||
|
||||
$this->post('/login',['uid'=>$username,'password'=>$password]);
|
||||
|
||||
return Auth::check() && (Auth::user()->getDN() === 'cn=AdminUser,dc=Test');
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user