Added XenForo route system and custom menu render.
This commit is contained in:
37
app/Livewire/EntryFilesModal.php
Normal file
37
app/Livewire/EntryFilesModal.php
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Livewire;
|
||||||
|
|
||||||
|
use App\Models\Entry;
|
||||||
|
use Livewire\Component;
|
||||||
|
|
||||||
|
class EntryFilesModal extends Component
|
||||||
|
{
|
||||||
|
|
||||||
|
public bool $open = false;
|
||||||
|
public ?int $entryId = null;
|
||||||
|
|
||||||
|
protected $listeners = [
|
||||||
|
'entryOpenFilesModal' => 'openModal'
|
||||||
|
];
|
||||||
|
|
||||||
|
public function openModal( int $entryId ): void
|
||||||
|
{
|
||||||
|
$this->entryId = $entryId;
|
||||||
|
$this->open = true;
|
||||||
|
|
||||||
|
$this->dispatch('modal:opened');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function close(): void
|
||||||
|
{
|
||||||
|
$this->open = false;
|
||||||
|
$this->entryId = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function render()
|
||||||
|
{
|
||||||
|
$files = $this->entryId ? Entry::find($this->entryId)?->files : collect();
|
||||||
|
return view('livewire.entry-files-modal', compact('files'));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,6 +20,7 @@ class AppServiceProvider extends ServiceProvider
|
|||||||
*/
|
*/
|
||||||
public function boot(): void
|
public function boot(): void
|
||||||
{
|
{
|
||||||
|
|
||||||
\Auth::extend('xenforo', function ($app, $name, array $config) {
|
\Auth::extend('xenforo', function ($app, $name, array $config) {
|
||||||
return new XenForoGuard($app['request']);
|
return new XenForoGuard($app['request']);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -8,7 +8,16 @@ class XenforoService {
|
|||||||
|
|
||||||
private const array PERMISSIONS_KEPT = [ 'general', 'romhackplaza' ];
|
private const array PERMISSIONS_KEPT = [ 'general', 'romhackplaza' ];
|
||||||
private const int TTL_PERMISSIONS = 300;
|
private const int TTL_PERMISSIONS = 300;
|
||||||
|
private const int TTL_ROUTES = 86400;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get permissions for a specific user ID.
|
||||||
|
*
|
||||||
|
* @param int $userId
|
||||||
|
* @param int $permissionCombinationId
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
public function getPermissions(int $userId, int $permissionCombinationId): array {
|
public function getPermissions(int $userId, int $permissionCombinationId): array {
|
||||||
|
|
||||||
return Cache::remember("xf_permissions_{$userId}", self::TTL_PERMISSIONS, function() use($permissionCombinationId) {
|
return Cache::remember("xf_permissions_{$userId}", self::TTL_PERMISSIONS, function() use($permissionCombinationId) {
|
||||||
@@ -29,8 +38,117 @@ class XenforoService {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear user data.
|
||||||
|
*
|
||||||
|
* @param int $userId
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
public function clearUserData(int $userId): void
|
public function clearUserData(int $userId): void
|
||||||
{
|
{
|
||||||
Cache::forget("xf_permissions_{$userId}");
|
Cache::forget("xf_permissions_{$userId}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param string $routeName <prefix>.<secname>
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getRoute( string $routeName, array $arguments ): string {
|
||||||
|
|
||||||
|
$routes = Cache::remember("xf_routes", self::TTL_ROUTES, function(){
|
||||||
|
return \DB::connection('xenforo')
|
||||||
|
->table('route')
|
||||||
|
->where('route_type', 'public' )
|
||||||
|
->get(['route_prefix', 'sub_name', 'format'])
|
||||||
|
->map(fn($r) => (array) $r )
|
||||||
|
->toArray();
|
||||||
|
});
|
||||||
|
|
||||||
|
$baseUrl = config('app.forum_url');
|
||||||
|
|
||||||
|
try {
|
||||||
|
[$prefix, $subName] = explode('.', $routeName, 2);
|
||||||
|
|
||||||
|
$route = collect($routes)->first(function ($r) use ($prefix, $subName) {
|
||||||
|
return $r['route_prefix'] === $prefix && $r['sub_name'] === $subName;
|
||||||
|
});
|
||||||
|
|
||||||
|
if( !$route )
|
||||||
|
return $baseUrl . '/' . $prefix;
|
||||||
|
|
||||||
|
$path = $this->buildRoutePath((array)$route, $arguments);
|
||||||
|
return rtrim($baseUrl, '/') . '/' . $path;
|
||||||
|
|
||||||
|
} catch (\Throwable $th) {
|
||||||
|
$prefix = $routeName;
|
||||||
|
|
||||||
|
$route = collect($routes)->first(function ($r) use ($prefix) {
|
||||||
|
return $r['route_prefix'] === $prefix;
|
||||||
|
});
|
||||||
|
|
||||||
|
if( !$route )
|
||||||
|
return $baseUrl . '/' . $prefix;
|
||||||
|
|
||||||
|
$path = $this->buildRoutePath((array)$route, $arguments);
|
||||||
|
return rtrim($baseUrl, '/') . '/' . $path;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private function buildRoutePath(array $route, array $arguments): string {
|
||||||
|
|
||||||
|
$prefix = $route['route_prefix'];
|
||||||
|
$format = $route['format'];
|
||||||
|
$subName = $route['sub_name'];
|
||||||
|
|
||||||
|
if (!$format) {
|
||||||
|
return $subName
|
||||||
|
? $prefix . '-/' . $subName
|
||||||
|
: $prefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (str_starts_with($format, '-/')) {
|
||||||
|
return $prefix . $format;
|
||||||
|
}
|
||||||
|
|
||||||
|
$built = preg_replace_callback(
|
||||||
|
'/:\+?(\w+)(?:_\w+)?(?:<([^>]+)>)?/',
|
||||||
|
function(array $m) use ($arguments): string {
|
||||||
|
$type = $m[1];
|
||||||
|
$keys = isset($m[2])
|
||||||
|
? explode(',', $m[2])
|
||||||
|
: [];
|
||||||
|
|
||||||
|
return match(true) {
|
||||||
|
|
||||||
|
$type === 'page' => isset($params['page']) && $params['page'] > 1
|
||||||
|
? 'page-' . $params['page']
|
||||||
|
: '',
|
||||||
|
|
||||||
|
$type === 'str_int' && count($keys) >= 2 => implode('.', array_filter([
|
||||||
|
$params[$keys[0]] ?? null,
|
||||||
|
$params[$keys[1]] ?? null,
|
||||||
|
])),
|
||||||
|
|
||||||
|
$type === 'int' && count($keys) >= 1 => (string) ($params[$keys[0]] ?? ''),
|
||||||
|
|
||||||
|
in_array($type, ['str', 'any']) && count($keys) >= 1
|
||||||
|
=> (string) ($params[$keys[0]] ?? ''),
|
||||||
|
|
||||||
|
default => isset($params[$type]) ? (string) $params[$type] : '',
|
||||||
|
};
|
||||||
|
},
|
||||||
|
$format
|
||||||
|
);
|
||||||
|
|
||||||
|
$built = preg_replace('/\/+/', '/', $prefix . '/' . $built);
|
||||||
|
$built = rtrim($built, '/');
|
||||||
|
|
||||||
|
return $built;
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
8
app/xenforo.php
Normal file
8
app/xenforo.php
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
if( !function_exists( 'xfRoute' ) ){
|
||||||
|
|
||||||
|
function xfRoute( string $routeName, array $arguments = [] ): string {
|
||||||
|
return app(\App\Services\XenforoService::class)->getRoute( $routeName, $arguments );
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -28,7 +28,8 @@
|
|||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"files": [
|
"files": [
|
||||||
"app/helpers.php"
|
"app/helpers.php",
|
||||||
|
"app/xenforo.php"
|
||||||
],
|
],
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
"App\\": "app/",
|
"App\\": "app/",
|
||||||
|
|||||||
94
config/menu.php
Normal file
94
config/menu.php
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Categories : <id> => ['name', 'items']
|
||||||
|
* Items: ['name','icon','route' or 'xf_route']
|
||||||
|
*/
|
||||||
|
return [
|
||||||
|
'website' => [
|
||||||
|
'name' => 'Website',
|
||||||
|
'items' => [
|
||||||
|
[
|
||||||
|
'name' => 'Home',
|
||||||
|
'icon' => 'home',
|
||||||
|
'route' => 'home',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'Database',
|
||||||
|
'icon' => 'database',
|
||||||
|
'route' => 'home'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => "Submissions Queue",
|
||||||
|
'icon' => 'gavel',
|
||||||
|
'route' => 'home'
|
||||||
|
],
|
||||||
|
]
|
||||||
|
],
|
||||||
|
'community' => [
|
||||||
|
'name' => 'Community',
|
||||||
|
'items' => [
|
||||||
|
[
|
||||||
|
'name' => 'Forum',
|
||||||
|
'icon' => 'message-circle',
|
||||||
|
'xf_route' => ''
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'Discord',
|
||||||
|
'icon' => 'messages-square',
|
||||||
|
'route' => 'home'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'Members',
|
||||||
|
'icon' => 'users',
|
||||||
|
'xf_route' => 'members'
|
||||||
|
],
|
||||||
|
|
||||||
|
]
|
||||||
|
],
|
||||||
|
'tools' => [
|
||||||
|
'name' => 'Tools',
|
||||||
|
'items' => [
|
||||||
|
[
|
||||||
|
'name' => 'ROM Patcher',
|
||||||
|
'icon' => 'stamp',
|
||||||
|
'route' => 'home'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'ROM Hasher',
|
||||||
|
'icon' => 'hash',
|
||||||
|
'route' => 'home'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'ROM Checker',
|
||||||
|
'icon' => 'check',
|
||||||
|
'route' => 'home'
|
||||||
|
]
|
||||||
|
]
|
||||||
|
],
|
||||||
|
'pages' => [
|
||||||
|
'name' => 'Pages',
|
||||||
|
'items' => [
|
||||||
|
[
|
||||||
|
'name' => 'Learn Romhacking',
|
||||||
|
'icon' => 'graduation-cap',
|
||||||
|
'route' => 'home'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'About',
|
||||||
|
'icon' => 'info',
|
||||||
|
'route' => 'home'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'Contact Us',
|
||||||
|
'icon' => 'at-sign',
|
||||||
|
'route' => 'home'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'Legal pages',
|
||||||
|
'icon' => 'scale',
|
||||||
|
'route' => 'home'
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
];
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
.modal-overlay {
|
.modal-overlay {
|
||||||
display: none;
|
display: flex;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0; left: 0; right: 0; bottom: 0;
|
top: 0; left: 0; right: 0; bottom: 0;
|
||||||
background-color: rgba(0, 0, 0, 0.7);
|
background-color: rgba(0, 0, 0, 0.7);
|
||||||
|
|||||||
@@ -19,5 +19,3 @@ window.EasyMDE = EasyMDE;
|
|||||||
|
|
||||||
// Hashes.
|
// Hashes.
|
||||||
window.calculateHashes = calculateHashes;
|
window.calculateHashes = calculateHashes;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -11,15 +11,17 @@
|
|||||||
|
|
||||||
<div class="menu-navigation">
|
<div class="menu-navigation">
|
||||||
|
|
||||||
|
@foreach( config('menu') as $menu )
|
||||||
<div class="menu-group">
|
<div class="menu-group">
|
||||||
<div class="menu-group-title">Website</div>
|
<div class="menu-group-title">{{ $menu['name'] }}</div>
|
||||||
<a href="{{ route('home') }}"
|
@foreach( $menu['items'] as $item )
|
||||||
@class(['menu-item', 'active' => request()->routeIs('home')]) >
|
<a href="{{ isset($item['xf_route']) ? xfRoute($item['xf_route']) : route($item['route']) }}"
|
||||||
<i data-lucide="home"></i><span>Home</span>
|
@class(['menu-item', 'active' => request()->routeIs( $item['route'] ?? '' )]) >
|
||||||
|
<i data-lucide="{{ $item['icon'] }}"></i><span>{{ $item['name'] }}</span>
|
||||||
</a>
|
</a>
|
||||||
|
@endforeach
|
||||||
</div>
|
</div>
|
||||||
|
@endforeach
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -56,7 +56,7 @@
|
|||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
<div class="hack-actions">
|
<div class="hack-actions">
|
||||||
<button class="btn primary">
|
<button class="btn primary" onclick="Livewire.dispatch('entryOpenFilesModal', { entryId: {{ $entry->id }} })">
|
||||||
<i data-lucide="download"></i> Download
|
<i data-lucide="download"></i> Download
|
||||||
</button>
|
</button>
|
||||||
<button class="btn">
|
<button class="btn">
|
||||||
@@ -94,4 +94,5 @@
|
|||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
</article>
|
</article>
|
||||||
|
@livewire('entry-files-modal')
|
||||||
@endsection
|
@endsection
|
||||||
|
|||||||
@@ -7,4 +7,6 @@
|
|||||||
Ceci est un block !
|
Ceci est un block !
|
||||||
</div>
|
</div>
|
||||||
<x-error-block error-type="page-not-allowed" />
|
<x-error-block error-type="page-not-allowed" />
|
||||||
|
|
||||||
|
{{ xfRoute( 'profile-posts.comments', ['profile_post_comment_id' => 1] ) }}
|
||||||
@endsection
|
@endsection
|
||||||
|
|||||||
33
resources/views/livewire/entry-files-modal.blade.php
Normal file
33
resources/views/livewire/entry-files-modal.blade.php
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
<div class="modal-overlay"
|
||||||
|
x-data
|
||||||
|
x-cloak
|
||||||
|
x-show="$wire.open"
|
||||||
|
x-transition.opacity
|
||||||
|
@click.self="$wire.close()"
|
||||||
|
@keydown.escape.window="$wire.close()"
|
||||||
|
@modal:opened.window="refreshIcons($el)"
|
||||||
|
>
|
||||||
|
<div class="modal-window" x-transition x-show="$wire.open">
|
||||||
|
<div class="modal-header">
|
||||||
|
<span class="modal-title">Download files</span>
|
||||||
|
<button type="button" class="modal-close" @click="$wire.close()">
|
||||||
|
<i data-lucide="x" size="20"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="file-list">
|
||||||
|
@forelse( $files as $file )
|
||||||
|
<div class="file-item">
|
||||||
|
<div class="file-info">
|
||||||
|
<span class="file-name">{{ $file->filename }}</span>
|
||||||
|
<span class="file-meta">{{ $file->filesize }} - 0 downloads</span>
|
||||||
|
</div>
|
||||||
|
<a href="{{ route('fs.download', ['entry_id' => $entryId, 'file' => $file->file_uuid] ) }}" class="btn primary"><i data-lucide="download"></i> Download</a>
|
||||||
|
</div>
|
||||||
|
@empty
|
||||||
|
No files found
|
||||||
|
@endforelse
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
1
storage/app/public/.gitignore
vendored
1
storage/app/public/.gitignore
vendored
@@ -1,2 +1,3 @@
|
|||||||
*
|
*
|
||||||
!.gitignore
|
!.gitignore
|
||||||
|
z
|
||||||
|
|||||||
Reference in New Issue
Block a user