diff --git a/app/Classes/LDAP/Attribute.php b/app/Classes/LDAP/Attribute.php
index 2c9fc40..9b027d1 100644
--- a/app/Classes/LDAP/Attribute.php
+++ b/app/Classes/LDAP/Attribute.php
@@ -2,6 +2,7 @@
namespace App\Classes\LDAP;
+use Illuminate\Contracts\View\View;
use Illuminate\Support\Collection;
use App\Classes\LDAP\Schema\AttributeType;
@@ -130,12 +131,14 @@ class Attribute
'hints' => $this->hints(),
// Is this an internal attribute
'is_internal' => isset($this->{$key}) && $this->{$key},
+ // Is this attribute the RDN
+ 'is_rdn' => $this->is_rdn,
// We prefer the name as per the schema if it exists
'name' => $this->schema ? $this->schema->{$key} : $this->{$key},
// Attribute name in lower case
'name_lc' => strtolower($this->name),
- // Is this attribute the RDN
- 'rdn' => $this->is_rdn,
+ // Attribute values
+ 'values' => $this->values,
default => throw new \Exception('Unknown key:' . $key),
};
@@ -151,22 +154,6 @@ class Attribute
return $this->values->join(' ');
}
- /**
- * Return an instance of this attribute that is deletable.
- * This is primarily used for rendering to know if to render delete options.
- *
- * @return Attribute
- */
- public function deletable(): self
- {
- $clone = clone $this;
-
- if (! $this->required_by->count())
- $clone->is_deletable = TRUE;
-
- return $clone;
- }
-
/**
* Return the hints about this attribute, ie: RDN, Required, etc
*
@@ -195,6 +182,13 @@ class Attribute
return $result->toArray();
}
+ public function render(bool $edit): View
+ {
+ return view('components.attribute')
+ ->with('edit',$edit)
+ ->with('o',$this);
+ }
+
/**
* Set the objectclasses that require this attribute
*
diff --git a/app/Http/Controllers/APIController.php b/app/Http/Controllers/APIController.php
index 1ce3271..0f85226 100644
--- a/app/Http/Controllers/APIController.php
+++ b/app/Http/Controllers/APIController.php
@@ -27,7 +27,7 @@ class APIController extends Controller
->transform(function($item) {
return [
'title'=>$item->getRdn(),
- 'item'=>Crypt::encryptString($item->getDn()),
+ 'item'=>$item->getDNSecure(),
'icon'=>$item->icon(),
'lazy'=>Arr::get($item->getAttribute('hassubordinates'),0) == 'TRUE',
'tooltip'=>$item->getDn(),
diff --git a/app/Http/Controllers/HomeController.php b/app/Http/Controllers/HomeController.php
index 4ecc8a7..6cf7c3b 100644
--- a/app/Http/Controllers/HomeController.php
+++ b/app/Http/Controllers/HomeController.php
@@ -8,10 +8,14 @@ use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\File;
+use Illuminate\Support\Facades\Session;
+use LdapRecord\Exceptions\InsufficientAccessException;
+use LdapRecord\LdapRecordException;
use LdapRecord\Query\ObjectNotFoundException;
use App\Classes\LDAP\Server;
use App\Exceptions\InvalidUsage;
+use App\Http\Requests\EntryRequest;
class HomeController extends Controller
{
@@ -25,6 +29,66 @@ class HomeController extends Controller
return view('debug');
}
+ /**
+ * Render a specific DN
+ *
+ * @param Request $request
+ * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
+ */
+ public function dn_frame(Request $request)
+ {
+ $dn = Crypt::decryptString($request->post('key'));
+
+ return view('frames.dn')
+ ->with('o',config('server')->fetch($dn))
+ ->with('dn',$dn);
+ }
+
+ public function entry_update(EntryRequest $request)
+ {
+ $dn = Crypt::decryptString($request->dn);
+
+ $o = config('server')->fetch($dn);
+
+ foreach ($request->except(['_token','dn']) as $key => $value)
+ $o->{$key} = array_filter($value);
+
+ Session::put('dn',$request->dn);
+
+ if (! $dirty=$o->getDirty())
+ return back()->with(['note'=>__('No attributes changed')]);
+
+ try {
+ $o->update($request->except(['_token','dn']));
+
+ } catch (InsufficientAccessException $e) {
+ $request->flash();
+
+ switch ($x=$e->getDetailedError()->getErrorCode()) {
+ case 50:
+ return back()->withErrors(sprintf('%s: %s (%s)',__('LDAP Server Error Code'),$x,__($e->getDetailedError()->getErrorMessage())));
+
+ default:
+ abort(599,$e->getDetailedError()->getErrorMessage());
+ }
+
+ } catch (LdapRecordException $e) {
+ $request->flash();
+
+ switch ($x=$e->getDetailedError()->getErrorCode()) {
+ case 8:
+ return back()->withErrors(sprintf('%s: %s (%s)',__('LDAP Server Error Code'),$x,__($e->getDetailedError()->getErrorMessage())));
+
+ default:
+ abort(599,$e->getDetailedError()->getErrorMessage());
+ }
+ }
+
+ return back()
+ ->with(['success'=>__('Entry updated')])
+ ->with(['updated'=>$dirty]);
+ }
+
/**
* Application home page
*/
@@ -32,17 +96,25 @@ class HomeController extends Controller
{
$base = Server::baseDNs() ?: collect();
- return view('home')
- ->with('server',config('ldap.connections.default.name'))
- ->with('bases',$base->transform(function($item) {
- return [
- 'title'=>$item->getRdn(),
- 'item'=>Crypt::encryptString($item->getDn()),
- 'lazy'=>TRUE,
- 'icon'=>'fa-fw fas fa-sitemap',
- 'tooltip'=>$item->getDn(),
- ];
- }));
+ $bases = $base->transform(function($item) {
+ return [
+ 'title'=>$item->getRdn(),
+ 'item'=>$item->getDNSecure(),
+ 'lazy'=>TRUE,
+ 'icon'=>'fa-fw fas fa-sitemap',
+ 'tooltip'=>$item->getDn(),
+ ];
+ });
+
+ if (Session::has('dn'))
+ return view('dn')
+ ->with('bases',$bases)
+ ->with('o',config('server')->fetch($dn=Crypt::decryptString(Session::pull('dn'))))
+ ->with('dn',$dn);
+ else
+ return view('home')
+ ->with('bases',$bases)
+ ->with('server',config('ldap.connections.default.name'));
}
/**
@@ -62,21 +134,6 @@ class HomeController extends Controller
->with('s',$s);
}
- /**
- * Render a specific DN
- *
- * @param Request $request
- * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
- */
- public function dn_frame(Request $request)
- {
- $dn = Crypt::decryptString($request->post('key'));
-
- return view('frames.dn')
- ->with('o',config('server')->fetch($dn))
- ->with('dn',$dn);
- }
-
/**
* Show the Schema Viewer
*
diff --git a/app/Http/Requests/EntryRequest.php b/app/Http/Requests/EntryRequest.php
new file mode 100644
index 0000000..a57b07e
--- /dev/null
+++ b/app/Http/Requests/EntryRequest.php
@@ -0,0 +1,31 @@
+
+ */
+ public function rules()
+ {
+ return [
+ 'dn'=>'string|min:3',
+ 'objectclass'=>'array|min:1',
+ ];
+ }
+}
\ No newline at end of file
diff --git a/app/Ldap/Entry.php b/app/Ldap/Entry.php
index eca3366..18288c2 100644
--- a/app/Ldap/Entry.php
+++ b/app/Ldap/Entry.php
@@ -4,6 +4,7 @@ namespace App\Ldap;
use Illuminate\Support\Arr;
use Illuminate\Support\Collection;
+use Illuminate\Support\Facades\Crypt;
use LdapRecord\Models\Model;
use App\Classes\LDAP\Attribute;
@@ -93,6 +94,15 @@ class Entry extends Model
/* METHODS */
+ /**
+ * Return a secure version of the DN
+ * @return string
+ */
+ public function getDNSecure(): string
+ {
+ return Crypt::encryptString($this->getDn());
+ }
+
/**
* Return a list of LDAP internal attributes
*
diff --git a/app/View/Components/Attribute.php b/app/View/Components/Attribute.php
new file mode 100644
index 0000000..ff40a6b
--- /dev/null
+++ b/app/View/Components/Attribute.php
@@ -0,0 +1,34 @@
+edit = $edit;
+ $this->o = $o;
+ }
+
+ /**
+ * Get the view / contents that represent the component.
+ *
+ * @return \Illuminate\Contracts\View\View|\Closure|string
+ */
+ public function render()
+ {
+ return $this->o->render($this->edit);
+ }
+}
\ No newline at end of file
diff --git a/public/js/custom.js b/public/js/custom.js
index 18249cc..e3ecf03 100644
--- a/public/js/custom.js
+++ b/public/js/custom.js
@@ -11,6 +11,38 @@ function expandChildren(node) {
}
}
+function getNode(item) {
+ $.ajax({
+ url: 'dn',
+ method: 'POST',
+ data: { key: item },
+ dataType: 'html',
+ beforeSend: function() {
+ content = $('.main-content').contents();
+ $('.main-content').empty().append('
');
+ }
+
+ }).done(function(html) {
+ $('.main-content').empty().append(html);
+
+ }).fail(function(item) {
+ switch(item.status) {
+ case 404:
+ $('.main-content').empty().append(item.responseText);
+ break;
+ case 419:
+ alert('Session has expired, reloading the page and try again...');
+ location.reload();
+ break;
+ case 500:
+ $('.main-content').empty().append(item.responseText);
+ break;
+ default:
+ alert(item.status+': Well that didnt work?');
+ }
+ });
+}
+
$(document).ready(function() {
// If our bases have been set, we'll render them directly
if (typeof basedn !== 'undefined') {
@@ -50,35 +82,7 @@ $(document).ready(function() {
},
click: function(event,data) {
if (data.targetType == 'title') {
- $.ajax({
- url: 'dn',
- method: 'POST',
- data: { key: data.node.data.item },
- dataType: 'html',
- beforeSend: function() {
- content = $('.main-content').contents();
- $('.main-content').empty().append('
');
- }
-
- }).done(function(html) {
- $('.main-content').empty().append(html);
-
- }).fail(function(item) {
- switch(item.status) {
- case 404:
- $('.main-content').empty().append(item.responseText);
- break;
- case 419:
- alert('Session has expired, reloading the page and try again...');
- location.reload();
- break;
- case 500:
- $('.main-content').empty().append(item.responseText);
- break;
- default:
- alert(item.status+': Well that didnt work?');
- }
- });
+ getNode(data.node.data.item);
}
},
source: sources,
@@ -90,13 +94,16 @@ $(document).ready(function() {
expandChildren(data.tree.rootNode);
},
- keydown: function(event, data){
+ keydown: function(event,data){
switch( $.ui.fancytree.eventToString(data.originalEvent) ) {
case 'return':
case 'space':
data.node.toggleExpanded();
break;
}
+ },
+ restore: function(event,data) {
+ //getNode(data.tree.getActiveNode().data.item);
}
});
});
\ No newline at end of file
diff --git a/resources/themes/architect/views/layouts/error.blade.php b/resources/themes/architect/views/layouts/error.blade.php
index c4408b3..ab30ef4 100644
--- a/resources/themes/architect/views/layouts/error.blade.php
+++ b/resources/themes/architect/views/layouts/error.blade.php
@@ -15,9 +15,9 @@
-
diff --git a/resources/views/components/attribute.blade.php b/resources/views/components/attribute.blade.php
new file mode 100644
index 0000000..02d06fa
--- /dev/null
+++ b/resources/views/components/attribute.blade.php
@@ -0,0 +1,23 @@
+
+
+
+ @foreach (old($o->name_lc,$o->values) as $value)
+ @if ($edit && ! $o->is_rdn)
+ values,$loop->index) }}"@endif>
+ @else
+ {{ $value }}
+ @endif
+ @endforeach
+
+
+
+
+ @if($o->is_rdn)
+
{{ __('Rename') }}
+ @elseif($edit && $o->can_addvalues)
+
+ {{ __('Add Value') }}
+
+ @endif
+
+
\ No newline at end of file
diff --git a/resources/views/dn.blade.php b/resources/views/dn.blade.php
new file mode 100644
index 0000000..e95a435
--- /dev/null
+++ b/resources/views/dn.blade.php
@@ -0,0 +1,22 @@
+@extends('architect::layouts.app')
+
+{{--
+@section('htmlheader_title')
+ @lang('Home')
+@endsection
+
+@section('page_title')
+@endsection
+@section('page_icon')
+@endsection
+--}}
+
+@section('main-content')
+ @include('frames.dn')
+@endsection
+
+@section('page-scripts')
+
+@append
\ No newline at end of file
diff --git a/resources/views/errors/599.blade.php b/resources/views/errors/599.blade.php
new file mode 100644
index 0000000..a6b1988
--- /dev/null
+++ b/resources/views/errors/599.blade.php
@@ -0,0 +1,9 @@
+@extends('architect::layouts.error')
+
+@section('title')
+ 599: @lang('Untrapped Error')
+@endsection
+
+@section('content')
+ {{ $exception->getMessage() }}
+@endsection
\ No newline at end of file
diff --git a/resources/views/frames/dn.blade.php b/resources/views/frames/dn.blade.php
index 3a1520f..5216db2 100644
--- a/resources/views/frames/dn.blade.php
+++ b/resources/views/frames/dn.blade.php
@@ -28,14 +28,44 @@
@endsection
@section('main-content')
+ @if(session()->has('note'))
+
+
Note:
+
+
{{ session()->pull('note') }}
+
+ @endif
+
+ @if(session()->has('success'))
+
+
Success!
+
+
{{ session()->pull('success') }}
+
+ @foreach (session()->pull('updated') as $key => $values)
+ {{ $key }}: {{ join(',',$values) }}
+ @endforeach
+
+
+ @endif
+
+ @if($errors->any())
+
+
Error?
+
+
+ @foreach ($errors->all() as $error)
+ {{ $error }}
+ @endforeach
+
+
+ @endif
+
-@endsection
\ No newline at end of file
+@endsection
+
+@section('page-scripts')
+
+@append
\ No newline at end of file
diff --git a/routes/web.php b/routes/web.php
index 4d2a47e..dfe07d4 100644
--- a/routes/web.php
+++ b/routes/web.php
@@ -38,3 +38,5 @@ Route::get('logout',[LoginController::class,'logout']);
Route::group(['prefix'=>'user'],function() {
Route::get('image',[HomeController::class,'user_image']);
});
+
+Route::post('entry/update',[HomeController::class,'entry_update']);
\ No newline at end of file