Compare commits

..

3 Commits

Author SHA1 Message Date
1ab60b99f4 dockerize project 2024-12-04 18:40:08 +01:00
eb67e4a5eb wip ig 2024-12-04 18:40:07 +01:00
3d739af292 add user and authenticator 2024-12-04 18:39:46 +01:00
37 changed files with 2919 additions and 610 deletions

View File

@ -7,12 +7,13 @@ xdebug_enabled: false
additional_hostnames: [] additional_hostnames: []
additional_fqdns: [] additional_fqdns: []
database: database:
type: mariadb type: postgres
version: "10.11" version: "17"
use_dns_when_possible: true use_dns_when_possible: true
composer_version: "2" composer_version: "2"
web_environment: [] web_environment: []
corepack_enable: false corepack_enable: false
host_db_port: "5432"
# Key features of DDEV's config.yaml: # Key features of DDEV's config.yaml:

18
.docker/Dockerfile Normal file
View File

@ -0,0 +1,18 @@
FROM php:8.2-apache
RUN apt-get update \
&& apt-get install -qq -y --no-install-recommends \
cron \
nano \
locales coreutils apt-utils git libicu-dev g++ libpng-dev libxml2-dev libzip-dev libonig-dev libxslt-dev;
RUN echo "en_US.UTF-8 UTF-8" > /etc/locale.gen && locale-gen
RUN curl -sSk https://getcomposer.org/installer | php -- --disable-tls && \
mv composer.phar /usr/local/bin/composer
RUN docker-php-ext-configure intl
RUN docker-php-ext-install pdo pdo_mysql mysqli gd opcache intl zip calendar dom mbstring zip gd xsl && a2enmod rewrite
RUN pecl install apcu && docker-php-ext-enable apcu
WORKDIR /var/www

10
.docker/compose.yaml Normal file
View File

@ -0,0 +1,10 @@
services:
www:
build: .
container_name: file-explorer
ports:
- "8741:80"
volumes:
- ./hosts:/etc/apache2/sites-enabled
- ../:/var/www/project
restart: always

18
.docker/hosts/server.conf Normal file
View File

@ -0,0 +1,18 @@
<VirtualHost *:80>
ServerName localhost
DocumentRoot /var/www/project/public
DirectoryIndex /index.php
<Directory /var/www/project/public>
AllowOverride None
Order Allow,Deny
Allow from All
</Directory>
# <Directory /var/www/project/public/bundles>
# FallbackResource disabled
# </Directory>
ErrorLog /var/log/apache2/project_error.log
CustomLog /var/log/apache2/project_access.log combined
</VirtualHost>

10
.env
View File

@ -18,3 +18,13 @@
APP_ENV=dev APP_ENV=dev
APP_SECRET=bfc9c288ee3dcce80dec8622c2870f27 APP_SECRET=bfc9c288ee3dcce80dec8622c2870f27
###< symfony/framework-bundle ### ###< symfony/framework-bundle ###
###> doctrine/doctrine-bundle ###
# Format described at https://www.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#connecting-using-a-url
# IMPORTANT: You MUST configure your server version, either here or in config/packages/doctrine.yaml
#
# DATABASE_URL="sqlite:///%kernel.project_dir%/var/data.db"
# DATABASE_URL="mysql://app:!ChangeMe!@127.0.0.1:3306/app?serverVersion=8.0.32&charset=utf8mb4"
# DATABASE_URL="mysql://app:!ChangeMe!@127.0.0.1:3306/app?serverVersion=10.11.2-MariaDB&charset=utf8mb4"
DATABASE_URL="postgresql://db:db@db:5432/db?serverVersion=16&charset=utf8"
###< doctrine/doctrine-bundle ###

6
.gitignore vendored
View File

@ -1,5 +1,4 @@
/.idea/ /.idea/
/data/
###> symfony/framework-bundle ### ###> symfony/framework-bundle ###
/.env.local /.env.local
/.env.local.php /.env.local.php
@ -9,8 +8,3 @@
/var/ /var/
/vendor/ /vendor/
###< symfony/framework-bundle ### ###< symfony/framework-bundle ###
###> symfony/asset-mapper ###
/public/assets/
/assets/vendor/
###< symfony/asset-mapper ###

View File

@ -1,9 +0,0 @@
/*
* Welcome to your app's main JavaScript file!
*
* This file will be included onto the page via the importmap() Twig function,
* which should already be in your base.html.twig.
*/
import './styles/app.css';
console.log('This log comes from assets/app.js - welcome to AssetMapper! 🎉');

View File

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24"><path fill="currentColor" d="M13 9V3.5L18.5 9M6 2c-1.11 0-2 .89-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8l-6-6z"/></svg>

Before

Width:  |  Height:  |  Size: 203 B

View File

@ -1 +0,0 @@
<svg viewBox="0 0 24 24"><path fill="currentColor" d="M4 20q-.825 0-1.412-.587T2 18V6q0-.825.588-1.412T4 4h6l2 2h8q.825 0 1.413.588T22 8v10q0 .825-.587 1.413T20 20z"/></svg>

Before

Width:  |  Height:  |  Size: 173 B

View File

@ -1,3 +0,0 @@
body {
background-color: transparent;
}

View File

@ -7,16 +7,18 @@
"php": ">=8.2", "php": ">=8.2",
"ext-ctype": "*", "ext-ctype": "*",
"ext-iconv": "*", "ext-iconv": "*",
"doctrine/dbal": "^3",
"doctrine/doctrine-bundle": "^2.13",
"doctrine/doctrine-migrations-bundle": "^3.3",
"doctrine/orm": "^3.3",
"symfony/apache-pack": "^1.0", "symfony/apache-pack": "^1.0",
"symfony/asset-mapper": "^7.1",
"symfony/console": "7.1.*", "symfony/console": "7.1.*",
"symfony/dotenv": "7.1.*", "symfony/dotenv": "7.1.*",
"symfony/finder": "7.1.*",
"symfony/flex": "^2", "symfony/flex": "^2",
"symfony/framework-bundle": "7.1.*", "symfony/framework-bundle": "7.1.*",
"symfony/runtime": "7.1.*", "symfony/runtime": "7.1.*",
"symfony/security-bundle": "7.1.*",
"symfony/twig-bundle": "7.1.*", "symfony/twig-bundle": "7.1.*",
"symfony/ux-icons": "^2.22",
"symfony/yaml": "7.1.*", "symfony/yaml": "7.1.*",
"twig/extra-bundle": "^2.12|^3.0", "twig/extra-bundle": "^2.12|^3.0",
"twig/twig": "^2.12|^3.0" "twig/twig": "^2.12|^3.0"
@ -52,8 +54,7 @@
"scripts": { "scripts": {
"auto-scripts": { "auto-scripts": {
"cache:clear": "symfony-cmd", "cache:clear": "symfony-cmd",
"assets:install %PUBLIC_DIR%": "symfony-cmd", "assets:install %PUBLIC_DIR%": "symfony-cmd"
"importmap:install": "symfony-cmd"
}, },
"post-install-cmd": [ "post-install-cmd": [
"@auto-scripts" "@auto-scripts"
@ -70,5 +71,10 @@
"allow-contrib": false, "allow-contrib": false,
"require": "7.1.*" "require": "7.1.*"
} }
},
"require-dev": {
"symfony/maker-bundle": "^1.61",
"symfony/stopwatch": "7.1.*",
"symfony/web-profiler-bundle": "7.1.*"
} }
} }

2841
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -2,7 +2,11 @@
return [ return [
Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true], Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true],
Symfony\Bundle\SecurityBundle\SecurityBundle::class => ['all' => true],
Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true],
Doctrine\Bundle\DoctrineBundle\DoctrineBundle::class => ['all' => true],
Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle::class => ['all' => true],
Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true], Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true],
Twig\Extra\TwigExtraBundle\TwigExtraBundle::class => ['all' => true], Twig\Extra\TwigExtraBundle\TwigExtraBundle::class => ['all' => true],
Symfony\UX\Icons\UXIconsBundle::class => ['all' => true], Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true],
]; ];

View File

@ -1,11 +0,0 @@
framework:
asset_mapper:
# The paths to make available to the asset mapper.
paths:
- assets/
missing_import_mode: strict
when@prod:
framework:
asset_mapper:
missing_import_mode: warn

View File

@ -0,0 +1,54 @@
doctrine:
dbal:
url: '%env(resolve:DATABASE_URL)%'
# IMPORTANT: You MUST configure your server version,
# either here or in the DATABASE_URL env var (see .env file)
#server_version: '16'
profiling_collect_backtrace: '%kernel.debug%'
use_savepoints: true
orm:
auto_generate_proxy_classes: true
enable_lazy_ghost_objects: true
report_fields_where_declared: true
validate_xml_mapping: true
naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware
identity_generation_preferences:
Doctrine\DBAL\Platforms\PostgreSQLPlatform: identity
auto_mapping: true
mappings:
App:
type: attribute
is_bundle: false
dir: '%kernel.project_dir%/src/Entity'
prefix: 'App\Entity'
alias: App
controller_resolver:
auto_mapping: false
when@test:
doctrine:
dbal:
# "TEST_TOKEN" is typically set by ParaTest
dbname_suffix: '_test%env(default::TEST_TOKEN)%'
when@prod:
doctrine:
orm:
auto_generate_proxy_classes: false
proxy_dir: '%kernel.build_dir%/doctrine/orm/Proxies'
query_cache_driver:
type: pool
pool: doctrine.system_cache_pool
result_cache_driver:
type: pool
pool: doctrine.result_cache_pool
framework:
cache:
pools:
doctrine.result_cache_pool:
adapter: cache.app
doctrine.system_cache_pool:
adapter: cache.system

View File

@ -0,0 +1,6 @@
doctrine_migrations:
migrations_paths:
# namespace is arbitrary but should be different from App\Migrations
# as migrations classes should NOT be autoloaded
'DoctrineMigrations': '%kernel.project_dir%/migrations'
enable_profiler: false

View File

@ -0,0 +1,46 @@
security:
# https://symfony.com/doc/current/security.html#registering-the-user-hashing-passwords
password_hashers:
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
# https://symfony.com/doc/current/security.html#loading-the-user-the-user-provider
providers:
# used to reload user from session & other features (e.g. switch_user)
app_user_provider:
entity:
class: App\Entity\User
property: email
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
lazy: true
provider: app_user_provider
custom_authenticators:
- App\Security\Authenticator
# activate different ways to authenticate
# https://symfony.com/doc/current/security.html#the-firewall
# https://symfony.com/doc/current/security/impersonating_user.html
# switch_user: true
# Easy way to control access for large sections of your site
# Note: Only the *first* access control that matches will be used
access_control:
- { path: /, roles: ROLE_USER}
# - { path: ^/admin, roles: ROLE_ADMIN }
# - { path: ^/profile, roles: ROLE_USER }
when@test:
security:
password_hashers:
# By default, password hashers are resource intensive and take time. This is
# important to generate secure password hashes. In tests however, secure hashes
# are not important, waste resources and increase test times. The following
# reduces the work factor to the lowest possible values.
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface:
algorithm: auto
cost: 4 # Lowest possible value for bcrypt
time_cost: 3 # Lowest possible value for argon
memory_cost: 10 # Lowest possible value for argon

View File

@ -0,0 +1,17 @@
when@dev:
web_profiler:
toolbar: true
intercept_redirects: false
framework:
profiler:
only_exceptions: false
collect_serializer_data: true
when@test:
web_profiler:
toolbar: false
intercept_redirects: false
framework:
profiler: { collect: false }

View File

@ -0,0 +1,3 @@
_security_logout:
resource: security.route_loader.logout
type: service

View File

@ -0,0 +1,8 @@
when@dev:
web_profiler_wdt:
resource: '@WebProfilerBundle/Resources/config/routing/wdt.xml'
prefix: /_wdt
web_profiler_profiler:
resource: '@WebProfilerBundle/Resources/config/routing/profiler.xml'
prefix: /_profiler

View File

@ -1,19 +0,0 @@
<?php
/**
* Returns the importmap for this application.
*
* - "path" is a path inside the asset mapper system. Use the
* "debug:asset-map" command to see the full list of paths.
*
* - "entrypoint" (JavaScript only) set to true for any module that will
* be used as an "entrypoint" (and passed to the importmap() Twig function).
*
* The "importmap:require" command can be used to add new entries to this file.
*/
return [
'app' => [
'path' => './assets/app.js',
'entrypoint' => true,
],
];

0
migrations/.gitignore vendored Normal file
View File

BIN
public/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

View File

@ -2,7 +2,6 @@
namespace App\Controller; namespace App\Controller;
use App\Service\FileSystemService;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
@ -11,10 +10,8 @@ use Symfony\Component\Routing\Attribute\Route;
class HomeController extends AbstractController class HomeController extends AbstractController
{ {
#[Route(path: '/', name: 'app_home', methods: Request::METHOD_GET)] #[Route(path: '/', name: 'app_home', methods: Request::METHOD_GET)]
public function __invoke( public function home(): Response
FileSystemService $fileSystemService
): Response
{ {
return $this->render('home.html.twig', ['content' => $fileSystemService->getDirs()]); return $this->render('index.html.twig');
} }
} }

0
src/Entity/.gitignore vendored Normal file
View File

91
src/Entity/User.php Normal file
View File

@ -0,0 +1,91 @@
<?php
namespace App\Entity;
use App\Repository\UserRepository;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\User\UserInterface;
#[ORM\Entity(repositoryClass: UserRepository::class)]
#[ORM\Table(name: '`user`')]
#[ORM\UniqueConstraint(name: 'UNIQ_IDENTIFIER_EMAIL', fields: ['email'])]
class User implements UserInterface
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
private ?int $id = null;
#[ORM\Column(length: 180)]
private string $email = '';
#[ORM\Column(length: 255)]
private string $name = '';
#[ORM\Column(length: 255)]
private string $username = '';
public function getId(): ?int
{
return $this->id;
}
public function getEmail(): string
{
return $this->email;
}
public function setEmail(string $email): static
{
$this->email = $email;
return $this;
}
public function getUserIdentifier(): string
{
return $this->email;
}
public function getRoles(): array
{
return ['ROLE_USER'];
}
public function eraseCredentials(): void
{
}
public function getName(): string
{
return $this->name;
}
public function setName(?string $name): static
{
$this->name = $name;
return $this;
}
public function getUsername(): string
{
return $this->username;
}
public function setUsername(string $username): static
{
$this->username = $username;
return $this;
}
public static function createFromRequest(Request $request): static
{
return (new self())
->setEmail($request->headers->get('x-authentik-email'))
->setName($request->headers->get('x-authentik-name'))
->setUsername($request->headers->get('x-authentik-username'));
}
}

View File

@ -1,56 +0,0 @@
<?php
declare(strict_types=1);
namespace App\Objects;
use SplFileInfo;
class DirContent
{
private function __construct(
private readonly string $name,
private readonly int $size,
private readonly string $type,
)
{
}
public static function make(SplFileInfo $fileInfo): DirContent
{
return new self(
$fileInfo->getBasename(),
$fileInfo->getSize() ?? 0,
$fileInfo->getType() ?? 'N/A',
);
}
public function getName(): string
{
return $this->name;
}
public function getSize(bool $humanReadable = true): int|string
{
if (!$humanReadable) {
return $this->size;
}
return $this->getHumanReadableSize();
}
public function getType(): string
{
return $this->type;
}
private function getHumanReadableSize()
{
$bytes = $this->size;
$size = array('B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB');
$factor = floor((strlen((string) $bytes) - 1) / 3);
return sprintf("%.1f %s", $bytes / (1024 ** $factor), $size[$factor]);
}
}

0
src/Repository/.gitignore vendored Normal file
View File

View File

@ -0,0 +1,34 @@
<?php
namespace App\Repository;
use App\Entity\User;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @extends ServiceEntityRepository<User>
*/
class UserRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, User::class);
}
public function save(User $user): void
{
$this->getEntityManager()->persist($user);
$this->getEntityManager()->flush();
}
public function exists(string $email): bool
{
return $this->createQueryBuilder('u')
->select('COUNT(u.id)')
->where('u.email = :email')
->setParameter('email', $email)
->getQuery()
->getSingleScalarResult() === 1;
}
}

View File

@ -0,0 +1,68 @@
<?php
namespace App\Security;
use App\Entity\User;
use App\Repository\UserRepository;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Http\Authenticator\AbstractAuthenticator;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\RememberMeBadge;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport;
class Authenticator extends AbstractAuthenticator
{
public function __construct(private readonly UserRepository $userRepository)
{
}
public function supports(Request $request): ?bool
{
return $request->headers->has('x-authentik-username')
&& $request->headers->has('x-authentik-email')
&& $request->headers->has('x-authentik-name');
}
public function authenticate(Request $request): Passport
{
$email = $request->headers->get('x-authentik-email');
$this->checkGroup($request);
$this->createUserIfNotExists($email, $request);
return new SelfValidatingPassport(new UserBadge($email), [new RememberMeBadge()]);
}
public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
{
return null;
}
public function onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response
{
dd($exception);
return new JsonResponse([$exception], Response::HTTP_UNAUTHORIZED);
}
private function createUserIfNotExists(string $email, Request $request): void
{
if ($this->userRepository->exists($email)) {
$user = User::createFromRequest($request);
$this->userRepository->save($user);
}
}
private function checkGroup(Request $request): void
{
$groups = explode('|', $request->headers->get('x-authentik-groups'));
if (!in_array('file-explorer user', $groups)) {
throw new \LogicException('You are not allowed to access this resource');
}
}
}

View File

@ -1,33 +0,0 @@
<?php
namespace App\Service;
use App\Objects\DirContent;
use Symfony\Component\DependencyInjection\Attribute\Autowire;
use Symfony\Component\Finder\Finder;
class FileSystemService
{
public function __construct(
#[Autowire(env: 'DATA_DIR')]
private readonly string $dir
) {
}
/**
* @return DirContent[]
*/
public function getDirs(): array
{
$finder = new Finder();
$finder->in($this->dir);
$contents = [];
foreach ($finder->depth(0) as $content) {
$contents[] = DirContent::make($content);
}
return $contents;
}
}

View File

@ -1,4 +1,31 @@
{ {
"doctrine/doctrine-bundle": {
"version": "2.13",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "2.13",
"ref": "8d96c0b51591ffc26794d865ba3ee7d193438a83"
},
"files": [
"config/packages/doctrine.yaml",
"src/Entity/.gitignore",
"src/Repository/.gitignore"
]
},
"doctrine/doctrine-migrations-bundle": {
"version": "3.3",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "3.1",
"ref": "1d01ec03c6ecbd67c3375c5478c9a423ae5d6a33"
},
"files": [
"config/packages/doctrine_migrations.yaml",
"migrations/.gitignore"
]
},
"symfony/apache-pack": { "symfony/apache-pack": {
"version": "1.0", "version": "1.0",
"recipe": { "recipe": {
@ -11,21 +38,6 @@
"public/.htaccess" "public/.htaccess"
] ]
}, },
"symfony/asset-mapper": {
"version": "7.1",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "6.4",
"ref": "5ad1308aa756d58f999ffbe1540d1189f5d7d14a"
},
"files": [
"assets/app.js",
"assets/styles/app.css",
"config/packages/asset_mapper.yaml",
"importmap.php"
]
},
"symfony/console": { "symfony/console": {
"version": "7.1", "version": "7.1",
"recipe": { "recipe": {
@ -43,11 +55,12 @@
"recipe": { "recipe": {
"repo": "github.com/symfony/recipes", "repo": "github.com/symfony/recipes",
"branch": "main", "branch": "main",
"version": "1.0", "version": "2.4",
"ref": "146251ae39e06a95be0fe3d13c807bcf3938b172" "ref": "52e9754527a15e2b79d9a610f98185a1fe46622a"
}, },
"files": [ "files": [
".env" ".env",
".env.dev"
] ]
}, },
"symfony/framework-bundle": { "symfony/framework-bundle": {
@ -69,6 +82,15 @@
"src/Kernel.php" "src/Kernel.php"
] ]
}, },
"symfony/maker-bundle": {
"version": "1.61",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "1.0",
"ref": "fadbfe33303a76e25cb63401050439aa9b1a9c7f"
}
},
"symfony/routing": { "symfony/routing": {
"version": "7.1", "version": "7.1",
"recipe": { "recipe": {
@ -82,6 +104,19 @@
"config/routes.yaml" "config/routes.yaml"
] ]
}, },
"symfony/security-bundle": {
"version": "7.1",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "6.4",
"ref": "2ae08430db28c8eb4476605894296c82a642028f"
},
"files": [
"config/packages/security.yaml",
"config/routes/security.yaml"
]
},
"symfony/twig-bundle": { "symfony/twig-bundle": {
"version": "7.1", "version": "7.1",
"recipe": { "recipe": {
@ -95,19 +130,20 @@
"templates/base.html.twig" "templates/base.html.twig"
] ]
}, },
"symfony/ux-icons": { "symfony/web-profiler-bundle": {
"version": "2.22", "version": "7.1",
"recipe": { "recipe": {
"repo": "github.com/symfony/recipes", "repo": "github.com/symfony/recipes",
"branch": "main", "branch": "main",
"version": "2.17", "version": "6.1",
"ref": "803a3bbd5893f9584969ab8670290cdfb6a0a5b5" "ref": "e42b3f0177df239add25373083a564e5ead4e13a"
}, },
"files": [ "files": [
"assets/icons/symfony.svg" "config/packages/web_profiler.yaml",
"config/routes/web_profiler.yaml"
] ]
}, },
"twig/extra-bundle": { "twig/extra-bundle": {
"version": "v3.16.0" "version": "v3.13.0"
} }
} }

View File

@ -1,11 +0,0 @@
<tr>
<td>
{% if file.type == 'dir' %}
{{ ux_icon('folder:closed', {height: '32px', width: '32px'}) }}
{% else %}
{{ ux_icon('file:default', {height: '32px', width: '32px'}) }}
{% endif %}
</td>
<td>{{ file.name }}</td>
<td>{{ file.size }}</td>
</tr>

View File

@ -1,13 +0,0 @@
<table class="table table-striped table-bordered w-75 mt-5">
<thead>
<tr>
<td>Expand</td>
<th>Name</th>
<th>Size</th>
</thead>
<tbody>
{% for dirContent in content %}
{% include '_partials/_row.html.twig' with {file: dirContent} %}
{% endfor %}
</tbody>
</table>

View File

@ -1,15 +1,13 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html lang="de">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Files | {% block title %}{% endblock %}</title> <title>Files | {% block title %}{% endblock %}</title>
<link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 128 128%22><text y=%221.2em%22 font-size=%2296%22>⚫️</text><text y=%221.3em%22 x=%220.2em%22 font-size=%2276%22 fill=%22%23fff%22>sf</text></svg>"> <link rel="icon" href="icon.png">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
{% block stylesheets %} {% block stylesheets %}
{% endblock %} {% endblock %}
{% block javascripts %} {% block javascripts %}
{% block importmap %}{{ importmap('app') }}{% endblock %}
{% endblock %} {% endblock %}
</head> </head>
<body> <body>

View File

@ -1,11 +0,0 @@
{% extends 'base.html.twig' %}
{% block title %}Home{% endblock %}
{% block body %}
<center class="mt-5">
<h1>Welcome to the File Explorer</h1>
<p>Use the navigation bar to explore the files and directories.</p>
{% include '_partials/_table.html.twig' %}
</center>
{% endblock %}

View File

@ -0,0 +1,7 @@
{% extends 'base.html.twig' %}
{% block title %}Home{% endblock %}
{% block body %}
{{ app.user.username }}
{% endblock %}