Start of enabling DN update.
This commit is contained in:
parent
a1a9b8ba76
commit
c36383b0fc
@ -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('<br>');
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
|
@ -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(),
|
||||
|
@ -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) {
|
||||
$bases = $base->transform(function($item) {
|
||||
return [
|
||||
'title'=>$item->getRdn(),
|
||||
'item'=>Crypt::encryptString($item->getDn()),
|
||||
'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
|
||||
*
|
||||
|
31
app/Http/Requests/EntryRequest.php
Normal file
31
app/Http/Requests/EntryRequest.php
Normal file
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class EntryRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'dn'=>'string|min:3',
|
||||
'objectclass'=>'array|min:1',
|
||||
];
|
||||
}
|
||||
}
|
@ -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
|
||||
*
|
||||
|
34
app/View/Components/Attribute.php
Normal file
34
app/View/Components/Attribute.php
Normal file
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace App\View\Components;
|
||||
|
||||
use Illuminate\View\Component;
|
||||
|
||||
use App\Classes\LDAP\Attribute as LDAPAttribute;
|
||||
|
||||
class Attribute extends Component
|
||||
{
|
||||
public LDAPAttribute $o;
|
||||
public bool $edit;
|
||||
|
||||
/**
|
||||
* Create a new component instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(bool $edit,LDAPAttribute $o)
|
||||
{
|
||||
$this->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);
|
||||
}
|
||||
}
|
67
public/js/custom.js
vendored
67
public/js/custom.js
vendored
@ -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('<div class="fa-3x"><i class="fas fa-spinner fa-pulse"></i></div>');
|
||||
}
|
||||
|
||||
}).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('<div class="fa-3x"><i class="fas fa-spinner fa-pulse"></i></div>');
|
||||
}
|
||||
|
||||
}).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);
|
||||
}
|
||||
});
|
||||
});
|
@ -15,9 +15,9 @@
|
||||
|
||||
<div class="modal-dialog w-100 mx-auto">
|
||||
<div class="modal-content">
|
||||
|
||||
<div class="modal-header">
|
||||
<div class="app-logo"><img class="w-50" src="{{ url('images/logo-h-lg.png') }}"></div>
|
||||
<img class="w-25" src="{{ url('images/logo-h-lg.png') }}">
|
||||
<span class="card-header-title text-danger ms-auto fs-4">@yield('title')</span>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
|
23
resources/views/components/attribute.blade.php
Normal file
23
resources/views/components/attribute.blade.php
Normal file
@ -0,0 +1,23 @@
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div id="{{ $o->name_lc }}">
|
||||
@foreach (old($o->name_lc,$o->values) as $value)
|
||||
@if ($edit && ! $o->is_rdn)
|
||||
<input class="form-control mb-1 @if($x=($o->values->search($value) === FALSE)) border-danger @endif" type="text" name="{{ $o->name_lc }}[]" value="{{ $value }}" @if($x)placeholder="{{ Arr::get($o->values,$loop->index) }}"@endif>
|
||||
@else
|
||||
{{ $value }}<br>
|
||||
@endif
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-sm-6 col-lg-4">
|
||||
@if($o->is_rdn)
|
||||
<span class="btn btn-sm btn-outline-focus mt-3 mb-3"><i class="fas fa-fw fa-exchange"></i> {{ __('Rename') }}</span>
|
||||
@elseif($edit && $o->can_addvalues)
|
||||
<div class="p-0 m-0 addable" id="{{ $o->name_lc }}">
|
||||
<span class="btn btn-sm btn-outline-primary mt-3 mb-3"><i class="fas fa-fw fa-plus"></i> {{ __('Add Value') }}</span>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
22
resources/views/dn.blade.php
Normal file
22
resources/views/dn.blade.php
Normal file
@ -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')
|
||||
<script type="text/javascript">
|
||||
var basedn = {!! $bases->toJson() !!};
|
||||
</script>
|
||||
@append
|
9
resources/views/errors/599.blade.php
Normal file
9
resources/views/errors/599.blade.php
Normal file
@ -0,0 +1,9 @@
|
||||
@extends('architect::layouts.error')
|
||||
|
||||
@section('title')
|
||||
599: @lang('Untrapped Error')
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
{{ $exception->getMessage() }}
|
||||
@endsection
|
@ -28,14 +28,44 @@
|
||||
@endsection
|
||||
|
||||
@section('main-content')
|
||||
@if(session()->has('note'))
|
||||
<div class="alert alert-info">
|
||||
<h4 class="alert-heading"><i class="fas fa-fw fa-note-sticky"></i> Note:</h4>
|
||||
<hr>
|
||||
<p>{{ session()->pull('note') }}</p>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if(session()->has('success'))
|
||||
<div class="alert alert-success">
|
||||
<h4 class="alert-heading"><i class="fas fa-fw fa-thumbs-up"></i> Success!</h4>
|
||||
<hr>
|
||||
<p>{{ session()->pull('success') }}</p>
|
||||
<ul style="list-style-type: square;">
|
||||
@foreach (session()->pull('updated') as $key => $values)
|
||||
<li>{{ $key }}: {{ join(',',$values) }}</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if($errors->any())
|
||||
<div class="alert alert-danger">
|
||||
<h4 class="alert-heading"><i class="fas fa-fw fa-thumbs-down"></i> Error?</h4>
|
||||
<hr>
|
||||
<ul style="list-style-type: square;">
|
||||
@foreach ($errors->all() as $error)
|
||||
<li>{{ $error }}</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="main-card mb-3 card">
|
||||
<div class="card-body">
|
||||
<div class="card-header-tabs">
|
||||
<ul class="nav nav-tabs">
|
||||
<li class="nav-item"><a data-bs-toggle="tab" href="#attributes" class="nav-link active">{{ __('Attributes') }}</a></li>
|
||||
{{--
|
||||
<li class="nav-item"><a data-bs-toggle="tab" href="#placeholder" class="nav-link">placeholder</a></li>
|
||||
--}}
|
||||
<li class="nav-item"><a data-bs-toggle="tab" href="#internal" class="nav-link">{{ __('Internal') }}</a></li>
|
||||
@env(['local'])
|
||||
<li class="nav-item"><a data-bs-toggle="tab" href="#debug" class="nav-link">{{ __('Debug') }}</a></li>
|
||||
@ -45,6 +75,11 @@
|
||||
<div class="tab-content">
|
||||
<!-- All Attributes -->
|
||||
<div class="tab-pane active" id="attributes" role="tabpanel">
|
||||
<form id="form-entry" method="POST" action="{{ url('entry/update') }}">
|
||||
@csrf
|
||||
|
||||
<input type="hidden" name="dn" value="{{ $o->getDNSecure() }}">
|
||||
|
||||
<div class="row">
|
||||
<div class="offset-2 col-8">
|
||||
<table class="table">
|
||||
@ -63,25 +98,22 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="ps-5">
|
||||
{!! $ao->deletable() !!}<br>
|
||||
@if ($ao->can_addvalues)
|
||||
<span class="p-0 m-0" id="add{{ $ao->name_lc }}"></span>
|
||||
<span class="btn btn-sm btn-outline-primary mt-3 mb-3"><i class="fas fa-plus"></i> {{ __('Add Value') }}</span>
|
||||
@endif
|
||||
<x-attribute :edit="true" :o="$ao"/>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{--
|
||||
<!-- Templates -->
|
||||
<div class="tab-pane" id="placeholder" role="tabpanel">
|
||||
<div><i class="fas fa-fw fa-spinner fa-pulse"></i></div>
|
||||
<div class="row">
|
||||
<div class="col-12 offset-sm-2 col-sm-4 col-lg-2">
|
||||
<span id="form-reset" class="btn btn-outline-danger">{{ __('Reset') }}</span>
|
||||
<span id="form-submit" class="btn btn-success">{{ __('Update') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
--}}
|
||||
|
||||
<!-- Internal Attributes -->
|
||||
<div class="tab-pane" id="internal" role="tabpanel">
|
||||
@ -96,7 +128,7 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="ps-5">
|
||||
{!! $ao !!}
|
||||
<x-attribute :edit="false" :o="$ao"/>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
@ -116,16 +148,29 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{{--
|
||||
<!-- Add Template -->
|
||||
<div class="tab-pane" id="addtemplate" role="tabpanel">
|
||||
<div><i class="fas fa-fw fa-spinner fa-pulse"></i></div>
|
||||
</div>
|
||||
--}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@section('page-scripts')
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
$('#reset').click(function() {
|
||||
$('#form-entry')[0].reset();
|
||||
})
|
||||
|
||||
$('#form-submit').click(function() {
|
||||
$('#form-entry')[0].submit();
|
||||
})
|
||||
|
||||
// Create a new entry when Add Value clicked
|
||||
$('.addable').click(function(item) {
|
||||
var cln = $(this).parent().parent().find('input:last').clone();
|
||||
cln.val('').attr('placeholder',undefined);
|
||||
cln.appendTo('#'+item.currentTarget.id)
|
||||
})
|
||||
});
|
||||
</script>
|
||||
@append
|
@ -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']);
|
Loading…
Reference in New Issue
Block a user