Compare commits

...

3 Commits

Author SHA1 Message Date
89d414ccd9 Revert version to 2.1.3-dev
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 1m23s
Create Docker Image / Build Docker Image (arm64) (push) Successful in 4m36s
Create Docker Image / Final Docker Image Manifest (push) Successful in 9s
2025-05-03 20:27:16 +10:00
ffb98631a6 Implemented search via the top menu 2025-05-03 20:27:16 +10:00
be69e22867 Update home page 2025-05-03 20:27:16 +10:00
6 changed files with 179 additions and 11 deletions

View File

@ -3,7 +3,7 @@ run-name: ${{ gitea.actor }} Building Docker Image 🐳
on: [push]
env:
DOCKER_HOST: tcp://127.0.0.1:2375
ASSETS: c2780a3
ASSETS: 10eca55
jobs:
test:

View File

@ -0,0 +1,59 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Str;
use App\Ldap\Entry;
class SearchController extends Controller
{
public function search(Request $request): Collection
{
$so = config('server');
// We are searching for a value
if (strpos($request->term,'=')) {
list($attr,$value) = explode('=',$request->term,2);
$value = trim($value);
$result = collect();
foreach ($so->baseDNs() as $base) {
$search = (new Entry)
->in($base);
$search = ($x=Str::startsWith($value,'*'))
? $search->whereEndsWith($attr,substr($value,1))
: $search->whereStartsWith($attr,$value);
$result = $result->merge($search->get());
}
return $result
->map(fn($item)=>[
'name'=>$item->getDN(),
'value'=>Crypt::encryptString($item->getDN()),
'category'=>sprintf('%s: [%s=%s%s]',__('Result'),$attr,$value,($x ? '' : '*'))
]);
// We are searching for an attribute
} else {
$attrs = $so
->schema('attributetypes')
->sortBy('name')
->filter(fn($item)=>Str::contains($item->name_lc,$request->term));
return $attrs
->map(fn($item)=>[
'name'=>$item->name,
'value'=>'',
'category'=>__('Select attribute...')
])
->values();
}
}
}

View File

@ -1 +1 @@
v2.1.2-rel
v2.1.3-dev

View File

@ -33,8 +33,12 @@
<div class="app-header-left">
<div class="search-wrapper">
<div class="input-holder">
<input type="text" class="search-input" placeholder="Type to search">
<button class="search-icon"><span></span></button>
<input type="text" class="search-input" id="search" placeholder="Type to search">
<button class="search-icon">
<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>
<button class="btn-close"></button>
</div>
@ -160,6 +164,13 @@
</div>
@section('page-scripts')
<style>
#search_results ul.typeahead.dropdown-menu {
overflow: scroll;
max-height: 300px;
}
</style>
<script type="text/javascript">
$(document).ready(function() {
$('button[id^="link-"]').on('click',function(item) {
@ -190,6 +201,70 @@
return false;
});
$('.search-wrapper input[id="search"]').typeahead({
autoSelect: false,
scrollHeight: 10,
theme: 'bootstrap5',
delay: 500,
minLength: 2,
items: {{ $search_limit ?? 100 }},
selectOnBlur: false,
appendTo: "#search_results",
source: function(query,process) {
search('{{ url('search') }}',query,process);
},
// Disable sorting and just return the items (items should be sorted by the ajax method)
sorter: function(items) {
return items;
},
matcher: function() { return true; },
// Disable sorting and just return the items (items should by the ajax method)
updater: function(item) {
// If item has a data value, then we'll use that
if (item.data && item.data.length)
return item.data;
if (! item.value)
return item.name+'=';
location.replace('/#'+item.value);
location.reload();
return '';
},
})
.on('keyup keypress',function(event) {
var key = event.keyCode || event.which;
if (key === 13) {
event.preventDefault();
return false;
}
});
});
var search = _.debounce(function(url,query,process){
$.ajax({
url : url,
type : 'POST',
data : 'term=' + query,
dataType : 'JSON',
async : true,
cache : false,
beforeSend : function() {
$('.search-wrapper div#searching').removeClass('d-none');
$('.search-wrapper .search-icon span').addClass('d-none');
},
success : function(data) {
// if json is null, means no match, won't do again.
if(data==null || (data.length===0)) return;
process(data);
},
complete : function() {
$('.search-wrapper div#searching').addClass('d-none');
$('.search-wrapper .search-icon span').removeClass('d-none');
}
})
}, 500);
</script>
@append

View File

@ -23,18 +23,51 @@
</div>
<div class="col-12 col-sm-8">
<h3 class="mb-1">Welcome to phpLDAPadmin</h3>
<h4 class="mb-3"><small>{{ config('app.version') }}</small></h4>
<p>phpLDAPadmin (or PLA for short) is an LDAP data management tool for administrators.</p>
<p>PLA aims to adhere to the LDAP standards so that it can interact with any LDAP server that implements those standards.</p>
<h1 class="mb-2">Welcome to phpLDAPadmin</h1>
<p>phpLDAPadmin (or PLA for short) is an LDAP (Lightweight Directory Access Protocol) data management tool for administrators.</p>
<p>PLA provides an easy-to-use interface for browsing, searching, and modifying data in an LDAP directory. Essentially, it's a user-friendly alternative to using command-line tools for LDAP management.</p>
</div>
</div>
<div class="row">
<div class="col-12">
<hr>
<p>Version 2 is a complete re-write of PLA, leveraging the advancements and modernisation of web tools and methods, libraries since version 1 was released.</p>
<p>You can support this application by letting us know which LDAP server you use (including version and platform).</p>
</div>
</div>
<div class="row">
<div class="col-12 col-sm-4">
<span class="text-dark">
<a class="link-opacity-50 link-opacity-100-hover link-dark" href="https://phpldapadmin.org"><i class="fas fa-fw fa-2x fa-globe me-1"></i></a>
<a class="link-opacity-50 link-opacity-100-hover link-dark" href="https://github.com/leenooks/phpldapadmin"><i class="fab fa-fw fa-2x fa-github me-1"></i></a>
<a class="link-opacity-50 link-opacity-100-hover link-dark" href="https://github.com/leenooks/phpLDAPadmin/discussions"><i class="fas fa-fw fa-2x fa-hand me-1"></i></a>
<a class="link-opacity-50 link-opacity-100-hover link-dark" href="https://github.com/leenooks/phpLDAPadmin/issues"><i class="fas fa-fw fa-2x fa-bug me-1"></i></a>
<a class="link-opacity-50 link-opacity-100-hover link-dark" href="https://hub.docker.com/r/phpldapadmin/phpldapadmin"><i class="fab fa-fw fa-2x fa-docker me-1"></i></a>
</span>
</div>
<div class="col-12 col-sm-8 col-xl-4">
<h5>Key Features and Functionality</h5>
<ul class="list-unstyled">
<li class="ps-0 p-1">
<i class="fas fa-fw fa-globe me-2"></i> Easy To Use Web Interface
</li>
<li class="ps-0 p-1">
<i class="fas fa-fw fa-sitemap me-2"></i> Hierarchical Tree View
</li>
<li class="ps-0 p-1">
<i class="fas fa-fw fa-language me-2"></i> Multi-language Support
</li>
<li class="ps-0 p-1">
<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
</li>
<li class="ps-0 p-1">
<i class="fas fa-fw fa-pen-to-square me-2"></i> Open Source
</li>
</ul>
</div>
</div>
</div>

View File

@ -2,7 +2,7 @@
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\{AjaxController,HomeController};
use App\Http\Controllers\{AjaxController,HomeController,SearchController};
use App\Http\Controllers\Auth\LoginController;
use App\Http\Middleware\AllowAnonymous;
@ -27,6 +27,7 @@ Auth::routes([
]);
Route::get('logout',[LoginController::class,'logout']);
Route::post('search',[SearchController::class,'search']);
Route::controller(HomeController::class)->group(function() {
Route::middleware(AllowAnonymous::class)->group(function() {