Compare commits
1 Commits
aaaed767d4
...
1e19213566
Author | SHA1 | Date | |
---|---|---|---|
1e19213566 |
@ -105,7 +105,6 @@ jobs:
|
||||
run: |
|
||||
registry=${{ github.server_url }}
|
||||
echo "registry=${registry##http*://}" >> "$GITHUB_OUTPUT"
|
||||
echo "version=$(cat public/VERISON)"
|
||||
|
||||
- name: Container Registry Login
|
||||
uses: docker/login-action@v2
|
||||
@ -145,7 +144,6 @@ jobs:
|
||||
|
||||
- name: Record version and Delete Unnecessary files
|
||||
run: |
|
||||
echo Building [${{ steps.registry.outputs.version }}]
|
||||
echo ${GITHUB_SHA::8} > VERSION
|
||||
rm -rf .git* tests/ storage/app/test/
|
||||
ls -al public/css/
|
||||
@ -158,7 +156,6 @@ jobs:
|
||||
file: docker/Dockerfile
|
||||
push: true
|
||||
tags: "${{ steps.registry.outputs.registry }}/${{ env.GITHUB_REPOSITORY }}:${{ env.VERSIONARCH }}"
|
||||
build-args: BUILD_REVISION=${GITHUB_SHA},BUILD_VERSION=${{ steps.registry.outputs.version }}
|
||||
|
||||
manifest:
|
||||
name: Final Docker Image Manifest
|
||||
|
@ -145,9 +145,9 @@ class Attribute implements \Countable, \ArrayAccess, \Iterator
|
||||
// Attribute values
|
||||
'values' => $this->values,
|
||||
// Required by Object Classes
|
||||
'required_by' => $this->schema?->required_by_object_classes ?: collect(),
|
||||
'required_by' => $this->schema->required_by_object_classes,
|
||||
// Used in Object Classes
|
||||
'used_in' => $this->schema?->used_in_object_classes ?: collect(),
|
||||
'used_in' => $this->schema->used_in_object_classes,
|
||||
|
||||
default => throw new \Exception('Unknown key:' . $key),
|
||||
};
|
||||
|
@ -1,51 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Classes\LDAP\Attribute;
|
||||
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
use App\Classes\LDAP\Attribute;
|
||||
|
||||
/**
|
||||
* Represents the RDN for an Entry
|
||||
*/
|
||||
final class RDN extends Attribute
|
||||
{
|
||||
private string $base;
|
||||
private Collection $objectclasses;
|
||||
|
||||
public function __get(string $key): mixed
|
||||
{
|
||||
return match ($key) {
|
||||
'base' => $this->base,
|
||||
default => parent::__get($key),
|
||||
};
|
||||
}
|
||||
|
||||
public function hints(): array
|
||||
{
|
||||
return [
|
||||
'required' => __('RDN is required')
|
||||
];
|
||||
}
|
||||
|
||||
public function render(bool $edit=FALSE,bool $old=FALSE,bool $new=FALSE): View
|
||||
{
|
||||
return view('components.attribute.rdn')
|
||||
->with('o',$this);
|
||||
}
|
||||
|
||||
public function setBase(string $base): void
|
||||
{
|
||||
$this->base = $base;
|
||||
}
|
||||
|
||||
public function setObjectClasses(array $classes): void
|
||||
{
|
||||
$this->objectclasses = collect();
|
||||
|
||||
foreach ($classes as $class)
|
||||
$this->objectclasses->push(cofig('server')->schema('objectclasses',$class));
|
||||
}
|
||||
}
|
@ -91,27 +91,20 @@ class HomeController extends Controller
|
||||
*
|
||||
* @param EntryAdd $request
|
||||
* @return Factory|View|Application|object
|
||||
* @throws InvalidUsage
|
||||
*/
|
||||
public function entry_add(EntryAdd $request)
|
||||
{
|
||||
switch ($request->step) {
|
||||
case 1:
|
||||
$container = Crypt::decryptString($request->dn);
|
||||
|
||||
$o = new Entry;
|
||||
$o->objectclass = $request->objectclass;
|
||||
$o->setRDNBase($container);
|
||||
|
||||
return view('frame')
|
||||
->with('subframe',$request->frame)
|
||||
->with('bases',$this->bases())
|
||||
->with('o',$o)
|
||||
->with('o',config('server')->fetch($x=Crypt::decryptString($request->dn)))
|
||||
->with('step',$request->step)
|
||||
->with('dn',$container);
|
||||
->with('dn',$x);
|
||||
|
||||
default:
|
||||
throw new InvalidUsage('Invalid entry step');
|
||||
dd($request);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,14 +12,11 @@ use App\Classes\LDAP\Attribute;
|
||||
use App\Classes\LDAP\Attribute\Factory;
|
||||
use App\Classes\LDAP\Export\LDIF;
|
||||
use App\Exceptions\Import\AttributeException;
|
||||
use App\Exceptions\InvalidUsage;
|
||||
|
||||
class Entry extends Model
|
||||
{
|
||||
private Collection $objects;
|
||||
private bool $noObjectAttributes = FALSE;
|
||||
// For new entries, this is the container that this entry will be stored in
|
||||
private string $rdnbase;
|
||||
|
||||
/* OVERRIDES */
|
||||
|
||||
@ -49,7 +46,7 @@ class Entry extends Model
|
||||
public function getAttributes(): array
|
||||
{
|
||||
return $this->objects
|
||||
->map(fn($item)=>$item->values)
|
||||
->map(fn($item)=>$item->values->toArray())
|
||||
->toArray();
|
||||
}
|
||||
|
||||
@ -95,7 +92,10 @@ class Entry extends Model
|
||||
$key = $this->normalizeAttributeKey($key);
|
||||
|
||||
if ((! $this->objects->get($key)) && $value) {
|
||||
$this->objects->put($key,Factory::create($key,[$value]));
|
||||
$o = new Attribute($key,[]);
|
||||
$o->value = $value;
|
||||
|
||||
$this->objects->put($key,$o);
|
||||
|
||||
} elseif ($this->objects->get($key)) {
|
||||
$this->objects->get($key)->value = $this->attributes[$key];
|
||||
@ -265,12 +265,8 @@ class Entry extends Model
|
||||
*/
|
||||
public function getObject(string $key): Attribute|null
|
||||
{
|
||||
return match ($key) {
|
||||
'rdn' => $this->getRDNObject(),
|
||||
|
||||
default => $this->objects
|
||||
->get($this->normalizeAttributeKey($key))
|
||||
};
|
||||
return $this->objects
|
||||
->get($this->normalizeAttributeKey($key));
|
||||
}
|
||||
|
||||
public function getObjects(): Collection
|
||||
@ -293,14 +289,6 @@ class Entry extends Model
|
||||
->filter(fn($a)=>(! $this->getVisibleAttributes()->contains(fn($b)=>($a->name === $b->name))));
|
||||
}
|
||||
|
||||
private function getRDNObject(): Attribute\RDN
|
||||
{
|
||||
$o = new Attribute\RDN('dn',[' ']);
|
||||
$o->setBase($this->rdnbase); // @todo for an existing object, return the base.
|
||||
|
||||
return $o;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return this list of user attributes
|
||||
*
|
||||
@ -425,12 +413,4 @@ class Entry extends Model
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setRDNBase(string $bdn): void
|
||||
{
|
||||
if ($this->exists)
|
||||
throw new InvalidUsage('Cannot set RDN base on existing entries');
|
||||
|
||||
$this->rdnbase = $bdn;
|
||||
}
|
||||
}
|
@ -48,20 +48,8 @@ return [
|
||||
'base_dn' => env('LDAP_BASE_DN', 'dc=local,dc=com'),
|
||||
'timeout' => env('LDAP_TIMEOUT', 5),
|
||||
'use_ssl' => env('LDAP_SSL', true),
|
||||
'use_tls' => env('LDAP_TLS', false),
|
||||
'name' => env('LDAP_NAME','LDAPS Server'),
|
||||
],
|
||||
|
||||
'openldaptls' => [
|
||||
'hosts' => [env('LDAP_HOST', '127.0.0.1')],
|
||||
'username' => env('LDAP_USERNAME', 'cn=user,dc=local,dc=com'),
|
||||
'password' => env('LDAP_PASSWORD', 'secret'),
|
||||
'port' => env('LDAP_PORT', 389),
|
||||
'base_dn' => env('LDAP_BASE_DN', 'dc=local,dc=com'),
|
||||
'timeout' => env('LDAP_TIMEOUT', 5),
|
||||
'use_ssl' => env('LDAP_SSL', false),
|
||||
'use_tls' => env('LDAP_TLS', true),
|
||||
'name' => env('LDAP_NAME','LDAP-TLS Server'),
|
||||
'name' => env('LDAP_NAME','LDAPS Server'),
|
||||
],
|
||||
|
||||
'opendj' => [
|
||||
|
@ -1,17 +1,5 @@
|
||||
FROM dunglas/frankenphp:php8.4-alpine
|
||||
|
||||
ARG BUILD_VERSION=2.0.0-dev
|
||||
ARG BUILD_REVISION=00000000
|
||||
|
||||
LABEL org.opencontainers.image.vendor="Deon George"
|
||||
LABEL org.opencontainers.image.licenses=GPLv2
|
||||
LABEL org.opencontainers.image.source=https://github.com/leenooks/phpldapadmin
|
||||
LABEL org.opencontainers.image.title=phpLDAPadmin
|
||||
LABEL org.opencontainers.image.description="An LDAP Administration Tool"
|
||||
LABEL org.opencontainers.image.url=https://phpldapadmin.org
|
||||
LABEL org.opencontainers.image.version=${BUILD_VERSION}
|
||||
LABEL org.opencontainers.image.revision=${BUILD_REVISION}
|
||||
|
||||
# Base
|
||||
RUN apk add --no-cache bash
|
||||
|
||||
|
4
public/css/fixes.css
vendored
4
public/css/fixes.css
vendored
@ -304,7 +304,3 @@ div#objectClass .input-group-delete {
|
||||
right: 10px;
|
||||
height: 5px;
|
||||
}
|
||||
|
||||
.input-group-text {
|
||||
background-color: #fafafa;
|
||||
}
|
@ -4,7 +4,7 @@
|
||||
<div class="col-12 col-sm-10 col-md-8">
|
||||
<div class="row">
|
||||
<div class="col-12 bg-light text-dark p-2">
|
||||
<strong><abbr title="{{ $o->description }}">{{ $o->name }}</abbr></strong>
|
||||
<strong><abbr title="{{ $o->description }}" data-attr-name="{{ $o->name_lc }}" data-attr-required="{{ $o->required_by->intersect($oc)->join('|') }}" data-oc="{{ $oc->count() ? $o->required_by->keys()->intersect($oc)->join('|') : $o->used_in->keys()->join('|') }}">{{ $o->name }}</abbr></strong>
|
||||
<!-- Attribute Hints -->
|
||||
<span class="float-end small">
|
||||
@foreach($o->hints as $name => $description)
|
||||
|
@ -1,25 +0,0 @@
|
||||
<!-- $o=RDN::class -->
|
||||
<x-attribute.layout :edit="$edit ?? FALSE" :new="$new ?? FALSE" :o="$o">
|
||||
@foreach($o->values as $value)
|
||||
@if($edit)
|
||||
<div class="input-group has-validation mb-3">
|
||||
<x-form.select
|
||||
name="rdn"
|
||||
:options="[]"
|
||||
/>
|
||||
|
||||
<span class="input-group-text">=</span>
|
||||
<input type="text" @class(['form-control','is-invalid'=>($e=$errors->get($o->name_lc.'.'.$loop->index)),'border-focus'=>$o->values->contains($value)]) name="rdn" placeholder="rdn">
|
||||
<label class="input-group-text" for="inputGroupSelect02">,{{ $o->base }}</label>
|
||||
|
||||
<div class="invalid-feedback pb-2">
|
||||
@if($e)
|
||||
{{ join('|',$e) }}
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
@else
|
||||
{{ $value }}
|
||||
@endif
|
||||
@endforeach
|
||||
</x-attribute.layout>
|
@ -75,6 +75,10 @@
|
||||
if (added_oc.sort().join('|') == newadded.sort().join('|'))
|
||||
return;
|
||||
|
||||
var attrs = $('[data-attr-name]').map(function() {
|
||||
return $(this).data('attrName');
|
||||
});
|
||||
|
||||
// Find out what was selected, and add them
|
||||
newadded.forEach(function (item) {
|
||||
if (added_oc.indexOf(item) !== -1)
|
||||
@ -147,6 +151,7 @@
|
||||
url: '{{ url('api/schema/objectclass/attrs') }}/'+item,
|
||||
cache: false
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
// Loop through added_oc, and remove anything not in newadded
|
||||
|
@ -52,7 +52,7 @@
|
||||
theme: 'bootstrap-5',
|
||||
dropdownAutoWidth: true,
|
||||
width: 'style',
|
||||
allowClear: {{ $allowclear ?? 'false' }},
|
||||
allowClear: {{ $allowclear ?? 'true' }},
|
||||
placeholder: '{{ $placeholder ?? '' }}',
|
||||
multiple: {{ $multiple ?? 'false' }},
|
||||
@isset($addvalues)
|
||||
|
@ -5,15 +5,10 @@
|
||||
@endsection
|
||||
|
||||
@section('main-content')
|
||||
<div class="row">
|
||||
<p class="alert alert-danger text-center">
|
||||
This is a tech preview of what is to come, and it is by no means complete.
|
||||
</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="offset-1 col-10">
|
||||
<div class="main-card mb-3 card">
|
||||
<form id="create-form" action="{{ url('entry/add') }}" method="POST" enctype="multipart/form-data">
|
||||
<form id="import-form" action="{{ url('entry/add') }}" method="POST" enctype="multipart/form-data">
|
||||
@csrf
|
||||
<input type="hidden" name="frame" value="create">
|
||||
<input type="hidden" name="dn" value="{{ Crypt::encryptString($dn) }}">
|
||||
@ -30,11 +25,12 @@
|
||||
<div class="col-12 col-sm-6">
|
||||
<x-form.select
|
||||
name="objectclass"
|
||||
:label="__('Select a Structural ObjectClass...')"
|
||||
:label="__('Select a Structural Object Class...')"
|
||||
:options="($oc=config('server')->schema('objectclasses'))
|
||||
->filter(fn($item)=>$item->isStructural())
|
||||
->sortBy(fn($item)=>$item->name_lc)
|
||||
->map(fn($item,$key)=>['id'=>$key,'value'=>$item->name])"
|
||||
allowclear="false"
|
||||
multiple="false"
|
||||
/>
|
||||
</div>
|
||||
@ -44,46 +40,16 @@
|
||||
|
||||
@case(2)
|
||||
<div class="card-body">
|
||||
<x-attribute-type :edit="true" :o="$o->getObject('rdn')"/>
|
||||
|
||||
@foreach ($o->getVisibleAttributes() as $ao)
|
||||
<x-attribute-type :edit="true" :o="$ao"/>
|
||||
@endforeach
|
||||
|
||||
<div id="newattrs"></div>
|
||||
|
||||
<!-- 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">
|
||||
|
||||
@if($o->getMissingAttributes()->count())
|
||||
<div class="row">
|
||||
<div class="col-12 bg-dark text-light p-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')->map(fn($item)=>['id'=>$item->name,'value'=>$item->name_lc])"/>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-2"></div>
|
||||
</div>
|
||||
|
||||
<div class="row pt-3">
|
||||
<div class="col-12 offset-sm-2 col-sm-4 col-lg-2">
|
||||
<x-form.reset form="dn-add"/>
|
||||
<x-form.submit action="Create" form="dn-add"/>
|
||||
<div class="col-12 col-sm-6">
|
||||
<p class="alert alert-danger">
|
||||
Not ready yet :)
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@break;
|
||||
|
||||
@endswitch
|
||||
|
||||
<div class="card-footer">
|
||||
@ -96,68 +62,3 @@
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@section('page-scripts')
|
||||
<script type="text/javascript">
|
||||
var dn = '{{ $o->getDNSecure() }}';
|
||||
var oc = {!! $o->getObject('objectclass')->values !!};
|
||||
|
||||
function editmode() {
|
||||
$('#dn-edit input[name="dn"]').val(dn);
|
||||
|
||||
$('button[id=entry-edit]').addClass('active').removeClass('btn-outline-dark').addClass('btn-outline-light');
|
||||
|
||||
// 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
|
||||
$('div#userPassword .form-select').each(function() {
|
||||
$(this).prop('disabled',false);
|
||||
})
|
||||
|
||||
$('.row.d-none').removeClass('d-none');
|
||||
$('.addable.d-none').removeClass('d-none');
|
||||
$('.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();
|
||||
});
|
||||
|
||||
editmode();
|
||||
});
|
||||
</script>
|
||||
@append
|
@ -31,7 +31,7 @@
|
||||
<input type="hidden" name="dn" value="">
|
||||
|
||||
@foreach ($o->getVisibleAttributes() as $ao)
|
||||
<x-attribute-type :edit="true" :o="$ao"/>
|
||||
<x-attribute-type :edit="true" :o="$ao" :oc="collect($o->objectclass)"/>
|
||||
@endforeach
|
||||
|
||||
<div id="newattrs"></div>
|
||||
|
Loading…
x
Reference in New Issue
Block a user