Deon George 49fd9b419a
All checks were successful
Create Docker Image / Test Application (x86_64) (push) Successful in 30s
Create Docker Image / Build Docker Image (x86_64) (push) Successful in 1m29s
Create Docker Image / Build Docker Image (arm64) (push) Successful in 4m38s
Create Docker Image / Final Docker Image Manifest (push) Successful in 9s
Some jquery selector changes, change some button spans to buttons, set readonly on the form for attribute javascript, fix krbTicketFlags to only be changed when in edit mode
2025-03-13 09:33:45 +11:00

328 lines
9.7 KiB
PHP

@extends('layouts.dn')
@section('page_title')
@include('fragment.dn.header',['o'=>($o ?? $o=config('server')->fetch($dn))])
@endsection
@section('main-content')
<x-note/>
<x-updated/>
<x-error/>
<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">@lang('Attributes')</a></li>
<li class="nav-item"><a data-bs-toggle="tab" href="#internal" class="nav-link">@lang('Internal')</a></li>
@env(['local'])
<li class="nav-item"><a data-bs-toggle="tab" href="#debug" class="nav-link">@lang('Debug')</a></li>
@endenv
</ul>
<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="">
@foreach ($o->getVisibleAttributes() as $ao)
<x-attribute-type :edit="true" :o="$ao"/>
@endforeach
@include('fragment.dn.add_attr')
</form>
<div class="row d-none pt-3">
<div class="col-12 offset-sm-2 col-sm-4 col-lg-2">
<x-form.reset form="dn-edit"/>
<x-form.submit action="Update" form="dn-edit"/>
</div>
</div>
</div>
<!-- Internal Attributes -->
<div class="tab-pane" id="internal" role="tabpanel">
@foreach ($o->getInternalAttributes() as $ao)
<x-attribute-type :o="$ao"/>
@endforeach
</div>
<!-- Debug -->
<div class="tab-pane" id="debug" role="tabpanel">
<div class="row">
<div class="col-4">
@dump($o)
</div>
<div class="col-4">
@dump($o->getAttributes())
</div>
<div class="col-4">
@dump(['available'=>$o->getAvailableAttributes()->pluck('name'),'missing'=>$o->getMissingAttributes()->pluck('name')])
</div>
</div>
</div>
</div>
</div>
</div>
</div>
@endsection
@section('page-modals')
<!-- Frame Modals -->
<div class="modal fade" id="page-modal" tabindex="-1" aria-labelledby="label" aria-hidden="true">
<div class="modal-dialog modal-lg modal-fullscreen-lg-down">
<div class="modal-content"></div>
</div>
</div>
<!-- EXPORT -->
<div class="modal fade" id="entry_export-modal" tabindex="-1" aria-labelledby="entry_export-label" aria-hidden="true">
<div class="modal-dialog modal-lg modal-fullscreen-lg-down">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="entry_export-label">LDIF for {{ $dn }}</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div id="entry_export"><div class="fa-3x"><i class="fas fa-spinner fa-pulse fa-sm"></i></div></div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-sm btn-secondary" data-bs-dismiss="modal">Close</button>
<button type="button" class="btn btn-sm btn-primary" id="entry_export-download">Download</button>
</div>
</div>
</div>
</div>
@if($up=$o->getObject('userpassword'))
<!-- CHECK USERPASSWORD -->
<div class="modal fade" id="userpassword_check-modal" tabindex="-1" aria-labelledby="userpassword_check-label" aria-hidden="true">
<div class="modal-dialog modal-lg modal-fullscreen-lg-down">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="userpassword_check-label">Check Passwords for {{ $dn }}</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<table class="table table-bordered p-1">
@foreach($up->values as $key => $value)
<tr>
<th>Check</th>
<td>{{ $up->render_item_old($key) }}</td>
<td>
<input type="password" style="width: 90%" name="password[{{$key}}]"> <i class="fas fa-fw fa-lock"></i>
<div class="invalid-feedback pb-2">
Invalid Password
</div>
</td>
</tr>
@endforeach
</table>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-sm btn-secondary" data-bs-dismiss="modal">Close</button>
<button type="button" class="btn btn-sm btn-primary" id="userpassword_check-submit"><i class="fas fa-fw fa-spinner fa-spin d-none"></i> Check</button>
</div>
</div>
</div>
</div>
@endif
@endsection
@section('page-scripts')
<script type="text/javascript">
var dn = '{{ $o->getDNSecure() }}';
var oc = {!! $o->getObject('objectclass')->values !!};
function download(filename,text) {
var element = document.createElement('a');
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
element.setAttribute('download', filename);
element.style.display = 'none';
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
}
function editmode() {
$('#dn-edit input[name="dn"]').val(dn);
$('form#dn-edit').attr('readonly',false);
$('button[id=entry-edit]')
.removeClass('btn-outline-dark')
.addClass('btn-dark')
.addClass('opacity-100')
.attr('disabled',true);
// Find all input items and turn off readonly
$('input.form-control').each(function() {
// Except for objectClass - @todo show an "X" instead
if ($(this)[0].name.match(/^objectclass/))
return;
$(this).attr('readonly',false);
});
// Our password type
$('attribute#userPassword .form-select').each(function() {
$(this).prop('disabled',false);
})
$('.row.d-none').removeClass('d-none');
$('button.addable.d-none').removeClass('d-none');
$('button.deletable.d-none').removeClass('d-none');
@if($o->getMissingAttributes()->count())
$('#newattr-select.d-none').removeClass('d-none');
@endif
}
$(document).ready(function() {
$('#newattr').on('change',function(item) {
$.ajax({
type: 'POST',
beforeSend: function() {},
success: function(data) {
$('#newattrs').append(data);
},
error: function(e) {
if (e.status != 412)
alert('That didnt work? Please try again....');
},
url: '{{ url('entry/attr/add') }}/'+item.target.value,
data: {
objectclasses: oc,
},
cache: false
});
// Remove the option from the list
$(this).find('[value="'+item.target.value+'"]').remove()
// If there are no more options
if ($(this).find("option").length === 1)
$('#newattr-select').remove();
});
$('#entry_export-download').on('click',function(item) {
item.preventDefault();
let ldif = $('#entry_export').find('pre:first'); // update this selector in your local version
download('ldap-export.ldif',ldif.html());
});
$('#page-modal').on('shown.bs.modal',function(item) {
var that = $(this).find('.modal-content');
switch ($(item.relatedTarget).attr('id')) {
case 'entry-delete':
$.ajax({
method: 'GET',
url: '{{ url('modal/delete') }}/'+dn,
dataType: 'html',
cache: false,
beforeSend: function() {
that.empty().append('<span class="p-3"><i class="fas fa-3x fa-spinner fa-pulse"></i></span>');
},
success: function(data) {
that.empty().html(data);
},
error: function(e) {
if (e.status != 412)
alert('That didnt work? Please try again....');
},
})
break;
default:
console.log('No action for button:'+$(item.relatedTarget).attr('id'));
}
});
$('#entry_export-modal').on('shown.bs.modal',function() {
$.ajax({
type: 'GET',
success: function(data) {
$('#entry_export').empty().append(data);
},
error: function(e) {
if (e.status != 412)
alert('That didnt work? Please try again....');
},
url: '{{ url('entry/export') }}/'+dn,
cache: false
})
})
@if($up)
$('button[id=userpassword_check-submit]').on('click',function(item) {
var that = $(this);
var passwords = $('#userpassword_check-modal')
.find('input[name^="password["')
.map((key,item)=>item.value);
if (passwords.length === 0) return false;
$.ajax({
type: 'POST',
beforeSend: function() {
// Disable submit, add spinning icon
that.prop('disabled',true);
that.find('i').removeClass('d-none');
},
complete: function() {
that.prop('disabled',false);
that.find('i').addClass('d-none');
},
success: function(data) {
data.forEach(function(item,key) {
var i = $('#userpassword_check-modal')
.find('input[name="password['+key+']')
.siblings('i');
var feedback = $('#userpassword_check-modal')
.find('input[name="password['+key+']')
.siblings('div.invalid-feedback');
if (item === 'OK') {
i.removeClass('text-danger').addClass('text-success').removeClass('fa-lock').addClass('fa-lock-open');
if (feedback.is(':visible'))
feedback.hide();
} else {
i.removeClass('text-success').addClass('text-danger').removeClass('fa-lock-open').addClass('fa-lock');
if (! feedback.is(':visible'))
feedback.show();
}
})
},
error: function(e) {
if (e.status != 412)
alert('That didnt work? Please try again....');
},
url: '{{ url('entry/password/check') }}',
data: {
dn: dn,
password: Array.from(passwords),
},
dataType: 'json',
cache: false
})
});
@endif
@if(old())
editmode();
@endif
});
</script>
@append