Merge pull request #1454 from knom/2.x

Enable/Disable Items with authentification headers
This commit is contained in:
KodeStar
2025-07-10 19:24:57 +01:00
committed by GitHub
28 changed files with 325 additions and 39 deletions

View File

@@ -48,3 +48,9 @@ PUSHER_APP_CLUSTER=mt1
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
AUTH_ROLES_ENABLE=false
AUTH_ROLES_HEADER="remote-groups"
AUTH_ROLES_HTTP_HEADER="HTTP_REMOTE_GROUPS"
AUTH_ROLES_ADMIN="admin"
AUTH_ROLES_DELIMITER=","

15
.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,15 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Listen for Xdebug",
"type": "php",
"request": "launch",
"port": 9003,
"pathMappings": {
"/var/www/html": "${workspaceFolder}"
}
}
]
}

16
.vscode/tasks.json vendored Normal file
View File

@@ -0,0 +1,16 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "Start Docker Compose",
"type": "shell",
"command": "docker-compose up --build",
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": []
}
]
}

View File

@@ -33,34 +33,59 @@ class ItemController extends Controller
/**
* Display a listing of the resource on the dashboard.
*/
public function dash(): View
public function dash(Request $request): View
{
$treat_tags_as = \App\Setting::fetch('treat_tags_as');
$data["treat_tags_as"] = $treat_tags_as;
if ($treat_tags_as == 'categories') {
$data['categories'] = Item::whereHas('children')->with('children', function ($query) {
$query->pinned()->orderBy('order', 'asc');
})->pinned()->orderBy('order', 'asc')->get();
if (config('app.auth_roles_enable')) {
$roles = explode(config('app.auth_roles_delimiter'), $request->header(config('app.auth_roles_header')));
if ($treat_tags_as == 'categories') {
$data['categories'] = Item::whereHas('children')->with('children', function ($query) {
$query->pinned()->orderBy('order', 'asc');
})->pinned()->orderBy('order', 'asc')->get();
} elseif ($treat_tags_as == 'tags') {
$data['apps'] = Item::with('parents')->where('type', 0)->pinned()->orderBy('order', 'asc')->get();
$data['all_apps'] = Item::where('type', 0)->orderBy('order', 'asc')->get();
$data['taglist'] = Item::where('id', 0)->orWhere(function($query) {
$query->where('type', 1)->pinned();
})->orderBy('order', 'asc')->get();
} elseif ($treat_tags_as == 'tags') {
$data['apps'] = Item::with('parents')->where('type', 0)->pinned()->orderBy('order', 'asc')->get();
$data['all_apps'] = Item::where('type', 0)->orderBy('order', 'asc')->get();
$data['taglist'] = Item::where('id', 0)->orWhere(function($query) {
$query->where('type', 1)->pinned();
})->orderBy('order', 'asc')->get();
} else {
$data['apps'] = Item::whereHas('parents', function ($query) {
$query->where('id', 0);
})->whereIn('role', $roles)->orWhere('type', 1)->pinned()->orderBy('order', 'asc')->get();
$data['all_apps'] = Item::whereHas('parents', function ($query) {
$query->where('id', 0);
})->orWhere('type', 1)->orderBy('order', 'asc')->get();
}
} else {
if ($treat_tags_as == 'categories') {
$data['categories'] = Item::whereHas('children')->with('children', function ($query) {
$query->pinned()->orderBy('order', 'asc');
})->pinned()->orderBy('order', 'asc')->get();
$data['apps'] = Item::whereHas('parents', function ($query) {
$query->where('id', 0);
})->orWhere('type', 1)->pinned()->orderBy('order', 'asc')->get();
} elseif ($treat_tags_as == 'tags') {
$data['apps'] = Item::with('parents')->where('type', 0)->pinned()->orderBy('order', 'asc')->get();
$data['all_apps'] = Item::where('type', 0)->orderBy('order', 'asc')->get();
$data['taglist'] = Item::where('id', 0)->orWhere(function($query) {
$query->where('type', 1)->pinned();
})->orderBy('order', 'asc')->get();
} else {
$data['all_apps'] = Item::whereHas('parents', function ($query) {
$query->where('id', 0);
})->orWhere(function ($query) {
$query->where('type', 1)->whereNot('id', 0);
})->orderBy('order', 'asc')->get();
$data['apps'] = Item::whereHas('parents', function ($query) {
$query->where('id', 0);
})->orWhere('type', 1)->pinned()->orderBy('order', 'asc')->get();
$data['all_apps'] = Item::whereHas('parents', function ($query) {
$query->where('id', 0);
})->orWhere(function ($query) {
$query->where('type', 1)->whereNot('id', 0);
})->orderBy('order', 'asc')->get();
}
}
//$data['all_apps'] = Item::doesntHave('parents')->get();

View File

@@ -88,11 +88,16 @@ class TagController extends Controller
*
* @param $slug
*/
public function show($slug): View
public function show($slug, Request $request): View
{
$item = Item::whereUrl($slug)->first();
//print_r($item);
$data['apps'] = $item->children()->pinned()->orderBy('order', 'asc')->get();
if (config('app.auth_roles_enable')) {
$roles = explode(config('app.auth_roles_delimiter'), $request->header(config('app.auth_roles_header')));
$data['apps'] = $item->children()->whereIn('role', $roles)->pinned()->orderBy('order', 'asc')->get();
} else {
$data['apps'] = $item->children()->pinned()->orderBy('order', 'asc')->get();
}
$data['tag'] = $item->id;
$data['all_apps'] = $item->children;

View File

@@ -33,6 +33,7 @@ use Symfony\Component\ClassLoader\ClassMapGenerator;
* @property string|null $class
* @property string|null $appid
* @property string|null $appdescription
* @property string|null $role
* @property-read \Illuminate\Database\Eloquent\Collection|Item[] $children
* @property-read int|null $children_count
* @property-read string $droppable
@@ -51,6 +52,7 @@ use Symfony\Component\ClassLoader\ClassMapGenerator;
* @method static Builder|Item pinned()
* @method static Builder|Item query()
* @method static Builder|Item whereAppdescription($value)
* @method static Builder|Item whereRole($value)
* @method static Builder|Item whereAppid($value)
* @method static Builder|Item whereClass($value)
* @method static Builder|Item whereColour($value)
@@ -105,6 +107,7 @@ class Item extends Model
'user_id',
'tag_id',
'appid',
'role',
];

View File

@@ -88,6 +88,11 @@ class AppServiceProvider extends ServiceProvider
$view->with('trianglify_seed', $trianglify_seed);
$view->with('allusers', $allusers);
$view->with('current_user', $current_user);
if (config('app.auth_roles_enable')){
$view->with('enable_auth_admin_controls', in_array(config('app.auth_roles_admin'),explode(config('app.auth_roles_delimiter'), $_SERVER[config('app.auth_roles_http_header')])));
} else {
$view->with('enable_auth_admin_controls', true);
}
});
$this->app['view']->addNamespace('SupportedApps', app_path('SupportedApps'));

View File

@@ -192,4 +192,10 @@ return [
'Yaml' => Symfony\Component\Yaml\Yaml::class,
])->toArray(),
'auth_roles_enable' => (bool) env('AUTH_ROLES_ENABLE', false),
'auth_roles_header' => env('AUTH_ROLES_HEADER', 'remote-groups'),
'auth_roles_http_header' => env('AUTH_ROLES_HTTP_HEADER', 'HTTP_REMOTE_GROUPS'),
'auth_roles_admin' => env('AUTH_ROLES_ADMIN', 'admin'),
'auth_roles_delimiter' => env('AUTH_ROLES_DELIMITER', ','),
];

View File

@@ -0,0 +1,32 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddRoleToItem extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('items', function (Blueprint $table) {
$table->text('role')->nullable();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('items', function (Blueprint $table) {
//
});
}
}

26
docker/docker-compose.yml Normal file
View File

@@ -0,0 +1,26 @@
version: "3"
services:
nginx:
build:
context: .
dockerfile: nginx/Dockerfile
ports:
- "8080:80"
networks:
- internal
volumes:
- ../:/var/www/html
php:
build:
context: .
dockerfile: php/Dockerfile
networks:
- internal
environment:
XDEBUG_MODE: debug
XDEBUG_CONFIG: client_host=host.docker.internal client_port=9003
volumes:
- ../:/var/www/html
networks:
internal:
driver: bridge

2
docker/nginx/Dockerfile Normal file
View File

@@ -0,0 +1,2 @@
FROM nginx:alpine
COPY ./default.conf /etc/nginx/conf.d

19
docker/nginx/default.conf Normal file
View File

@@ -0,0 +1,19 @@
server {
listen 0.0.0.0:80;
root /var/www/html;
location / {
index index.php index.html;
}
location ~ \.php$ {
include fastcgi_params;
fastcgi_pass php:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
}
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
}

4
docker/php/Dockerfile Normal file
View File

@@ -0,0 +1,4 @@
FROM php:8.4-fpm
RUN pecl install xdebug \
&& docker-php-ext-enable xdebug

View File

@@ -105,4 +105,7 @@ return array (
'alert.success.user_restored' => 'Nutzer erfolgreich wiederhergestellt',
'dashboard.reorder' => 'Elemente neu anordnen und anheften',
'dashboard.settings' => 'Einstellungen',
'role' => 'Authentifizierungsrolle',
'unauthorized_for_form' => 'Sie haben keinen Zugriff auf diese Seite.',
'disabled_feature' => 'Diese Funktion ist deaktiviert.',
);

View File

@@ -114,4 +114,7 @@ return array (
'alert.success.user_restored' => 'User restored successfully',
'dashboard.reorder' => 'Reorder and pin items',
'dashboard.settings' => 'Settings',
'role' => 'Authentication role',
'unauthorized_for_form' => 'You are not authorized to view this form.',
'disabled_feature' => 'This feature is disabled.',
);

View File

@@ -1,6 +1,8 @@
@extends('layouts.app')
@section('content')
@if(!$app['config']->get('app.auth_roles_enable', false))
<?php
$user = \App\User::currentUser();
?>
@@ -21,5 +23,14 @@ $user = \App\User::currentUser();
</div>
</form>
@else
<section class="module-container">
<header>
<div class="section-title">
{{ __('app.disabled_feature') }}
</div>
</header>
</section>
@endif
@endsection

View File

@@ -1,4 +1,5 @@
<section class="module-container">
<section class="module-container">
@if($enable_auth_admin_controls)
<header>
<div class="section-title">{{ __('app.apps.preview') }}</div>
<div class="module-actions">
@@ -76,6 +77,13 @@
{!! Form::select('tags[]', $tags, $current_tags, ['class' => 'tags', 'multiple']) !!}
</div>
@if($app['config']->get('app.auth_roles_enable', false))
<div class="input">
<label>{{ __('app.role') }}</label>
{!! Form::text('role', $item->role ?? null, array('placeholder' => __('app.role'), 'id' => 'role', 'class' => 'form-control')) !!}
</div>
@endif
<div class="input">
<div class="icon-container">
<div id="appimage">
@@ -137,6 +145,13 @@
<a href="{{ route('items.index', []) }}" class="button"><i class="fa fa-ban"></i><span>{{ __('app.buttons.cancel') }}</span></a>
</div>
</footer>
@else
<header>
<div class="section-title">
{{ __('app.unauthorized_for_form') }}
</div>
</header>
@endif
</section>

View File

@@ -3,6 +3,7 @@
@section('content')
<section class="module-container">
@if($enable_auth_admin_controls)
<header>
<div class="section-title">{{ __('app.import') }}</div>
<div class="module-actions">
@@ -31,6 +32,13 @@
<a href="{{ route('settings.index', []) }}" class="button"><i class="fa fa-ban"></i><span>{{ __('app.buttons.cancel') }}</span></a>
</div>
</footer>
@else
<header>
<div class="section-title">
{{ __('app.unauthorized_for_form') }}
</div>
</header>
@endif
</section>

View File

@@ -2,6 +2,7 @@
@section('content')
<section class="module-container">
@if($enable_auth_admin_controls)
<header>
<div class="section-title">
{{ __('app.apps.app_list') }}
@@ -53,6 +54,13 @@
</tbody>
</table>
@else
<header>
<div class="section-title">
{{ __('app.unauthorized_for_form') }}
</div>
</header>
@endif
</section>

View File

@@ -82,7 +82,7 @@
</div>
</div>
@endif
@if($allusers->count() > 1)
@if(!($allusers->count() <= 1 || config('app.auth_roles_enable')))
<div id="switchuser">
@if($current_user->avatar)
<img class="user-img" src="{{ asset('/storage/'.$current_user->avatar) }}" />
@@ -94,22 +94,22 @@
</div>
@endif
@yield('content')
@if($enable_auth_admin_controls)
<div id="config-buttons">
@if(Route::is('dash') || Route::is('tags.show'))
<a id="config-button" class="config" href=""><i class="fas fa-exchange"></i><div class="tooltip left">{{ __('app.dashboard.reorder') }}</div></a>
@endif
<a id="dash" class="config" href="{{ route('dash', []) }}"><i class="fas fa-th"></i><div class="tooltip left">{{ __('app.dashboard') }}</div></a>
@if($current_user->id === 1)
@if($current_user->id === 1 && !config('app.auth_roles_enable'))
<a id="users" class="config" href="{{ route('users.index', []) }}"><i class="fas fa-user"></i><div class="tooltip left">{{ __('app.user.user_list') }}</div></a>
@endif
<a id="items" class="config" href="{{ route('items.index', []) }}"><i class="fas fa-list"></i><div class="tooltip left">{{ __('app.apps.app_list') }}</div></a>
<a id="folder" class="config" href="{{ route('tags.index', []) }}"><i class="fas fa-tag"></i><div class="tooltip left">{{ __('app.apps.tag_list') }}</div></a>
<a id="settings" class="config" href="{{ route('settings.index', []) }}"><i class="fas fa-cogs"></i><div class="tooltip left">{{ __('app.dashboard.settings') }}</div></a>
</div>
@endif
</main>
</div>

View File

@@ -1,4 +1,5 @@
<section class="module-container">
@if($enable_auth_admin_controls)
<header>
<div class="section-title">{{ __($setting->label) }}</div>
<div class="module-actions">
@@ -26,5 +27,12 @@
<a href="{{ route('settings.index', []) }}" class="button"><i class="fa fa-ban"></i><span>{{ __('app.buttons.cancel') }}</span></a>
</div>
</footer>
@else
<header>
<div class="section-title">
{{ __('app.unauthorized_for_form') }}
</div>
</header>
@endif
</section>
</section>

View File

@@ -2,6 +2,7 @@
@section('content')
@if($enable_auth_admin_controls)
@foreach ($groups as $index => $group)
<section class="module-container">
<header>
@@ -57,5 +58,14 @@
</table>
</section>
@endforeach
@else
<section class="module-container">
<header>
<div class="section-title">
{{ __('app.unauthorized_for_form') }}
</div>
</header>
</section>
@endif
@endsection

View File

@@ -1,4 +1,5 @@
<section class="module-container">
<section class="module-container">
@if($enable_auth_admin_controls)
<header>
<div class="section-title">{{ __('app.apps.add_tag') }}</div>
<div class="module-actions">
@@ -30,6 +31,13 @@
{!! Form::text('colour', null, array('placeholder' => __('app.apps.hex'),'class' => 'form-control color-picker')) !!}
<hr />
</div>
@if($app['config']->get('app.auth_roles_enable', false))
<div class="input">
<label>{{ __('app.role') }}</label>
{!! Form::text('role', $item->role ?? null, array('placeholder' => __('app.role'), 'id' => 'role', 'class' => 'form-control')) !!}
<hr />
</div>
@endif
<div class="input">
<label>{{ __('app.apps.icon') }}</label>
<div class="icon-container">
@@ -51,6 +59,19 @@
</div>
</div>
</div>
<div class="input">
<label>{{ __('app.apps.pinned') }}</label>
{!! Form::hidden('pinned', '0') !!}
<label class="switch">
<?php
$checked = false;
if(isset($item->pinned) && (bool)$item->pinned === true) $checked = true;
$set_checked = ($checked) ? ' checked="checked"' : '';
?>
<input type="checkbox" name="pinned" value="1"<?php echo $set_checked;?> />
<span class="slider round"></span>
</label>
</div>
<div id="sapconfig"></div>
@@ -62,7 +83,11 @@
<a href="{{ route('tags.index', []) }}" class="button"><i class="fa fa-ban"></i><span>{{ __('app.buttons.cancel') }}</span></a>
</div>
</footer>
@else
<header>
<div class="section-title">
{{ __('app.unauthorized_for_form') }}
</div>
</header>
@endif
</section>

View File

@@ -2,6 +2,7 @@
@section('content')
<section class="module-container">
@if($enable_auth_admin_controls)
<header>
<div class="section-title">
{{ __('app.apps.tag_list') }}
@@ -50,7 +51,12 @@
</tbody>
</table>
@else
<header>
<div class="section-title">
{{ __('app.unauthorized_for_form') }}
</div>
</header>
@endif
</section>
@endsection

View File

@@ -1,4 +1,5 @@
<section class="module-container">
@if($enable_auth_admin_controls)
<header>
<div class="section-title">{{ __('app.user.add_user') }}</div>
<div class="module-actions">
@@ -91,7 +92,11 @@
<a href="{{ route('users.index', []) }}" class="button"><i class="fa fa-ban"></i><span>{{ __('app.buttons.cancel') }}</span></a>
</div>
</footer>
@else
<header>
<div class="section-title">
{{ __('app.unauthorized_for_form') }}
</div>
</header>
@endif
</section>

View File

@@ -2,6 +2,7 @@
@section('content')
<section class="module-container">
@if($enable_auth_admin_controls)
<header>
<div class="section-title">
{{ __('app.user.user_list') }}
@@ -60,7 +61,12 @@
</tbody>
</table>
@else
<header>
<div class="section-title">
{{ __('app.unauthorized_for_form') }}
</div>
</header>
@endif
</section>
@endsection

View File

@@ -1,7 +1,7 @@
@extends('layouts.users')
@section('content')
@if(!$app['config']->get('app.auth_roles_enable', false))
<div class="userlist">
@foreach($users as $user)
<a class="user" href="{{ route('user.set', [$user->id]) }}">
@@ -14,5 +14,14 @@
</a>
@endforeach
</div>
@else
<section class="module-container">
<header>
<div class="section-title">
{{ __('app.disabled_feature') }}
</div>
</header>
</section>
@endif
@endsection

5
xdebug.ini Normal file
View File

@@ -0,0 +1,5 @@
zend_extension=xdebug.so
xdebug.mode=debug
xdebug.start_with_request=yes
xdebug.client_host=host.docker.internal
xdebug.client_port=9003