Compare commits
	
		
			1 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					1f341d6781 | 
							
								
								
									
										7
									
								
								asset/lean-api/js/api-console.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								asset/lean-api/js/api-console.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,7 @@
 | 
				
			|||||||
 | 
					class ApiConsole {
 | 
				
			||||||
 | 
					    constructor(options) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -38,8 +38,7 @@
 | 
				
			|||||||
        "lean" : {
 | 
					        "lean" : {
 | 
				
			||||||
            "autoload": {
 | 
					            "autoload": {
 | 
				
			||||||
                "definitions" : [
 | 
					                "definitions" : [
 | 
				
			||||||
                    "meta/definitions/software.php",
 | 
					                    "meta/definitions/software.php"
 | 
				
			||||||
                    "meta/definitions/storage.php"
 | 
					 | 
				
			||||||
                ],
 | 
					                ],
 | 
				
			||||||
                "config": [
 | 
					                "config": [
 | 
				
			||||||
                    "meta/config.php"
 | 
					                    "meta/config.php"
 | 
				
			||||||
 | 
				
			|||||||
@ -1,28 +1,9 @@
 | 
				
			|||||||
<?php
 | 
					<?php
 | 
				
			||||||
 | 
					
 | 
				
			||||||
$path = dirname(__DIR__, 1);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
return [
 | 
					return [
 | 
				
			||||||
    'lean' => [
 | 
					    'lean' => [
 | 
				
			||||||
        'autoload' => [
 | 
					        'autoload' => [
 | 
				
			||||||
            'lean.api',
 | 
					            'lean.api',
 | 
				
			||||||
        ]
 | 
					        ]
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
 | 
					];
 | 
				
			||||||
    'ulmus' => [
 | 
					 | 
				
			||||||
        'connections' => [
 | 
					 | 
				
			||||||
            'lean.api' => [
 | 
					 | 
				
			||||||
                'adapter'  => getenv("LEAN_API_ADAPTER") ?: "SQLite",
 | 
					 | 
				
			||||||
                'path'     =>  getenv('PROJECT_PATH') . DIRECTORY_SEPARATOR . ( getenv("LEAN_API_PATH") ?: "var/lean-api.sqlite3" ),
 | 
					 | 
				
			||||||
                'pragma_begin' => array_merge(
 | 
					 | 
				
			||||||
                    explode(',', getenv("LEAN_API_PRAGMA_BEGIN") ?: "foreign_keys=ON,synchronous=NORMAL"),
 | 
					 | 
				
			||||||
                    explode(',', getenv('DEBUG') ? getenv("LEAN_API_PRAGMA_DEBUG_BEGIN") : "journal_mode=WAL")
 | 
					 | 
				
			||||||
                ),
 | 
					 | 
				
			||||||
                'pragma_close' => array_merge(
 | 
					 | 
				
			||||||
                    explode(',', getenv("LEAN_API_PRAGMA_CLOSE") ?: "analysis_limit=500,optimize"),
 | 
					 | 
				
			||||||
                    explode(',', getenv('DEBUG') ? getenv("LEAN_API_PRAGMA_DEBUG_CLOSE") : "")
 | 
					 | 
				
			||||||
                ),
 | 
					 | 
				
			||||||
            ],
 | 
					 | 
				
			||||||
        ]
 | 
					 | 
				
			||||||
    ]
 | 
					 | 
				
			||||||
];
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -1,8 +1,6 @@
 | 
				
			|||||||
<?php
 | 
					<?php
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use Ulmus\ConnectionAdapter;
 | 
					$path = dirname(__DIR__, 2);
 | 
				
			||||||
 | 
					 | 
				
			||||||
putenv('LEAN_API_PROJECT_PATH=' . $path = dirname(__DIR__, 2));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
return [
 | 
					return [
 | 
				
			||||||
    'lean.api' => [
 | 
					    'lean.api' => [
 | 
				
			||||||
@ -24,13 +22,6 @@ return [
 | 
				
			|||||||
            ],
 | 
					            ],
 | 
				
			||||||
        ],
 | 
					        ],
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        'ulmus' => [
 | 
					 | 
				
			||||||
            'entities' => [ 'Lean\\Api\\Entity' => implode(DIRECTORY_SEPARATOR, [ $path, 'src', 'Entity', '' ]) ],
 | 
					 | 
				
			||||||
            'adapters' => [
 | 
					 | 
				
			||||||
                DI\get('lean.api:storage'),
 | 
					 | 
				
			||||||
            ]
 | 
					 | 
				
			||||||
        ],
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        'tell' => [
 | 
					        'tell' => [
 | 
				
			||||||
            'json' => [
 | 
					            'json' => [
 | 
				
			||||||
                [
 | 
					                [
 | 
				
			||||||
@ -40,21 +31,8 @@ return [
 | 
				
			|||||||
            ]
 | 
					            ]
 | 
				
			||||||
        ],
 | 
					        ],
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        'routes' => [
 | 
					        /*'routes' => [
 | 
				
			||||||
            'Lean\\Api\\Controller' => implode(DIRECTORY_SEPARATOR, [ $path, "src", "Controller", "" ]),
 | 
					            'Lean\\Api\\Controller' => implode(DIRECTORY_SEPARATOR, [ $path, "src", "Controller", "" ]),
 | 
				
			||||||
        ],
 | 
					        ],*/
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
 | 
					 | 
				
			||||||
    'lean.api:storage' => function($c) {
 | 
					 | 
				
			||||||
        $adapter = new ConnectionAdapter('lean.api', $c->get('config')['ulmus'], false);
 | 
					 | 
				
			||||||
        $adapter->resolveConfiguration();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return $adapter;
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    Lean\ApplicationStrategy\NotFoundDecoratorInterface::class => DI\autowire(Lean\Api\ApplicationStrategy\NotFoundDecorator::class),
 | 
					 | 
				
			||||||
    Lean\ApplicationStrategy\MethodNotAllowedInterface::class => DI\autowire(Lean\Api\ApplicationStrategy\MethodNotAllowedDecorator::class),
 | 
					 | 
				
			||||||
    Lean\Api\Factory\MessageFactoryInterface::class => DI\autowire(Lean\Api\Lib\Message::class),
 | 
					 | 
				
			||||||
    Lean\Api\Factory\DebugFormFactoryInterface::class => DI\autowire(Lean\Api\Factory\DebugFormFactory::class),
 | 
					 | 
				
			||||||
    # League\Route\Strategy\ApplicationStrategy::class => DI\autowire(Lean\Api\ApplicationStrategy::class),
 | 
					 | 
				
			||||||
];
 | 
					];
 | 
				
			||||||
@ -1,19 +0,0 @@
 | 
				
			|||||||
<?php
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use Psr\Container\ContainerInterface;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use Ulmus\ConnectionAdapter,
 | 
					 | 
				
			||||||
    Ulmus\Container\AdapterProxy;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use Storage\Session;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use function DI\autowire, DI\create, DI\get;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
return [
 | 
					 | 
				
			||||||
   'lean.api:storage' => function($c) {
 | 
					 | 
				
			||||||
        $adapter = new ConnectionAdapter('lean.api', $c->get('config')['ulmus'], false);
 | 
					 | 
				
			||||||
        $adapter->resolveConfiguration();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return $adapter;
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
];
 | 
					 | 
				
			||||||
@ -1,21 +0,0 @@
 | 
				
			|||||||
# LEAN API
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## Debug tooling to help development within Lean's API
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[Documentation](../) / Debug API queries
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
--------------------------------------------------------------------------------
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### Routes
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
{route:descriptor}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
{request:debugger}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### Forms / actions
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
{form:descriptor}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### Entities
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
{entity:descriptor}
 | 
					 | 
				
			||||||
@ -1,21 +0,0 @@
 | 
				
			|||||||
# LEAN API
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## Debug tooling to help development within Lean's API
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[Lean API](../../debug) / Debug API queries
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
--------------------------------------------------------------------------------
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### Routes
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
{route:descriptor}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
{request:debugger}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### Forms / actions
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
{form:descriptor}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### Entities
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
{entity:descriptor}
 | 
					 | 
				
			||||||
@ -1,7 +0,0 @@
 | 
				
			|||||||
# Lean API
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## Lean's API internal debug API
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### Routes disponibles
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
- [Debug / Errors](./debug/errors/documentation)
 | 
					 | 
				
			||||||
@ -1,22 +1,9 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "descriptor": {
 | 
					 | 
				
			||||||
    "form": {
 | 
					 | 
				
			||||||
      "none": "Aucun formulaire existant pour cet API"
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    "entity": {
 | 
					 | 
				
			||||||
      "none": "Aucune entité trouvée pour cet API"
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    "route": {
 | 
					 | 
				
			||||||
      "none": "Aucune route trouvée pour cet API"
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  "form": {
 | 
					  "form": {
 | 
				
			||||||
    "error": {
 | 
					 | 
				
			||||||
      "entity": "Une propriété $entity est nécessaire pour envoyer ce formulaire."
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    "save": {
 | 
					    "save": {
 | 
				
			||||||
      "error": {
 | 
					      "error": {
 | 
				
			||||||
        "entity": "Une erreur est survenue en tenant de sauvegarder les données pour l'entité {$entity}.",
 | 
					        "entity": "Une propriété $entity est nécessaire dans ce form",
 | 
				
			||||||
 | 
					        "save": "Une erreur est survenue en tenant de sauvegarder les données",
 | 
				
			||||||
        "pdo": "Une erreur est survenue : '{$error}'"
 | 
					        "pdo": "Une erreur est survenue : '{$error}'"
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      "success": {
 | 
					      "success": {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,26 +0,0 @@
 | 
				
			|||||||
<?php
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace Lean\Api;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use League\Route\Strategy;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use League\Route\Http\Exception\NotFoundException;
 | 
					 | 
				
			||||||
use Lean\ApplicationStrategy\NotFoundDecoratorInterface;
 | 
					 | 
				
			||||||
use Lean\ApplicationStrategy\ThrowableHandler;
 | 
					 | 
				
			||||||
use Lean\Factory\HttpFactoryInterface;
 | 
					 | 
				
			||||||
use Picea\Asset\Asset;
 | 
					 | 
				
			||||||
use Psr\Container\ContainerInterface;
 | 
					 | 
				
			||||||
use Psr\Http\Message\ResponseInterface;
 | 
					 | 
				
			||||||
use Psr\Http\Message\ServerRequestInterface;
 | 
					 | 
				
			||||||
use Psr\Http\Server\MiddlewareInterface;
 | 
					 | 
				
			||||||
use Picea\Picea;
 | 
					 | 
				
			||||||
use Psr\Http\Server\RequestHandlerInterface;
 | 
					 | 
				
			||||||
use function DI\get;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class ApplicationStrategy extends \Lean\ApplicationStrategy {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public function getNotFoundDecorator(NotFoundException $exception): MiddlewareInterface
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return $this->getContainer()->get(NotFoundDecoratorInterface::class);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,29 +0,0 @@
 | 
				
			|||||||
<?php
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace Lean\Api\ApplicationStrategy;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use DI\Attribute\Inject;
 | 
					 | 
				
			||||||
use Lean\ApplicationStrategy;
 | 
					 | 
				
			||||||
use Lean\Factory\HttpFactoryInterface;
 | 
					 | 
				
			||||||
use Picea\Picea;
 | 
					 | 
				
			||||||
use Psr\Container\ContainerInterface;
 | 
					 | 
				
			||||||
use Psr\Http\Message\ResponseInterface;
 | 
					 | 
				
			||||||
use Psr\Http\Message\ServerRequestInterface;
 | 
					 | 
				
			||||||
use Psr\Http\Server\RequestHandlerInterface;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class MethodNotAllowedDecorator implements \Lean\ApplicationStrategy\MethodNotAllowedInterface
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if ($request->getMethod() === 'OPTIONS') {
 | 
					 | 
				
			||||||
            header('Access-Control-Allow-Origin: *');
 | 
					 | 
				
			||||||
            header('Access-Control-Allow-Methods: *');
 | 
					 | 
				
			||||||
            header('Access-Control-Allow-Headers: *');
 | 
					 | 
				
			||||||
            header('Access-Control-Allow-Credentials: true');
 | 
					 | 
				
			||||||
            exit(0);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return $handler->handle($request);;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,33 +0,0 @@
 | 
				
			|||||||
<?php
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace Lean\Api\ApplicationStrategy;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use DI\Attribute\Inject;
 | 
					 | 
				
			||||||
use Lean\Factory\HttpFactoryInterface;
 | 
					 | 
				
			||||||
use Picea\Picea;
 | 
					 | 
				
			||||||
use Psr\Container\ContainerInterface;
 | 
					 | 
				
			||||||
use Psr\Http\Message\ResponseInterface;
 | 
					 | 
				
			||||||
use Psr\Http\Message\ServerRequestInterface;
 | 
					 | 
				
			||||||
use Psr\Http\Server\MiddlewareInterface;
 | 
					 | 
				
			||||||
use Psr\Http\Server\RequestHandlerInterface;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class NotFoundDecorator extends \Lean\ApplicationStrategy\NotFoundDecorator
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        if (php_sapi_name() !== 'cli' and ! defined('STDIN'))  {
 | 
					 | 
				
			||||||
            return $this->throw404($request);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return parent::process($request, $handler);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public function throw404(ServerRequestInterface $request) : ResponseInterface
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return $this->checkAssetTrigger($request) ?: $this->httpFactory->createJsonResponse([
 | 
					 | 
				
			||||||
            'status' => 'error',
 | 
					 | 
				
			||||||
            'message' => "Not Found",
 | 
					 | 
				
			||||||
            'ts' => time(),
 | 
					 | 
				
			||||||
        ], 404);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,23 +0,0 @@
 | 
				
			|||||||
<?php
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace Lean\Api\ApplicationStrategy;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use Psr\Http\Message\ResponseInterface;
 | 
					 | 
				
			||||||
use Psr\Http\Message\ServerRequestInterface;
 | 
					 | 
				
			||||||
use Psr\Http\Server\MiddlewareInterface;
 | 
					 | 
				
			||||||
use Psr\Http\Server\RequestHandlerInterface;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class ThrowableHandler extends \Lean\ApplicationStrategy\ThrowableHandler
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    public function process(
 | 
					 | 
				
			||||||
        ServerRequestInterface $request,
 | 
					 | 
				
			||||||
        RequestHandlerInterface $handler
 | 
					 | 
				
			||||||
    ): ResponseInterface {
 | 
					 | 
				
			||||||
        try {
 | 
					 | 
				
			||||||
            return $handler->handle($request);
 | 
					 | 
				
			||||||
        } catch (\Throwable $ex) {
 | 
					 | 
				
			||||||
            echo sprintf("%s in <strong>%s</strong> <pre>%s</pre>", $ex->getMessage(), $ex->getFile() . ":" . $ex->getLine(), $ex->getTraceAsString());
 | 
					 | 
				
			||||||
            exit();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -12,6 +12,5 @@ class ContextField
 | 
				
			|||||||
        public ?int $maxLength = null,
 | 
					        public ?int $maxLength = null,
 | 
				
			||||||
        public ?string $regexFormat = null,
 | 
					        public ?string $regexFormat = null,
 | 
				
			||||||
        public ?string $example = null,
 | 
					        public ?string $example = null,
 | 
				
			||||||
        public bool $hidden = false,
 | 
					 | 
				
			||||||
    ) {}
 | 
					    ) {}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -13,6 +13,5 @@ class EntityField
 | 
				
			|||||||
        public ?string $regexFormat = null,
 | 
					        public ?string $regexFormat = null,
 | 
				
			||||||
        public mixed $example = null,
 | 
					        public mixed $example = null,
 | 
				
			||||||
        public ?string $field = null,
 | 
					        public ?string $field = null,
 | 
				
			||||||
        public ?string $setterMethod = null,
 | 
					 | 
				
			||||||
    ) {}
 | 
					    ) {}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -1,23 +0,0 @@
 | 
				
			|||||||
<?php
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace Lean\Api\Controller;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use Lean\Api\{Controller, Entity, Form, Lib};
 | 
					 | 
				
			||||||
use Notes\Route\Attribute\Method\Route;
 | 
					 | 
				
			||||||
use Notes\Route\Attribute\Object\Route as RouteObj;
 | 
					 | 
				
			||||||
use Notes\Security\Attribute\Security;
 | 
					 | 
				
			||||||
use Notes\Security\Attribute\Taxus;
 | 
					 | 
				
			||||||
use Psr\Http\Message\{ResponseInterface, ServerRequestInterface};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[Security(locked: false)]
 | 
					 | 
				
			||||||
#[RouteObj(base: "/lean/debug")]
 | 
					 | 
				
			||||||
class Debug {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    use \Lean\Api\Lib\ControllerTrait;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    #[Route("/", name: "lean.api:debug-doc", method: "GET", description: "Documentation section")]
 | 
					 | 
				
			||||||
    public function documentation(ServerRequestInterface $request, array $arguments) : ResponseInterface
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return $this->renderMarkdown(getenv("LEAN_API_PROJECT_PATH") . "/meta/docs/lean-api.md", [ Entity\Error::class, ], [ Form\Debug\ErrorContext::class ]);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,46 +0,0 @@
 | 
				
			|||||||
<?php
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace Lean\Api\Controller\Debug;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use Lean\Api\{Controller, Entity, Form, Lib};
 | 
					 | 
				
			||||||
use Notes\Route\Attribute\Method\Route;
 | 
					 | 
				
			||||||
use Notes\Route\Attribute\Object\Route as RouteObj;
 | 
					 | 
				
			||||||
use Notes\Security\Attribute\Security;
 | 
					 | 
				
			||||||
use Notes\Security\Attribute\Taxus;
 | 
					 | 
				
			||||||
use Psr\Http\Message\{ResponseInterface, ServerRequestInterface};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[Security(locked: false)]
 | 
					 | 
				
			||||||
## [Taxus(Entity\UserTypeEnum::Developer)]
 | 
					 | 
				
			||||||
#[RouteObj(base: "/lean/debug/errors")]
 | 
					 | 
				
			||||||
class Errors {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    use \Lean\Api\Lib\ControllerTrait;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    #[Route("/documentation", name: "lean.api:errors-doc", method: "GET", description: "Documentation section")]
 | 
					 | 
				
			||||||
    public function documentation(ServerRequestInterface $request, array $arguments) : ResponseInterface
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return $this->renderMarkdown(getenv("LEAN_API_PROJECT_PATH") . "/meta/docs/debug/errors.md", [ Entity\Error::class, ], [ Form\Debug\ErrorContext::class ]);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    #[Route("/", name: "lean.api:errors-list", method: [ "GET" ], description: "List every errors received")]
 | 
					 | 
				
			||||||
    public function list(ServerRequestInterface $request, array $arguments): ResponseInterface
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        $search = Entity\Error::searchRequest()->fromRequest($request);
 | 
					 | 
				
			||||||
        $collection = Entity\Error::repository()->filterServerRequest($search)->loadAll()->iterate(function($e) {
 | 
					 | 
				
			||||||
            unset($e->trace);
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return $this->output($collection, $search->count);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    #[Route("/{id:\d+}", name: "lean.api:errors-single", method: [ "GET" ], description: "Get a single error from it's ID")]
 | 
					 | 
				
			||||||
    public function single(ServerRequestInterface $request, array $arguments): ResponseInterface
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        $type = Entity\Error::class;
 | 
					 | 
				
			||||||
        $request = $this->searchEntityFromRequest($request, $type);
 | 
					 | 
				
			||||||
        $result = $request->getAttribute('lean.searchRequest');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return $this->output($result[$type]->entity, $result[$type]->search->count);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -15,9 +15,6 @@ trait DescriptorTrait
 | 
				
			|||||||
        elseif ($value instanceof \UnitEnum) {
 | 
					        elseif ($value instanceof \UnitEnum) {
 | 
				
			||||||
            return $value::class . "::" . $value->name;
 | 
					            return $value::class . "::" . $value->name;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        elseif (is_array($value)) {
 | 
					 | 
				
			||||||
            return sprintf('[ %s ]', implode(', ', array_map([ self::class, 'displayValue' ], $value)));
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return $value;
 | 
					        return $value;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -1,79 +0,0 @@
 | 
				
			|||||||
<?php
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace Lean\Api\Entity;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use Lean\Api\Attribute\EntityField;
 | 
					 | 
				
			||||||
use Ulmus\EntityTrait,
 | 
					 | 
				
			||||||
    Ulmus\SearchRequest\SearchableInterface,
 | 
					 | 
				
			||||||
    Ulmus\SearchRequest\SearchRequestInterface,
 | 
					 | 
				
			||||||
    Ulmus\Entity\Field\Datetime;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use Ulmus\{Attribute\Obj\Table,
 | 
					 | 
				
			||||||
    Entity\EntityInterface};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use Ulmus\{Api\Common\MethodEnum,
 | 
					 | 
				
			||||||
    SearchRequest,
 | 
					 | 
				
			||||||
    SearchRequest\Attribute\PropertyValueModifier\Split,
 | 
					 | 
				
			||||||
    SearchRequest\Attribute\PropertyValueSource,
 | 
					 | 
				
			||||||
    SearchRequest\Attribute\SearchOrderBy,
 | 
					 | 
				
			||||||
    SearchRequest\Attribute\SearchWhere,
 | 
					 | 
				
			||||||
    SearchRequest\SearchMethodEnum};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use Ulmus\Attribute\Property\{Field, Filter, FilterJoin, Relation, Join, Virtual, Where};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[Table(name: "debug_errors", adapter: "lean.api")]
 | 
					 | 
				
			||||||
class Error implements EntityInterface, \JsonSerializable {
 | 
					 | 
				
			||||||
    use EntityTrait;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    #[Field\Id]
 | 
					 | 
				
			||||||
    public int $id;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    #[Field]
 | 
					 | 
				
			||||||
    #[EntityField(description: "URL from which the error occurred")]
 | 
					 | 
				
			||||||
    public string $url;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    #[Field]
 | 
					 | 
				
			||||||
    #[EntityField(description: "HTTP method", field: "httpMethod")]
 | 
					 | 
				
			||||||
    public MethodEnum $method;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    #[Field]
 | 
					 | 
				
			||||||
    #[EntityField(description: "Error message")]
 | 
					 | 
				
			||||||
    public string $message;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    #[Field]
 | 
					 | 
				
			||||||
    #[EntityField(description: "Error code")]
 | 
					 | 
				
			||||||
    public int $code;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    #[Field]
 | 
					 | 
				
			||||||
    #[EntityField(description: "File from which the error occurred")]
 | 
					 | 
				
			||||||
    public string $file;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    #[Field]
 | 
					 | 
				
			||||||
    #[EntityField(description: "Line in the file from which the error occurred")]
 | 
					 | 
				
			||||||
    public int $line;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    #[Field]
 | 
					 | 
				
			||||||
    #[EntityField(description: "Stack trace of the exception")]
 | 
					 | 
				
			||||||
    public array $trace;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    #[Field\CreatedAt(name: "created_at")]
 | 
					 | 
				
			||||||
    public Datetime $createdAt;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public function __toString() {
 | 
					 | 
				
			||||||
        return mb_strlen($this->message) > 255 ? mb_substr($this->message, 0, 255) . "[...]" : $this->message;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public static function searchRequest(...$arguments) : SearchRequestInterface
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return new #[SearchRequest\Attribute\SearchRequestParameter(Error::class)] class(...$arguments) extends SearchRequest\SearchRequest {
 | 
					 | 
				
			||||||
            #[SearchRequest\Attribute\SearchWhere(source: SearchRequest\Attribute\PropertyValueSource::RequestAttribute)]
 | 
					 | 
				
			||||||
            public int $id;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            #[SearchWhere(method: SearchMethodEnum::Like)]
 | 
					 | 
				
			||||||
            public string $message;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            #[SearchOrderBy(parameter: "created_at",)]
 | 
					 | 
				
			||||||
            public string $createdAt = SearchOrderBy::DESCENDING;
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,11 +0,0 @@
 | 
				
			|||||||
<?php
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace Lean\Api\Entity\User;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
interface UserPrivilegeInterface
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    public function isDeveloper() : bool;
 | 
					 | 
				
			||||||
    public function isAdmin() : bool;
 | 
					 | 
				
			||||||
    public function isUser() : bool;
 | 
					 | 
				
			||||||
    public function isAnonymous() : bool;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,39 +0,0 @@
 | 
				
			|||||||
<?php
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace Lean\Api\Factory;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use Lean\Api\{Factory, Form, Entity, Lib};
 | 
					 | 
				
			||||||
use Lean\LanguageHandler;
 | 
					 | 
				
			||||||
use Picea\Ui\Method\FormContextInterface;
 | 
					 | 
				
			||||||
use Picea\Ui\Method\FormInterface;
 | 
					 | 
				
			||||||
use Psr\Http\Message\ServerRequestInterface;
 | 
					 | 
				
			||||||
use Ulmus\Entity\EntityInterface;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class DebugFormFactory implements DebugFormFactoryInterface
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    public function __construct(
 | 
					 | 
				
			||||||
        protected ServerRequestInterface $request,
 | 
					 | 
				
			||||||
        protected LanguageHandler $languageHandler,
 | 
					 | 
				
			||||||
        protected MessageFactoryInterface $messageFactory,
 | 
					 | 
				
			||||||
    ) {}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public function errorSave(EntityInterface|Entity\Error $entity): FormInterface
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return new Form\Debug\ErrorSave($this->languageHandler, $this->messageFactory, $entity);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public function errorSaveContext(? ServerRequestInterface $request = null, ? string $formName = null): FormContextInterface
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return new Form\Debug\ErrorContext($request ?: $this->request, $formName);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public function errorDelete(EntityInterface|Entity\Error $entity): FormInterface
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return new Form\Debug\ErrorDelete($this->languageHandler, $this->messageFactory, $entity);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public function errorDeleteContext(?ServerRequestInterface $request = null, ?string $formName = null): FormContextInterface
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return new Lib\FormContext($request, $formName);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,21 +0,0 @@
 | 
				
			|||||||
<?php
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace Lean\Api\Factory;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use Picea\Ui\Method\FormContextInterface;
 | 
					 | 
				
			||||||
use Picea\Ui\Method\FormInterface;
 | 
					 | 
				
			||||||
use Psr\Http\Message\ServerRequestInterface;
 | 
					 | 
				
			||||||
use Lean\LanguageHandler;
 | 
					 | 
				
			||||||
use Ulmus\Entity\EntityInterface;
 | 
					 | 
				
			||||||
use Lean\Api\Entity;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
interface DebugFormFactoryInterface
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    public function __construct(ServerRequestInterface $request, LanguageHandler $languageHandler, MessageFactoryInterface $messageFactory,);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    ### ERROR SAVE
 | 
					 | 
				
			||||||
    public function errorSave(Entity\Error|EntityInterface $entity): FormInterface;
 | 
					 | 
				
			||||||
    public function errorSaveContext(?ServerRequestInterface $request = null, ? string $formName = null): FormContextInterface;
 | 
					 | 
				
			||||||
    public function errorDelete(Entity\Error|EntityInterface $entity): FormInterface;
 | 
					 | 
				
			||||||
    public function errorDeleteContext(?ServerRequestInterface $request = null, ? string $formName = null): FormContextInterface;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,13 +0,0 @@
 | 
				
			|||||||
<?php
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace Lean\Api\Factory;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
interface MessageFactoryInterface
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    public static function generateSuccess(string $message, ? string $header = null, ? string $class = null) : self;
 | 
					 | 
				
			||||||
    public static function generateError(string $message, ? string $header = null, ? string $class = null) : self;
 | 
					 | 
				
			||||||
    public static function generateWarning(string $message, ? string $header = null, ? string $class = null) : self;
 | 
					 | 
				
			||||||
    public static function generateInformation(string $message, ? string $header = null, ? string $class = null) : self;
 | 
					 | 
				
			||||||
    public static function generateDebug(string $message, ? string $header = null, ? string $class = null) : self;
 | 
					 | 
				
			||||||
    public static function generateTrace(string $message, ? string $header = null, ? string $class = null) : self;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,45 +0,0 @@
 | 
				
			|||||||
<?php
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace Lean\Api\Form\Debug;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use Lean\Api\{Entity};
 | 
					 | 
				
			||||||
use Lean\Api\Attribute\ContextField;
 | 
					 | 
				
			||||||
use Picea\Ui\Method\FormContext;
 | 
					 | 
				
			||||||
use Ulmus\Api\Common\MethodEnum;
 | 
					 | 
				
			||||||
use Ulmus\Entity\Field\Datetime;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[ContextField(description: "This form saves an error received by the API")]
 | 
					 | 
				
			||||||
class ErrorContext extends FormContext
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    #[ContextField(description: "URL which the error was received from", hidden: true, )]
 | 
					 | 
				
			||||||
    public string $url;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    #[ContextField( description: "HTTP method used when this error was generated", hidden: true, )]
 | 
					 | 
				
			||||||
    public MethodEnum|string $httpMethod;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    #[ContextField(description: "Error message generated")]
 | 
					 | 
				
			||||||
    public string $message;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    #[ContextField(description: "HTTP error code")]
 | 
					 | 
				
			||||||
    public int $code;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    #[ContextField(description: "File in which the error occured")]
 | 
					 | 
				
			||||||
    public string $file;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    #[ContextField(description: "Line of the error")]
 | 
					 | 
				
			||||||
    public int $line;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    #[ContextField(description: "Complete stack trace (when available)")]
 | 
					 | 
				
			||||||
    public array $trace;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public function valid(? Entity\Error $error = null): bool
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        $server = $this->getRequest()->getServerParams();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        $this->url = ( ( 'on' === ( $server['HTTPS'] ?? false ) ) ? 'https' : 'http' ) . '://' . $server['HTTP_HOST'] . $server["REQUEST_URI"];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        $this->httpMethod = MethodEnum::from($server['REQUEST_METHOD']);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return parent::valid();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,20 +0,0 @@
 | 
				
			|||||||
<?php
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace Lean\Api\Form\Debug;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use Lean\Api\Factory\MessageFactoryInterface;
 | 
					 | 
				
			||||||
use Lean\LanguageHandler;
 | 
					 | 
				
			||||||
use Lean\Api\{Lib, Entity};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class ErrorSave extends \Lean\Api\Form\Save {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public function __construct(
 | 
					 | 
				
			||||||
        protected LanguageHandler $languageHandler,
 | 
					 | 
				
			||||||
        protected MessageFactoryInterface $message,
 | 
					 | 
				
			||||||
        public Entity\Error $entity,
 | 
					 | 
				
			||||||
    ) {
 | 
					 | 
				
			||||||
        parent::__construct($this->languageHandler, $this->message);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        $this->contextClass = ErrorContext::class;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -6,25 +6,35 @@ use CSSLSJ\ExamenFga\Api\{Lib};
 | 
				
			|||||||
use Picea\Ui\Method\{FormContextInterface};
 | 
					use Picea\Ui\Method\{FormContextInterface};
 | 
				
			||||||
use Ulmus\Entity\EntityInterface;
 | 
					use Ulmus\Entity\EntityInterface;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
abstract class Delete implements \Picea\Ui\Method\FormInterface {
 | 
					class Delete implements \Picea\Ui\Method\FormInterface {
 | 
				
			||||||
    use FormTrait;
 | 
					
 | 
				
			||||||
 | 
					    public function __construct(
 | 
				
			||||||
 | 
					        public EntityInterface $entity,
 | 
				
			||||||
 | 
					    ) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function getEntity() : EntityInterface
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->entity;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function initialize(FormContextInterface $context) : void {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function validate(FormContextInterface $context) : bool
 | 
					    public function validate(FormContextInterface $context) : bool
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if ( ! $this->entity->isLoaded() ) {
 | 
					        if ( ! $this->entity->isLoaded() ) {
 | 
				
			||||||
            $context->pushMessage($this->message::generateError(
 | 
					            $context->pushMessage(Lib\Message::generateError(
 | 
				
			||||||
                $this->lang('lean.api.form.delete.error.entity')
 | 
					                $this->lang('lean.api.form.delete.error.entity')
 | 
				
			||||||
            ));
 | 
					            ));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return $context->valid($this->getEntity()->isLoaded() ? $this->getEntity() : null);
 | 
					        return $context->valid();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function execute(FormContextInterface $context) : void
 | 
					    public function execute(FormContextInterface $context) : void
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
            if ( $this->getEntity()::repository()->destroy($this->getEntity()) ) {
 | 
					            if ( $this->getEntity()::repository()->destroy($this->getEntity()) ) {
 | 
				
			||||||
                $context->pushMessage($this->message::generateSuccess(
 | 
					                $context->pushMessage(Lib\Message::generateSuccess(
 | 
				
			||||||
                    $this->lang('lean.api.form.delete.success.save')
 | 
					                    $this->lang('lean.api.form.delete.success.save')
 | 
				
			||||||
                ));
 | 
					                ));
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
				
			|||||||
@ -1,42 +0,0 @@
 | 
				
			|||||||
<?php
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace Lean\Api\Form;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use Lean\Api\Factory\MessageFactoryInterface;
 | 
					 | 
				
			||||||
use Lean\LanguageHandler;
 | 
					 | 
				
			||||||
use Picea\Ui\Method\FormContextInterface;
 | 
					 | 
				
			||||||
use Ulmus\Entity\EntityInterface;
 | 
					 | 
				
			||||||
use Ulmus\EntityCollection;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
trait FormTrait
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    public function __construct(
 | 
					 | 
				
			||||||
        protected LanguageHandler $languageHandler,
 | 
					 | 
				
			||||||
        protected MessageFactoryInterface $message,
 | 
					 | 
				
			||||||
        # public EntityInterface $entity,
 | 
					 | 
				
			||||||
    ) {}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public function initialize(FormContextInterface $context) : void
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        if(isset($this->contextClass) && ! $context instanceof $this->contextClass ) {
 | 
					 | 
				
			||||||
            throw new \LogicException(
 | 
					 | 
				
			||||||
                sprintf("Your context type should be a %s", $this->contextClass)
 | 
					 | 
				
			||||||
            );
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public function lang(string $key, array $variables = [])
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return $this->languageHandler->languageFromKey($key, $variables);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public function getEntity() : EntityInterface|EntityCollection
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        if (! isset($this->entity)) {
 | 
					 | 
				
			||||||
            throw new \InvalidArgumentException($this->lang("lean.api.form.error.entity"));
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return $this->entity;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,13 +0,0 @@
 | 
				
			|||||||
<?php
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace Lean\Api\Form;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
enum MessageTypeEnum
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    case Error;
 | 
					 | 
				
			||||||
    case Success;
 | 
					 | 
				
			||||||
    case Information;
 | 
					 | 
				
			||||||
    case Warning;
 | 
					 | 
				
			||||||
    case Debug;
 | 
					 | 
				
			||||||
    case Trace;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -2,19 +2,33 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace Lean\Api\Form;
 | 
					namespace Lean\Api\Form;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use CSLSJ\Lean\Form\Session\EmailContext;
 | 
					use CSSLSJ\ExamenFga\Api\{Form\Location\SessionContext, Lib, Entity};
 | 
				
			||||||
use Picea\Ui\Method\{ FormContextInterface, };
 | 
					use Picea\Ui\Method\{ FormContextInterface, Message\ErrorMessage };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use Ulmus\Attribute\Property\Field;
 | 
					use Ulmus\Attribute\Property\Field;
 | 
				
			||||||
use Lean\Api\Attribute\EntityField;
 | 
					use Lean\Api\Attribute\EntityField;
 | 
				
			||||||
 | 
					use Lean\LanguageHandler;
 | 
				
			||||||
 | 
					use Psr\Http\Message\ServerRequestInterface;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use Ulmus\Entity\EntityInterface;
 | 
					use Ulmus\Entity\EntityInterface;
 | 
				
			||||||
use Ulmus\Entity\Field\Datetime;
 | 
					use Ulmus\Entity\Field\Datetime;
 | 
				
			||||||
 | 
					use function CSSLSJ\ExamenFga\Api\View\{ lang };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
abstract class Save implements \Picea\Ui\Method\FormInterface {
 | 
					abstract class Save implements \Picea\Ui\Method\FormInterface {
 | 
				
			||||||
    use FormTrait;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    protected string $contextClass;
 | 
					    public function __construct(
 | 
				
			||||||
 | 
					        protected LanguageHandler $languageHandler,
 | 
				
			||||||
 | 
					#        public EntityInterface $entity,
 | 
				
			||||||
 | 
					    ) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function getEntity() : EntityInterface
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (! isset($this->entity)) {
 | 
				
			||||||
 | 
					            throw new \InvalidArgumentException($this->lang("lean.api.form.save.error.entity"));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $this->entity;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function validate(FormContextInterface $context) : bool
 | 
					    public function validate(FormContextInterface $context) : bool
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
@ -22,43 +36,37 @@ abstract class Save implements \Picea\Ui\Method\FormInterface {
 | 
				
			|||||||
        return $context->valid($this->getEntity()->isLoaded() ? $this->getEntity() : null);
 | 
					        return $context->valid($this->getEntity()->isLoaded() ? $this->getEntity() : null);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function execute(FormContextInterface $context) : mixed
 | 
					    public function execute(FormContextInterface $context) : void
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $entity = $this->getEntity();
 | 
					        $entity = $this->getEntity();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if  ($entity->isLoaded()) {
 | 
					        if  ($entity->isLoaded() ) {
 | 
				
			||||||
            if (property_exists($entity, 'updatedAt') && $entity->repository()->generateDatasetDiff($entity) ) {
 | 
					            $entity->updatedAt = new Datetime();
 | 
				
			||||||
                $entity->updatedAt = new Datetime();
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        else {
 | 
					        else {
 | 
				
			||||||
            if (property_exists($entity, 'createdAt') && empty($entity->createdAt)) {
 | 
					            $entity->createdAt = new Datetime();
 | 
				
			||||||
                $entity->createdAt = new Datetime();
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
            $this->assignContextToEntity($context);
 | 
					            $this->assignContextToEntity($context);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if ( $saved = $entity::repository()->save($entity) ) {
 | 
					            if ( $entity::repository()->save($entity) ) {
 | 
				
			||||||
                $context->pushMessage($this->message::generateSuccess(
 | 
					                $context->pushMessage(Lib\Message::generateSuccess(
 | 
				
			||||||
                    $this->lang('lean.api.form.save.success.entity')
 | 
					                    $this->lang('lean.api.form.save.success.entity')
 | 
				
			||||||
                ));
 | 
					                ));
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else {
 | 
					            else {
 | 
				
			||||||
                $context->pushMessage($this->message::generateWarning(
 | 
					                throw new \InvalidArgumentException($this->lang('lean.api.form.save.error.entity'));
 | 
				
			||||||
                    $this->lang('lean.api.form.save.error.entity', [ 'entity' => $this->entity::class ])
 | 
					 | 
				
			||||||
                ));
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        catch(\PDOException $ex) {
 | 
					 | 
				
			||||||
            throw new \PDOException($this->lang('lean.api.form.save.error.pdo', [ 'error' => $ex->getMessage() ]));
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        catch(\Throwable $ex) {
 | 
					        catch(\Throwable $ex) {
 | 
				
			||||||
            throw $ex;
 | 
					            throw new \ErrorException($this->lang('lean.api.form.save.error.pdo', [ 'error' => $ex->getMessage() ]));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return $saved;
 | 
					    protected function lang(string $key, array $variables = [])
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->languageHandler->languageFromKey($key, $variables);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    protected function assignContextToEntity(FormContextInterface $context) : void
 | 
					    protected function assignContextToEntity(FormContextInterface $context) : void
 | 
				
			||||||
@ -67,20 +75,19 @@ abstract class Save implements \Picea\Ui\Method\FormInterface {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        foreach($entity::resolveEntity()->fieldList() as $key => $property) {
 | 
					        foreach($entity::resolveEntity()->fieldList() as $key => $property) {
 | 
				
			||||||
            $field = $property->getAttribute(Field::class)->object;
 | 
					            $field = $property->getAttribute(Field::class)->object;
 | 
				
			||||||
            if (! $field->readonly || ! $entity->isLoaded()) {
 | 
					
 | 
				
			||||||
 | 
					            if (! $field->readonly) {
 | 
				
			||||||
                $apiField = $property->getAttribute(EntityField::class)->object ?? null;
 | 
					                $apiField = $property->getAttribute(EntityField::class)->object ?? null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if ($apiField) {
 | 
					                if ($apiField) {
 | 
				
			||||||
                    $var = $apiField->field ?: $key;
 | 
					                    if ($apiField->field) {
 | 
				
			||||||
 | 
					                        if ( isset($context->{$apiField->field}) ) {
 | 
				
			||||||
                    if ( property_exists($context, $var) && ( new \ReflectionProperty($context, $var) )->isInitialized($context) ) {
 | 
					                            $entity->$key = $context->{$apiField->field};
 | 
				
			||||||
                        if ($apiField->setterMethod) {
 | 
					 | 
				
			||||||
                            # Use a setter method
 | 
					 | 
				
			||||||
                            call_user_func([ $entity, $apiField->setterMethod ], $context->{$var});
 | 
					 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        else {
 | 
					                    }
 | 
				
			||||||
                            # Direct property set
 | 
					                    else {
 | 
				
			||||||
                            $entity->$key = $context->{$var};
 | 
					                        if ( isset($context->{$key}) ) {
 | 
				
			||||||
 | 
					                            $entity->$key = $context->{$key};
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
				
			|||||||
@ -15,6 +15,7 @@ class FormDescriptor
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        foreach($forms as $form) {
 | 
					        foreach($forms as $form) {
 | 
				
			||||||
            $fields = [];
 | 
					            $fields = [];
 | 
				
			||||||
 | 
					            $propertyHtml = "";
 | 
				
			||||||
            $formName = is_object($form) ? $form::class : $form;
 | 
					            $formName = is_object($form) ? $form::class : $form;
 | 
				
			||||||
            $reflector = new ObjectReflection($formName);
 | 
					            $reflector = new ObjectReflection($formName);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -23,19 +24,17 @@ class FormDescriptor
 | 
				
			|||||||
            foreach($reflector->reflectProperties() as $property) {
 | 
					            foreach($reflector->reflectProperties() as $property) {
 | 
				
			||||||
                $field = $property->getAttribute(ContextField::class);
 | 
					                $field = $property->getAttribute(ContextField::class);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if ($field && ! $field->object->hidden ) {
 | 
					                if ($field) {
 | 
				
			||||||
                    $types = $property->getTypes();
 | 
					                    $types = $property->getTypes();
 | 
				
			||||||
 | 
					 | 
				
			||||||
                    $fields[] = [
 | 
					                    $fields[] = [
 | 
				
			||||||
                        'name' => $property->name,
 | 
					                        'name' => $property->name,
 | 
				
			||||||
                        'description' => $field->object->description,
 | 
					                        'description' => $field->object->description,
 | 
				
			||||||
                        'type' => $field->object->type ?? $types,
 | 
					                        'type' => $field->object->type ?? implode(' | ', array_map(fn($e) => $e->type, $types)),
 | 
				
			||||||
                        'allowNulls' => $property->allowsNull(),
 | 
					                        'allowNulls' => $property->allowsNull(),
 | 
				
			||||||
                        'regexPattern' => $field->object->regexFormat ?? null,
 | 
					                        'regexPattern' =>$field->object->regexFormat ?? "aucun",
 | 
				
			||||||
                        'minLength' => $field->object->minLength ?? null,
 | 
					                        'minLength' =>$field->object->minLength ?? "aucune",
 | 
				
			||||||
                        'maxLength' => $field->object->maxLength ?? null,
 | 
					                        'maxLength' =>$field->object->maxLength ?? "aucune",
 | 
				
			||||||
                        'example' =>  $field->object->example ?? null,
 | 
					                        'example' =>$field->object->example,
 | 
				
			||||||
                        'values' => $this->generateExampleValues($types),
 | 
					 | 
				
			||||||
                    ];
 | 
					                    ];
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@ -49,17 +48,4 @@ class FormDescriptor
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        return $list;
 | 
					        return $list;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
    protected function generateExampleValues(array $types) : string|array
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        $values = [];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        foreach($types as $type) {
 | 
					 | 
				
			||||||
            if ( enum_exists($type->type) ) {
 | 
					 | 
				
			||||||
                $values = array_merge($values, array_map(fn($e) => $e->value, $type->type::cases()));
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return $values;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -2,24 +2,14 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace Lean\Api;
 | 
					namespace Lean\Api;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use DI\Attribute\Inject;
 | 
					 | 
				
			||||||
use League\CommonMark\CommonMarkConverter;
 | 
					use League\CommonMark\CommonMarkConverter;
 | 
				
			||||||
use Lean\Api\Lib\ApiSearchRequestInterface;
 | 
					 | 
				
			||||||
use Notes\Attribute\Ignore;
 | 
					use Notes\Attribute\Ignore;
 | 
				
			||||||
use Psr\Container\ContainerInterface;
 | 
					 | 
				
			||||||
use Psr\Http\Message\ResponseInterface;
 | 
					use Psr\Http\Message\ResponseInterface;
 | 
				
			||||||
use Psr\Http\Message\ServerRequestInterface;
 | 
					 | 
				
			||||||
use Ulmus\Entity\EntityInterface;
 | 
					 | 
				
			||||||
use Ulmus\EntityCollection;
 | 
					 | 
				
			||||||
use Ulmus\SearchRequest\SearchRequestInterface;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
trait LeanApiTrait
 | 
					trait LeanApiTrait
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    use DescriptorTrait;
 | 
					    use DescriptorTrait;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[Inject]
 | 
					 | 
				
			||||||
    protected ContainerInterface $container;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    #[Ignore]
 | 
					    #[Ignore]
 | 
				
			||||||
    public function renderMarkdown(string $filepath, array $entities = [], array $forms = [], int $code = 200, array $headers = []) : ResponseInterface
 | 
					    public function renderMarkdown(string $filepath, array $entities = [], array $forms = [], int $code = 200, array $headers = []) : ResponseInterface
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
@ -32,15 +22,10 @@ trait LeanApiTrait
 | 
				
			|||||||
        if (str_contains($markdown, '{route:descriptor}'))
 | 
					        if (str_contains($markdown, '{route:descriptor}'))
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            $markdown = str_replace('{route:descriptor}', $this->renderRawView('lean-api/route_descriptor', [
 | 
					            $markdown = str_replace('{route:descriptor}', $this->renderRawView('lean-api/route_descriptor', [
 | 
				
			||||||
                'routes' => (new RouteDescriptor($this, $this->picea->compiler->getExtensionFromToken('url'), $this->container))->getRoutes()
 | 
					                'routes' => (new RouteDescriptor($this, $this->picea->compiler->getExtensionFromToken('url')))->getRoutes()
 | 
				
			||||||
            ]), $markdown);
 | 
					            ]), $markdown);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (str_contains($markdown, '{request:debugger}'))
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            $markdown = str_replace('{request:debugger}', $this->renderRawView('lean-api/request_debugger', []), $markdown);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (str_contains($markdown, '{entity:descriptor}'))
 | 
					        if (str_contains($markdown, '{entity:descriptor}'))
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            $markdown = str_replace('{entity:descriptor}', $this->renderRawView('lean-api/entity_descriptor', [
 | 
					            $markdown = str_replace('{entity:descriptor}', $this->renderRawView('lean-api/entity_descriptor', [
 | 
				
			||||||
@ -59,81 +44,10 @@ trait LeanApiTrait
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[Ignore]
 | 
					    #[Ignore]
 | 
				
			||||||
    protected function output(\JsonSerializable|array $data, int $count) : ResponseInterface
 | 
					    protected function output(\JsonSerializable|array $data, int $count) {
 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return $this->renderJson([
 | 
					        return $this->renderJson([
 | 
				
			||||||
            'data' => $data,
 | 
					            'data' => $data,
 | 
				
			||||||
            'count' => $count,
 | 
					            'count' => $count,
 | 
				
			||||||
        ]);
 | 
					        ]);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
    #[Ignore]
 | 
					 | 
				
			||||||
    protected function outputSearchResult(ApiSearchRequestInterface $apiSearchRequest) : ResponseInterface
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return $this->output($apiSearchRequest->getResult(), $apiSearchRequest->getSearch()->count);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    #[Ignore]
 | 
					 | 
				
			||||||
        protected function searchEntityFromRequest(ServerRequestInterface $request, string $entityType, ? string $resultKey = null) : ServerRequestInterface
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        $search = $entityType::searchRequest()->fromRequest($request);
 | 
					 | 
				
			||||||
        $entity = $entityType::repository()->filterServerRequest($search)->loadOne() ?? false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (! $entity ) {
 | 
					 | 
				
			||||||
            throw new \InvalidArgumentException(sprintf("L'entré pour l'entité demandé (%s) est introuvable avec le ou les arguments fournis '%s'", $entityType, json_encode($request->getAttributes())));
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return $request->withAttribute("lean.searchRequest",
 | 
					 | 
				
			||||||
            [
 | 
					 | 
				
			||||||
                $resultKey ?: $entityType => new class($search, $entity) implements ApiSearchRequestInterface {
 | 
					 | 
				
			||||||
                    public function __construct(
 | 
					 | 
				
			||||||
                        public readonly SearchRequestInterface $search,
 | 
					 | 
				
			||||||
                        public readonly EntityInterface        $entity,
 | 
					 | 
				
			||||||
                    ) {}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    public function getSearch(): SearchRequestInterface
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        return $this->search;
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    public function getResult(): EntityCollection|EntityInterface
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        return $this->entity;
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            ] + $request->getAttribute("lean.searchRequest", [])
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    #[Ignore]
 | 
					 | 
				
			||||||
    protected function searchEntitiesFromRequest(ServerRequestInterface $request, string $entityType, ? string $resultKey = null) : ServerRequestInterface
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        $search = $entityType::searchRequest()->fromRequest($request);
 | 
					 | 
				
			||||||
        $entity = $entityType::repository()->filterServerRequest($search)->loadAll();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (! $entity ) {
 | 
					 | 
				
			||||||
            throw new \InvalidArgumentException(sprintf("L'entré pour l'entité demandé (%s) est introuvable avec le ou les arguments fournis '%s'", $entityType, json_encode($request->getAttributes())));
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return $request->withAttribute("lean.searchRequest",
 | 
					 | 
				
			||||||
            [
 | 
					 | 
				
			||||||
                $resultKey ?: $entityType => new class($search, $entity) implements ApiSearchRequestInterface {
 | 
					 | 
				
			||||||
                    public function __construct(
 | 
					 | 
				
			||||||
                        public readonly SearchRequestInterface $search,
 | 
					 | 
				
			||||||
                        public readonly EntityCollection       $collection,
 | 
					 | 
				
			||||||
                    ) {}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    public function getSearch(): SearchRequestInterface
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        return $this->search;
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    public function getResult(): EntityCollection|EntityInterface
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        return $this->collection;
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            ] + $request->getAttribute("lean.searchRequest", [])
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -1,13 +0,0 @@
 | 
				
			|||||||
<?php
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace Lean\Api\Lib;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use Ulmus\Entity\EntityInterface;
 | 
					 | 
				
			||||||
use Ulmus\EntityCollection;
 | 
					 | 
				
			||||||
use Ulmus\SearchRequest\SearchRequestInterface;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
interface ApiSearchRequestInterface
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    public function getSearch() : SearchRequestInterface;
 | 
					 | 
				
			||||||
    public function getResult() : EntityCollection|EntityInterface;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,13 +0,0 @@
 | 
				
			|||||||
<?php
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace Lean\Api\Lib;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use Notes\Route\Attribute\Object\Route;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[Route(method: ['GET', 'POST', ])]
 | 
					 | 
				
			||||||
trait ControllerTrait
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    use \Lean\ControllerTrait, \Lean\Api\LeanApiTrait {
 | 
					 | 
				
			||||||
        \Lean\Api\LeanApiTrait::renderMarkdown insteadof \Lean\ControllerTrait;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,49 +0,0 @@
 | 
				
			|||||||
<?php
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace Lean\Api\Lib;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use Lean\Api\Factory\MessageFactoryInterface;
 | 
					 | 
				
			||||||
use Lean\LanguageHandler;
 | 
					 | 
				
			||||||
use Psr\Http\Message\ServerRequestInterface;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class FormContext extends \Picea\Ui\Method\FormContext {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public function __construct(
 | 
					 | 
				
			||||||
        protected LanguageHandler $languageHandler,
 | 
					 | 
				
			||||||
        protected MessageFactoryInterface $message,
 | 
					 | 
				
			||||||
        ServerRequestInterface $request,
 | 
					 | 
				
			||||||
        ? string $formName = null
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        parent::__construct($request, $formName);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public function lang(string $key, array $variables = [])
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return $this->languageHandler->languageFromKey($key, $variables);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public function pushSuccessMessage($key, $variables = []) {
 | 
					 | 
				
			||||||
        $this->pushMessage($this->message::generateSuccess(
 | 
					 | 
				
			||||||
            $this->lang($key, $variables)
 | 
					 | 
				
			||||||
        ));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public function pushWarningMessage($key, $variables = []) {
 | 
					 | 
				
			||||||
        $this->pushMessage($this->message::generateWarning(
 | 
					 | 
				
			||||||
            $this->lang($key, $variables)
 | 
					 | 
				
			||||||
        ));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public function pushErrorMessage($key, $variables = []) {
 | 
					 | 
				
			||||||
        $this->pushMessage($this->message::generateError(
 | 
					 | 
				
			||||||
            $this->lang($key, $variables)
 | 
					 | 
				
			||||||
        ));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public function pushInfoMessage($key, $variables = []) {
 | 
					 | 
				
			||||||
        $this->pushMessage($this->message::generateInfo(
 | 
					 | 
				
			||||||
            $this->lang($key, $variables)
 | 
					 | 
				
			||||||
        ));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,132 +0,0 @@
 | 
				
			|||||||
<?php declare(strict_types=1);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace Lean\Api\Lib;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use Lean\Api\Factory\MessageFactoryInterface;
 | 
					 | 
				
			||||||
use Picea\Ui\Method\FormMessage;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class Message implements FormMessage, MessageFactoryInterface {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const MESSAGE_TYPE = [
 | 
					 | 
				
			||||||
        'success' => [
 | 
					 | 
				
			||||||
            'class' => 'success',
 | 
					 | 
				
			||||||
            'header' => 'Succès !',
 | 
					 | 
				
			||||||
            'message' => ''
 | 
					 | 
				
			||||||
        ],
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        'error' => [
 | 
					 | 
				
			||||||
            'class' => 'danger',
 | 
					 | 
				
			||||||
            'header' => 'Error !',
 | 
					 | 
				
			||||||
            'message' => ''
 | 
					 | 
				
			||||||
        ],
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        'warning' => [
 | 
					 | 
				
			||||||
            'class' => 'warning',
 | 
					 | 
				
			||||||
            'header' => 'Attention !',
 | 
					 | 
				
			||||||
            'message' => ''
 | 
					 | 
				
			||||||
        ],
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        'information' => [
 | 
					 | 
				
			||||||
            'class' => 'information',
 | 
					 | 
				
			||||||
            'header' => 'À savoir !',
 | 
					 | 
				
			||||||
            'message' => ''
 | 
					 | 
				
			||||||
        ],
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        'debug' => [
 | 
					 | 
				
			||||||
            'class' => 'debug',
 | 
					 | 
				
			||||||
            'header' => 'Debug :',
 | 
					 | 
				
			||||||
            'message' => ''
 | 
					 | 
				
			||||||
        ],
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        'trace' => [
 | 
					 | 
				
			||||||
            'class' => 'trace',
 | 
					 | 
				
			||||||
            'header' => 'Trace :',
 | 
					 | 
				
			||||||
            'message' => ''
 | 
					 | 
				
			||||||
        ]
 | 
					 | 
				
			||||||
    ];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public string $type;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public string $message;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public string $class;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public ? string $header = null;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public function __construct(string $message = "", string $type = "error", ? string $header = null, ? string $class = null)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        $this->message = $message;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        $this->type = $type;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if ( $header !== null ) {
 | 
					 | 
				
			||||||
            $this->header = $header;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        else {
 | 
					 | 
				
			||||||
            $this->header = static::MESSAGE_TYPE[$type]['header'];
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if ( $class !== null ) {
 | 
					 | 
				
			||||||
            $this->class = $class;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        else {
 | 
					 | 
				
			||||||
            $this->class = static::MESSAGE_TYPE[$type]['class'];
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public function render() : string
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return <<<HTML
 | 
					 | 
				
			||||||
            <article class="message is-{$this->class}" role="alert">
 | 
					 | 
				
			||||||
                <div class="message-body">
 | 
					 | 
				
			||||||
                    <strong>{$this->header}</strong> 
 | 
					 | 
				
			||||||
                    <span>{$this->message}</span>
 | 
					 | 
				
			||||||
                </div>
 | 
					 | 
				
			||||||
            </article>
 | 
					 | 
				
			||||||
        HTML;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public function renderJson() : array
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return [
 | 
					 | 
				
			||||||
            'name' => 'message',
 | 
					 | 
				
			||||||
            'type' => $this->type,
 | 
					 | 
				
			||||||
            'message' => $this->message,
 | 
					 | 
				
			||||||
        ];
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public function isError() : bool
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return $this->type === "error";
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public static function generateSuccess(string $message, ? string $header = null, ? string $class = null) : self
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return new static($message, 'success', $header, $class);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public static function generateError(string $message, ? string $header = null, ? string $class = null) : self
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return new static($message, 'error', $header, $class);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public static function generateWarning(string $message, ? string $header = null, ? string $class = null) : self
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return new static($message, 'warning', $header, $class);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public static function generateInformation(string $message, ? string $header = null, ? string $class = null) : self
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return new static($message, 'information', $header, $class);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public static function generateDebug(string $message, ? string $header = null, ? string $class = null) : self
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return new static($message, 'debug', $header, $class);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public static function generateTrace(string $message, ? string $header = null, ? string $class = null) : self
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return new static($message, 'trace', $header, $class);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -4,44 +4,29 @@ namespace Lean\Api\Middleware;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
use Laminas\Diactoros\Response\JsonResponse;
 | 
					use Laminas\Diactoros\Response\JsonResponse;
 | 
				
			||||||
use Lean\Factory\HttpFactory;
 | 
					use Lean\Factory\HttpFactory;
 | 
				
			||||||
use Picea\Ui\Method\FormHandler;
 | 
					 | 
				
			||||||
use Psr\Http\Message\ResponseInterface;
 | 
					use Psr\Http\Message\ResponseInterface;
 | 
				
			||||||
use Psr\Http\Message\ServerRequestInterface;
 | 
					use Psr\Http\Message\ServerRequestInterface;
 | 
				
			||||||
use Psr\Http\Server\MiddlewareInterface;
 | 
					use Psr\Http\Server\MiddlewareInterface;
 | 
				
			||||||
use Psr\Http\Server\RequestHandlerInterface;
 | 
					use Psr\Http\Server\RequestHandlerInterface;
 | 
				
			||||||
use Lean\Api\{Factory\DebugFormFactoryInterface, Form, Entity};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ApiRenderer implements MiddlewareInterface {
 | 
					class ApiRenderer implements MiddlewareInterface {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function __construct(
 | 
					 | 
				
			||||||
        protected DebugFormFactoryInterface $debugFormFactory,
 | 
					 | 
				
			||||||
    ) {
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler) : ResponseInterface
 | 
					    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler) : ResponseInterface
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        try {
 | 
					        try { 
 | 
				
			||||||
            $response = $handler->handle($request);
 | 
					            $response = $handler->handle($request);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        catch(\Throwable $ex) {
 | 
					        catch(\Exception $ex) {
 | 
				
			||||||
            # $errorId = $this->saveError($request, $ex)->id;
 | 
					            if ( ! getenv('DEBUG') ) {
 | 
				
			||||||
 | 
					 | 
				
			||||||
            if ($this->awaitingJson($request)) {
 | 
					 | 
				
			||||||
                return HttpFactory::createJsonResponse([
 | 
					                return HttpFactory::createJsonResponse([
 | 
				
			||||||
                    'status' => 'failed',
 | 
					                    'status' => 'failed',
 | 
				
			||||||
 | 
					                    'message' => $ex->getMessage(),
 | 
				
			||||||
                    'ts' => time(),
 | 
					                    'ts' => time(),
 | 
				
			||||||
                    'data' => [
 | 
					                ], 400);
 | 
				
			||||||
                       # 'error_id' => $errorId,
 | 
					            }
 | 
				
			||||||
                        'message' => $ex->getMessage(),
 | 
					            else {
 | 
				
			||||||
                    ] + (getenv('DEBUG') ? [
 | 
					                throw $ex;
 | 
				
			||||||
                        'file' => $ex->getFile(),
 | 
					 | 
				
			||||||
                        'line' => $ex->getLine(),
 | 
					 | 
				
			||||||
                        'code' => $ex->getCode(),
 | 
					 | 
				
			||||||
                        'backtrace' => $ex->getTrace(), ] : [])
 | 
					 | 
				
			||||||
                ], 500);
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					 | 
				
			||||||
            throw $ex;
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if ($response instanceof JsonResponse) {
 | 
					        if ($response instanceof JsonResponse) {
 | 
				
			||||||
@ -58,30 +43,4 @@ class ApiRenderer implements MiddlewareInterface {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        return $response;
 | 
					        return $response;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
    protected function saveError(ServerRequestInterface $request, \Throwable $exception) : Entity\Error
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        $request = $request->withMethod('PUT')->withParsedBody([]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        $context = $this->debugFormFactory->errorSaveContext($request);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        $context->sets([
 | 
					 | 
				
			||||||
            'message' => $exception->getMessage(),
 | 
					 | 
				
			||||||
            'code' => $exception->getCode(),
 | 
					 | 
				
			||||||
            'file' => $exception->getFile(),
 | 
					 | 
				
			||||||
            'line' => $exception->getLine(),
 | 
					 | 
				
			||||||
            'trace' => $exception->getTrace(),
 | 
					 | 
				
			||||||
        ]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        $form = $this->debugFormFactory->errorSave($entity = new Entity\Error());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        new FormHandler($request, $form, $context);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return $entity;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    protected function awaitingJson(ServerRequestInterface $request) : bool
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return str_contains(strtolower($request->getHeaderLine('content-type')), 'json');
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,26 +0,0 @@
 | 
				
			|||||||
<?php
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace Lean\Api\Middleware;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use Laminas\Diactoros\Response\JsonResponse;
 | 
					 | 
				
			||||||
use Lean\Factory\HttpFactory;
 | 
					 | 
				
			||||||
use Picea\Ui\Method\FormHandler;
 | 
					 | 
				
			||||||
use Psr\Http\Message\ResponseInterface;
 | 
					 | 
				
			||||||
use Psr\Http\Message\ServerRequestInterface;
 | 
					 | 
				
			||||||
use Psr\Http\Server\MiddlewareInterface;
 | 
					 | 
				
			||||||
use Psr\Http\Server\RequestHandlerInterface;
 | 
					 | 
				
			||||||
use Lean\Api\{Factory\DebugFormFactoryInterface, Form, Entity};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class CORS implements MiddlewareInterface {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler) : ResponseInterface
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        var_dump($request->getMethod() );
 | 
					 | 
				
			||||||
        if ($request->getMethod() === "option") {
 | 
					 | 
				
			||||||
            die("an option :)");
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return $handler->handle($request);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -5,27 +5,14 @@ namespace Lean\Api;
 | 
				
			|||||||
use Lean\Factory\HttpFactory;
 | 
					use Lean\Factory\HttpFactory;
 | 
				
			||||||
use Notes\ObjectReflection;
 | 
					use Notes\ObjectReflection;
 | 
				
			||||||
use Notes\Route\Attribute\Method\Route;
 | 
					use Notes\Route\Attribute\Method\Route;
 | 
				
			||||||
use Notes\Security\SecurityHandler;
 | 
					 | 
				
			||||||
use Picea\Extension\UrlExtension;
 | 
					use Picea\Extension\UrlExtension;
 | 
				
			||||||
use Psr\Container\ContainerInterface;
 | 
					 | 
				
			||||||
use Taxus\Taxus;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
class RouteDescriptor
 | 
					class RouteDescriptor
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    protected SecurityHandler $securityHandler;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    protected Taxus $taxus;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public function __construct(
 | 
					    public function __construct(
 | 
				
			||||||
        public object $controller,
 | 
					        public object $controller,
 | 
				
			||||||
        protected UrlExtension $urlExtension,
 | 
					        protected UrlExtension $urlExtension,
 | 
				
			||||||
        ContainerInterface $container
 | 
					    ) {}
 | 
				
			||||||
    ) {
 | 
					 | 
				
			||||||
        if ($container->has(SecurityHandler::class) && $container->has(Taxus::class)) {
 | 
					 | 
				
			||||||
            $this->securityHandler = $container->get(SecurityHandler::class);
 | 
					 | 
				
			||||||
            $this->taxus = $container->get(Taxus::class);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function getRoutes() : array
 | 
					    public function getRoutes() : array
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
@ -50,9 +37,7 @@ class RouteDescriptor
 | 
				
			|||||||
                    'path' => $base.$path,
 | 
					                    'path' => $base.$path,
 | 
				
			||||||
                    'cleaned' => $cleaned,
 | 
					                    'cleaned' => $cleaned,
 | 
				
			||||||
                    'description'=> $route->description,
 | 
					                    'description'=> $route->description,
 | 
				
			||||||
                    #'methods' =>implode(', ', (array)$route->method),
 | 
					                    'methods' => $route->method,
 | 
				
			||||||
                    'methods' => (array) $route->method,
 | 
					 | 
				
			||||||
                    'privileges' => $this->getPrivilegeFromRoute($method->name),
 | 
					 | 
				
			||||||
                ];
 | 
					                ];
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -72,32 +57,4 @@ class RouteDescriptor
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        return implode('/', $paths);
 | 
					        return implode('/', $paths);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * @param string $method    Which method are we inspecting
 | 
					 | 
				
			||||||
     * @return false|array|null Returns NULL when securityHandler is undefined, FALSE when no security applies for this method and else an array of ['admin' => [ 'status' => true, 'description' => "' ], ...].
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    protected function getPrivilegeFromRoute(string $method) : null|false|array
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        if ( isset($this->securityHandler) ){
 | 
					 | 
				
			||||||
            $list = [];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if ( $this->securityHandler->isLocked($this->controller::class, $method) ) {
 | 
					 | 
				
			||||||
                foreach($this->taxus->list as $name => $definition) {
 | 
					 | 
				
			||||||
                    if ($definition[0]->testableArguments !== null) {
 | 
					 | 
				
			||||||
                        if ( $this->securityHandler->hasGrantPermission($this->controller::class, $method, ...$definition[0]->testableArguments) ) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            else {
 | 
					 | 
				
			||||||
                return false;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            return $list;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return false;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -1,21 +1,20 @@
 | 
				
			|||||||
{% language.set "lean.api.descriptor.entity" %}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
{% function yesOrNo(bool $toggle) : void %}
 | 
					{% function yesOrNo(bool $toggle) : void %}
 | 
				
			||||||
    <span style="color: {{ $toggle ? 'green' : '#ac1b1b' }}">{{ $toggle ? 'oui' : 'non' }}</span>
 | 
					    <span style="color: {{ $toggle ? 'green' : '#ac1b1b' }}">{{ $toggle ? 'oui' : 'non' }}</span>
 | 
				
			||||||
{% endfunction %}
 | 
					{% endfunction %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{% function length(int|null|string $length): void %}
 | 
					{% function length(int|null $length): void %}
 | 
				
			||||||
    <span style="color:{{ $length ? 'black' : 'gray' }}">{{ $length ?? "non-défini" }}</span>
 | 
					    <span style="color:{{ $length ? 'black' : 'gray' }}">{{ $length ?? "non-défini" }}</span>
 | 
				
			||||||
{% endfunction %}
 | 
					{% endfunction %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<div class="entities">
 | 
					<div class="entities">
 | 
				
			||||||
    {% foreach $entities as $name => $entity %}
 | 
					    {% foreach $entities as $name => $entity %}
 | 
				
			||||||
        <div class="entity-wrapper" style="padding-left: 15px;border-left: 3px solid #eaa1af;">
 | 
					        <div class="entity-wrapper" style="padding-left: 15px;border-left: 3px solid #eaa1af;">
 | 
				
			||||||
            <h4 class='entity-name' title="{{ $name }}">{{ $entity['className'] }}</h4>
 | 
					            <h4 class='entity-name'>{{ $name }}</h4>
 | 
				
			||||||
            <div class='description'>{{ $entity['description'] }}</div>
 | 
					            <div class='description'>{{ $entity['description'] }}</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            <hr style="margin-top:15px">
 | 
					            <hr style="margin-top:15px">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <h5>Champs</h5>
 | 
				
			||||||
            <ol class='fields'>
 | 
					            <ol class='fields'>
 | 
				
			||||||
                {% foreach $entity['fields'] as $field %}
 | 
					                {% foreach $entity['fields'] as $field %}
 | 
				
			||||||
                    <li class="odd-even">
 | 
					                    <li class="odd-even">
 | 
				
			||||||
@ -36,36 +35,31 @@
 | 
				
			|||||||
            </ol>
 | 
					            </ol>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        {% if $entity['searchRequestFields'] %}
 | 
					        <div class="search-request-wrapper">
 | 
				
			||||||
            <div class="search-request-wrapper">
 | 
					            <h4 class='search-request-name'>{{ $name }}::searchRequest()</h4>
 | 
				
			||||||
                <h4 class='search-request-name' title="{{ $name }}">{{ $entity['className'] }}::searchRequest()</h4>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                {% if $entity['searchRequestDescription'] %}
 | 
					            <h5>Requêtes</h5>
 | 
				
			||||||
                    <div class='description' style="margin-bottom:10px">{{ $entity['searchRequestDescription'] }}</div>
 | 
					            <div class='description' style="margin-bottom:10px">{{ $entity['searchRequestDescription'] }}</div>
 | 
				
			||||||
                {% endif %}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                <ol class='requests'>
 | 
					            <ol class='requests'>
 | 
				
			||||||
                    {% foreach $entity['searchRequestFields'] as $field %}
 | 
					                {% foreach $entity['searchRequestFields'] as $field %}
 | 
				
			||||||
                        <li class="odd-even">
 | 
					                    <li class="odd-even">
 | 
				
			||||||
                            <div class="title">
 | 
					                        <div class="title">
 | 
				
			||||||
                                <div><strong style="font-family:monospace">{{ $field['name'] }}</strong> <span style='margin-left:15px'>{{ $field['description'] }}</span></div>
 | 
					                            <div><strong style="font-family:monospace">{{ $field['name'] }}</strong> <span style='margin-left:15px'>{{ $field['description'] }}</span></div>
 | 
				
			||||||
                            </div>
 | 
					                        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            <div class="field-desc" style="margin-top:10px;;background:#fff;padding:5px;font-size:0.9em">
 | 
					                        <div class="field-desc" style="margin-top:10px;;background:#fff;padding:5px;font-size:0.9em">
 | 
				
			||||||
                                <div><u>Paramètre de requête (GET)</u> : {{ $field['parameter'] }}</div>
 | 
					                            <div><u>Paramètre de requête (GET)</u> : {{ $field['parameter'] }}</div>
 | 
				
			||||||
                                <div><u>Attribut</u> : {{ $field['tag'] }}</div>
 | 
					                            <div><u>Attribut</u> : {{ $field['tag'] }}</div>
 | 
				
			||||||
                                <div><u>Type(s)</u> : {{ $field['type'] }}</div>
 | 
					                            <div><u>Type(s)</u> : {{ $field['type'] }}</div>
 | 
				
			||||||
                                <div><u>Nullable</u> : {{ yesOrNo($field['allowNulls']) }}</div>
 | 
					                            <div><u>Nullable</u> : {{ yesOrNo($field['allowNulls']) }}</div>
 | 
				
			||||||
                                {% if $field['default'] !== "" %}
 | 
					                            {% if $field['default'] !== "" %}
 | 
				
			||||||
                                    <div><u>Valeur par défault</u> : {{ $this->displayValue($field['default']) }}</div>
 | 
					                                <div><u>Valeur par défault</u> : {{ $this->displayValue($field['default']) }}</div>
 | 
				
			||||||
                                {% endif %}
 | 
					                            {% endif %}
 | 
				
			||||||
                            </div>
 | 
					                        </div>
 | 
				
			||||||
                        </li>
 | 
					                    </li>
 | 
				
			||||||
                    {% endforeach %}
 | 
					                {% endforeach %}
 | 
				
			||||||
                </ol>
 | 
					            </ol>
 | 
				
			||||||
            </div>
 | 
					        </div>
 | 
				
			||||||
        {% endif %}
 | 
					 | 
				
			||||||
    {% or %}
 | 
					 | 
				
			||||||
        <i style="color:#585858; padding:0 12px">{% _ "none" %}</i>
 | 
					 | 
				
			||||||
    {% endforeach %}
 | 
					    {% endforeach %}
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
@ -1,15 +1,11 @@
 | 
				
			|||||||
{% language.set "lean.api.descriptor.form" %}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
{% function yesOrNo(bool $toggle) : void %}
 | 
					{% function yesOrNo(bool $toggle) : void %}
 | 
				
			||||||
    <span style="color: {{ $toggle ? 'green' : '#ac1b1b' }}">{{ $toggle ? 'oui' : 'non' }}</span>
 | 
					    <span style="color: {{ $toggle ? 'green' : '#ac1b1b' }}">{{ $toggle ? 'oui' : 'non' }}</span>
 | 
				
			||||||
{% endfunction %}
 | 
					{% endfunction %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<div class="forms">
 | 
					<div class="forms">
 | 
				
			||||||
    {% foreach $forms as $name => $form %}
 | 
					    {% foreach $forms as $name => $form %}
 | 
				
			||||||
        <div class="single-form" style="padding-left:15px;border-left: 3px solid #9ccce6;" data-form="{% json.html $form %}">
 | 
					        <div class="single-form" style="padding-left:15px;border-left: 3px solid #9ccce6;">
 | 
				
			||||||
            <h4 class='form-name'>
 | 
					            <h4 class='form-name'>{{ $name }}</h4>
 | 
				
			||||||
                <span title="{{ $name }}">{{ $form['className'] }}</span>
 | 
					 | 
				
			||||||
            </h4>
 | 
					 | 
				
			||||||
            <div class='description'>{{ $form['description'] }}</div>
 | 
					            <div class='description'>{{ $form['description'] }}</div>
 | 
				
			||||||
            <hr style="margin-top:15px">
 | 
					            <hr style="margin-top:15px">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -27,30 +23,16 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
                        <div class="field-desc" style="margin-top:10px;;background:#fff;padding:5px;font-size:0.9em">
 | 
					                        <div class="field-desc" style="margin-top:10px;;background:#fff;padding:5px;font-size:0.9em">
 | 
				
			||||||
                            <div><u>Variable POST / champ JSON</u> : {{ $field['name'] }}</div>
 | 
					                            <div><u>Variable POST / champ JSON</u> : {{ $field['name'] }}</div>
 | 
				
			||||||
                            <div><u>Type(s)</u> : {{ implode(' | ', array_map(fn($e) => $e->type, $field['type'])) }}</div>
 | 
					                            <div><u>Type(s)</u> : {{ $field['type'] }}</div>
 | 
				
			||||||
                            <div><u>Nullable</u> : {{ yesOrNo($field['allowNulls']) }}</div>
 | 
					                            <div><u>Nullable</u> : {{ yesOrNo($field['allowNulls']) }}</div>
 | 
				
			||||||
                            {% if $field['regexPattern'] !== null %}
 | 
					                            <div><u>Pattern regex</u> : {{ $field['regexPattern'] }}</div>
 | 
				
			||||||
                                <div><u>Pattern regex</u> : {{ $field['regexPattern'] }}</div>
 | 
					                            <div><u>Taille min.</u> : {{ $field['minLength'] }}</div>
 | 
				
			||||||
                            {% endif %}
 | 
					                            <div><u>Taille max.</u> : {{ $field['maxLength'] }}</div>
 | 
				
			||||||
                            {% if $field['minLength'] !== null %}
 | 
					                            <div><u>Exemple</u> : {{ $field['example'] }}</div>
 | 
				
			||||||
                                <div><u>Taille min.</u> : {{ $field['minLength'] }}</div>
 | 
					 | 
				
			||||||
                            {% endif %}
 | 
					 | 
				
			||||||
                            {% if $field['maxLength'] !== null %}
 | 
					 | 
				
			||||||
                                <div><u>Taille max.</u> : {{ $field['maxLength'] }}</div>
 | 
					 | 
				
			||||||
                            {% endif %}
 | 
					 | 
				
			||||||
                            {% if $field['example'] !== null || $field['values'] %}
 | 
					 | 
				
			||||||
                                <div><u>Exemple</u> : {{ $field['example'] }}</div>
 | 
					 | 
				
			||||||
                            {% endif %}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                            {% if $field['values'] %}
 | 
					 | 
				
			||||||
                                <div><u>Valeurs possibles</u> : [ <u>{{= implode('</u>, <u>', $field['values']) }}</u> ]</div>
 | 
					 | 
				
			||||||
                            {% endif %}
 | 
					 | 
				
			||||||
                        </div>
 | 
					                        </div>
 | 
				
			||||||
                    </li>
 | 
					                    </li>
 | 
				
			||||||
                {% endforeach %}
 | 
					                {% endforeach %}
 | 
				
			||||||
            </ol>
 | 
					            </ol>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
    {% or %}
 | 
					 | 
				
			||||||
        <i style="color:#585858; padding:0 12px">{% _ "none" %}</i>
 | 
					 | 
				
			||||||
    {% endforeach %}
 | 
					    {% endforeach %}
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
@ -1,245 +0,0 @@
 | 
				
			|||||||
{% use Ulmus\Api\Common\MethodEnum %}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
{% language.set "lean.api.request.debugger" %}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<div id="request-debugger" class="hide">
 | 
					 | 
				
			||||||
    <div class="request-head">
 | 
					 | 
				
			||||||
        <div class="method" style="">
 | 
					 | 
				
			||||||
            {% ui.select "method", MethodEnum::generateArray(), post('method') %}
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        <div class="url" style="flex-grow: 1;">
 | 
					 | 
				
			||||||
            {% ui:text "url" %}
 | 
					 | 
				
			||||||
            {% ui:text "token", $this->session->jwt %}
 | 
					 | 
				
			||||||
            <button class="request-btn">Envoyer</button>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
    </div>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    <div class="request-content">
 | 
					 | 
				
			||||||
        <div id="request" style="min-height: 150px; width:100%; border:1px solid #ededed;">{}</div>
 | 
					 | 
				
			||||||
    </div>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    <div class="request-response hide">
 | 
					 | 
				
			||||||
        <hr>
 | 
					 | 
				
			||||||
        <pre id="response" class="code" ace-theme="ace/theme/cloud9_day"></pre>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        <div class="response-head">
 | 
					 | 
				
			||||||
            <span class="response-code"></span>
 | 
					 | 
				
			||||||
            <span class="response-message"></span>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
    </div>
 | 
					 | 
				
			||||||
</div>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<style>
 | 
					 | 
				
			||||||
    .request-head {display:flex;padding-top: 4px;border:1px solid #e1e1e1;border-bottom:0}
 | 
					 | 
				
			||||||
    .request-head .method {width: 90px;text-align: center;line-height: 34px;font-weight: bold;}
 | 
					 | 
				
			||||||
    .request-head .method select {background:none;border:0;font-size: inherit;text-align: center;color: inherit;font-weight: bold;}
 | 
					 | 
				
			||||||
    .request-head .url input {border:0;color: #6f6f6f;background: #f9f9f9;font-size: 80%;font-weight: bold;}
 | 
					 | 
				
			||||||
    .request-head .url [name="url"] {width: calc(65% - 80px);}
 | 
					 | 
				
			||||||
    .request-head .url [name="token"] {width:calc(35% - 10px);font-size:60%}
 | 
					 | 
				
			||||||
    .request-head .url button {font-size: 80%;width: 80px;border-radius:0;border: 1px solid #ccc;height:26px;padding: 0;background:#f9f9f9;color: #6f6f6f;cursor: pointer;}
 | 
					 | 
				
			||||||
    .request-head .url button:active {filter:contrast(85%);}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    .response-head {display: flex;border:1px solid #9f9f9f;margin-bottom: 5px;}
 | 
					 | 
				
			||||||
    .response-head .response-code {background:#dfdfdf;padding:0 5px;font-weight: bold;line-height: 29px;font-size: 80%;}
 | 
					 | 
				
			||||||
    .response-head .response-message {padding:0 10px;background:#fbfbfb;line-height: 30px;font-size: 80%;}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    #response {max-height: 66vh;}
 | 
					 | 
				
			||||||
</style>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<script src="{% asset 'static/ace/src-noconflict/ace.js' %}" type="text/javascript" charset="utf-8"></script>
 | 
					 | 
				
			||||||
<script src="{% asset 'static/ace/src-noconflict/ext-static_highlight.js' %}" type="text/javascript" charset="utf-8"></script>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<script>
 | 
					 | 
				
			||||||
    let requestDebugger = document.getElementById('request-debugger'),
 | 
					 | 
				
			||||||
        requestHead = requestDebugger.querySelector(".request-head"),
 | 
					 | 
				
			||||||
        requestContent = requestDebugger.querySelector(".request-content"),
 | 
					 | 
				
			||||||
        responseHead = requestDebugger.querySelector(".response-head"),
 | 
					 | 
				
			||||||
        responseResponse = requestDebugger.querySelector(".request-response"),
 | 
					 | 
				
			||||||
        method = requestHead.querySelector(".method"),
 | 
					 | 
				
			||||||
        input = requestHead.querySelector("[name='url']"),
 | 
					 | 
				
			||||||
        token = requestHead.querySelector("[name='token']"),
 | 
					 | 
				
			||||||
        button = requestHead.querySelector(".request-btn");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Editor
 | 
					 | 
				
			||||||
    let editor = ace.edit("request");
 | 
					 | 
				
			||||||
    editor.setTheme("ace/theme/cloud9_day");
 | 
					 | 
				
			||||||
    editor.session.setMode("ace/mode/json");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Code highlighter
 | 
					 | 
				
			||||||
    let highlight = ace.require("ace/ext/static_highlight"),
 | 
					 | 
				
			||||||
        dom = ace.require("ace/lib/dom"),
 | 
					 | 
				
			||||||
        responseEditorElement = responseResponse.querySelector('#response');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    input.addEventListener('keydown', evt => evt.keyCode === 13 ? button.click() : null);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    document.addEventListener("DOMContentLoaded", (evt) => {
 | 
					 | 
				
			||||||
        document.querySelectorAll(".form-name").forEach(elem => {
 | 
					 | 
				
			||||||
            elem.insertAdjacentHTML('beforeend', '<a href="javascript:void(0)" class="btn debug">DEBUG</a>');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            let formData = JSON.parse(elem.closest('.single-form').getAttribute('data-form'));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            elem.querySelector(".btn.debug").addEventListener("click", (btn) => {
 | 
					 | 
				
			||||||
                requestDebugger.classList.toggle('hide', false);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                let json = {};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                formData.fields.forEach((field) => {
 | 
					 | 
				
			||||||
                    json[field.name] = field.allowNulls ? null : "";
 | 
					 | 
				
			||||||
                });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                editor.setValue(JSON.stringify(json,null,2), -1);
 | 
					 | 
				
			||||||
            });
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        document.querySelectorAll("li[class*='method-']").forEach( (url) => {
 | 
					 | 
				
			||||||
            url.addEventListener("click", (evt) => {
 | 
					 | 
				
			||||||
                evt.preventDefault();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                let routeMethod = url.querySelector('.route-method');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                method.style.color = getComputedStyle(routeMethod).getPropertyValue('background-color');
 | 
					 | 
				
			||||||
                method.querySelector('select').value = routeMethod.innerText;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                input.value = url.querySelector('.route-link a').getAttribute('href');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                document.getElementById('request-debugger').classList.toggle('hide', false);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                replaceUrlVariableUsingData();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                input.focus();
 | 
					 | 
				
			||||||
            });
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        let aceMode;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        button.addEventListener("click", (evt) => {
 | 
					 | 
				
			||||||
            let requestMethod = method.querySelector('select').value;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (requestMethod === 'DELETE' && ! confirm("Attention ! Vous allez lancer une procédure de suppression de données.\n\nContinuer ?")) {
 | 
					 | 
				
			||||||
                return;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            launchRequest(requestMethod, input.value, editor.getValue())
 | 
					 | 
				
			||||||
            .then((response) => {
 | 
					 | 
				
			||||||
                responseHead.querySelector('.response-code').innerText = response.status;
 | 
					 | 
				
			||||||
                responseHead.querySelector('.response-message').innerText = response.statusText;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                aceMode = parseContentType(response);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                return response.text();
 | 
					 | 
				
			||||||
            })
 | 
					 | 
				
			||||||
            .then(body => {
 | 
					 | 
				
			||||||
                if (aceMode === "json") {
 | 
					 | 
				
			||||||
                    body = JSON.stringify(JSON.parse(body), null, 2);
 | 
					 | 
				
			||||||
                    responseEditorElement.innerHTML = body;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                else {
 | 
					 | 
				
			||||||
                    responseEditorElement.innerText = body;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                formatResponse("ace/mode/" + aceMode);
 | 
					 | 
				
			||||||
            });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            responseResponse.classList.toggle('hide', false);
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        let selectRoute = getQueryVariable("debug.route"),
 | 
					 | 
				
			||||||
            presetData = getQueryVariable("debug.data");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if ( selectRoute ) {
 | 
					 | 
				
			||||||
            if (presetData) {
 | 
					 | 
				
			||||||
                editor.setValue(presetData);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            document.querySelector(`[data-name="${selectRoute}"]`).click();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    async function launchRequest(method = "POST", url = "", body = "{}") {
 | 
					 | 
				
			||||||
        method = method.toUpperCase();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        let responseData = {
 | 
					 | 
				
			||||||
            method: method,
 | 
					 | 
				
			||||||
            mode: "cors",
 | 
					 | 
				
			||||||
            cache: "no-cache",
 | 
					 | 
				
			||||||
            credentials: "omit",
 | 
					 | 
				
			||||||
            headers: {
 | 
					 | 
				
			||||||
                "Content-Type": "application/json",
 | 
					 | 
				
			||||||
                'Authorization': `Bearer ${token.value}`
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            redirect: "follow",
 | 
					 | 
				
			||||||
            referrerPolicy: "no-referrer"
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if ( [ "HEAD", "GET" ].indexOf(method) === -1 ) {
 | 
					 | 
				
			||||||
            responseData.body = body;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return await fetch(url, responseData);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    function formatResponse(mode) {
 | 
					 | 
				
			||||||
        highlight(responseEditorElement, {
 | 
					 | 
				
			||||||
            mode: mode,
 | 
					 | 
				
			||||||
            theme: responseEditorElement.getAttribute("ace-theme"),
 | 
					 | 
				
			||||||
            firstLineNumber: 1,
 | 
					 | 
				
			||||||
            showGutter: responseEditorElement.getAttribute("ace-gutter"),
 | 
					 | 
				
			||||||
            trim: true
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    function parseContentType(response) {
 | 
					 | 
				
			||||||
        let type = response.headers.get('content-type').toLowerCase();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if ( type.indexOf('text/html') !== -1 ) {
 | 
					 | 
				
			||||||
            return "html";
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        else if ( type.indexOf('text/css') !== -1 ) {
 | 
					 | 
				
			||||||
            return "css";
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        else if ( type.indexOf('text/csv') !== -1 ) {
 | 
					 | 
				
			||||||
            return "csv";
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        else if ( type.indexOf('text/xml') !== -1 ) {
 | 
					 | 
				
			||||||
            return "xml";
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        else if ( type.indexOf('text/plain') !== -1 ) {
 | 
					 | 
				
			||||||
            return "text";
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        else if ( type.indexOf('application/javascript') !== -1 ) {
 | 
					 | 
				
			||||||
            return "javascript";
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        else if ( type.indexOf('application/json') !== -1 || type.indexOf('application/ld+json') !== -1 ) {
 | 
					 | 
				
			||||||
            return "json";
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    function getQueryVariable(variable) {
 | 
					 | 
				
			||||||
        retval = false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        window.location.search.substring(1).split("&").forEach(vars => {
 | 
					 | 
				
			||||||
            var pair = vars.split("=");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (pair.length === 2 && pair[0] === variable) {
 | 
					 | 
				
			||||||
                return retval = decodeURI(pair[1]);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return retval;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    function replaceUrlVariableUsingData() {
 | 
					 | 
				
			||||||
        try {
 | 
					 | 
				
			||||||
            let vars = input.value.match(/[^{}]+(?=})/g),
 | 
					 | 
				
			||||||
                body = JSON.parse(editor.getValue());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            vars.forEach(v => {
 | 
					 | 
				
			||||||
                if (body[v]) {
 | 
					 | 
				
			||||||
                    input.value = input.value.replace("{" + v + "}", body[v]);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            })
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        catch(e) {}
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
</script>
 | 
					 | 
				
			||||||
@ -1,35 +1,31 @@
 | 
				
			|||||||
{% language.set "lean.api.descriptor.route" %}
 | 
					{% function printMethods(array|string $methods) %}
 | 
				
			||||||
 | 
					    {% foreach (array) $methods as $method %}
 | 
				
			||||||
 | 
					        <a style="color:#ac1b1b" href="#" class="method-item" data-method="{{ $method }}">{{ $method }}</a>
 | 
				
			||||||
 | 
					    {% endforeach %}
 | 
				
			||||||
 | 
					{% endfunction %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<ul class="routes-wrapper">
 | 
					<ul>
 | 
				
			||||||
    {% foreach $routes as $route %}
 | 
					    {% foreach $routes as $route %}
 | 
				
			||||||
        {% foreach $route['methods'] as $method %}
 | 
					        <li>
 | 
				
			||||||
            <li class="method-{{ strtolower($method) }}" data-name="{{ $route['name'] }}">
 | 
					            <span><a href="{{ $route['route'] }}" title="{{ $route['path'] }}" style='font-family:monospace;font-size:.85em'>{{ $route['cleaned'] }}</a> - {{= $route['description'] }}</span>
 | 
				
			||||||
                <span class="route-method">
 | 
					            <span>{{ printMethods($route['methods']) }}</span>
 | 
				
			||||||
                    <span class="method-name">{{ strtoupper($method) }}</span>
 | 
					            <small style="color:#374300">{{ $route['name'] }}</small>
 | 
				
			||||||
                </span>
 | 
					        </li>
 | 
				
			||||||
 | 
					 | 
				
			||||||
                <span class="route-link">
 | 
					 | 
				
			||||||
                    <a href="{{ $route['route'] }}" title="{{ $route['path'] }}">{{ $route['cleaned'] }}</a>
 | 
					 | 
				
			||||||
                    <span>-</span>
 | 
					 | 
				
			||||||
                    <span>{{= $route['description'] }}</span>
 | 
					 | 
				
			||||||
                </span>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                <small class="route-name">
 | 
					 | 
				
			||||||
                    <span>{{ $route['name'] }}</span>
 | 
					 | 
				
			||||||
                    <br>
 | 
					 | 
				
			||||||
                    <span class="permissions">
 | 
					 | 
				
			||||||
                        {% foreach ['admin', 'school' ] as $privilege %}
 | 
					 | 
				
			||||||
                            <u class="privilege">{{ $privilege }}</u>
 | 
					 | 
				
			||||||
                        {% endforeach %}
 | 
					 | 
				
			||||||
                    </span>
 | 
					 | 
				
			||||||
                </small>
 | 
					 | 
				
			||||||
            </li>
 | 
					 | 
				
			||||||
        {% or %}
 | 
					 | 
				
			||||||
            <i style="color:#585858; padding:0 12px">{% _ "none" %}</i>
 | 
					 | 
				
			||||||
        {% endforeach %}
 | 
					 | 
				
			||||||
    {% endforeach %}
 | 
					    {% endforeach %}
 | 
				
			||||||
</ul>
 | 
					</ul>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<style>
 | 
					<div class="api-console">
 | 
				
			||||||
    .permissions {color:#888}
 | 
					    <label>Corps / body (JSON)</label>
 | 
				
			||||||
</style>
 | 
					    <ui-textarea name="breeder_description">
 | 
				
			||||||
 | 
					        <div slot="input">
 | 
				
			||||||
 | 
					            {% ui:textarea "body" %}
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					    </ui-textarea>
 | 
				
			||||||
 | 
					    <div></div>
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script type="text/javascript">
 | 
				
			||||||
 | 
					    document.querySelectorAll('[data-method]').forEach((e) => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
@ -16,69 +16,33 @@
 | 
				
			|||||||
            <meta name="theme-color" content="#ffffff">
 | 
					            <meta name="theme-color" content="#ffffff">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            <style>
 | 
					            <style>
 | 
				
			||||||
                *, *:before, *:after {box-sizing: border-box;}
 | 
					 | 
				
			||||||
                a{color:#e44a00}h3{background:#e1e1e1;padding:6px 12px}ul{background:#e9e9fd;padding-top:20px;padding-bottom:20px;border:1px solid #e3e3ec}ul li + li{margin-top:8px}li > em{font-size:0.75rem;color:gray}body{font-family:Helvetica, 'Helvetica Neuve', Arial, Tahoma, sans-serif;font-size:17px;color:#333}h1,h2,h3,h4,h5,h6{color:#222;margin:0 0 20px}dl,ol,p,pre,table,ul{margin:0 0 20px}h1,h2,h3{line-height:1.1}h1{font-size:20px;text-align:right;color:#387eea;font-weight:bold}h2{color:#393939}h3,h4,h5,h6{color:#494949}h3{display:flex}h3 > code{margin-right:5px;color:#b52dac}h3 > strong{margin-left:auto}a{color:#39c;font-weight:400;text-decoration:none}a small{font-size:11px;color:#777;margin-top:-0.6em;display:block}.wrapper{width:860px;margin:0 auto}blockquote{border-left:1px solid #e5e5e5;margin:0;padding:0 0 0 20px;font-style:italic}code,pre{font-size:12px}pre{padding:8px 15px;background:#f8f8f8;border-radius:5px;border:1px solid #e5e5e5;overflow-x:auto}table{width:100%;border-collapse:collapse}td,th{text-align:left;padding:5px 10px;border-bottom:1px solid #e5e5e5}dt{color:#444;font-weight:700}th{color:#444}img{max-width:100%}header{width:270px;float:left;position:fixed}header ul{list-style:none;height:40px;padding:0;background:#eee;background:-moz-linear-gradient(top, #f8f8f8 0%, #dddddd 100%);background:-webkit-gradient(linear, left top, left bottom, color-stop(0%,#f8f8f8), color-stop(100%,#dddddd));background:-webkit-linear-gradient(top, #f8f8f8 0%,#dddddd 100%);background:-o-linear-gradient(top, #f8f8f8 0%,#dddddd 100%);background:-ms-linear-gradient(top, #f8f8f8 0%,#dddddd 100%);background:linear-gradient(top, #f8f8f8 0%,#dddddd 100%);border-radius:5px;border:1px solid #d2d2d2;box-shadow:inset #fff 0 1px 0, inset rgba(0,0,0,0.03) 0 -1px 0;width:270px}header li{width:89px;float:left;border-right:1px solid #d2d2d2;height:40px}header ul a{line-height:1;font-size:11px;color:#999;display:block;text-align:center;padding-top:6px;height:40px}strong{color:#222;font-weight:700}header ul li + li{width:88px;border-left:1px solid #fff}header ul li + li + li{border-right:none;width:89px}header ul a strong{font-size:14px;display:block;color:#222}section{width:500px;float:right;padding-bottom:50px}small{font-size:11px}hr{border:0;background:#e5e5e5;height:1px;margin:0 0 20px}footer{width:270px;float:left;position:fixed;bottom:50px}@media print, screen and (max-width: 960px){div.wrapper{width:auto;margin:0}footer,header,section{float:none;position:static;width:auto}header{padding-right:320px}section{border:1px solid #e5e5e5;border-width:1px 0;padding:20px 0;margin:0 0 20px}header a small{display:inline}header ul{position:absolute;right:50px;top:52px}}@media print, screen and (max-width: 720px){body{word-wrap:break-word}header{padding:0}header p.view,header ul{position:static}code,pre{word-wrap:normal}}@media print, screen and (max-width: 480px){body{padding:15px}header ul{display:none}}@media print{body{padding:0.4in;font-size:12pt;color:#444}}#wrapper{margin-left:auto;margin-right:auto;background-color:white}.ca-menu{list-style:none;padding:0;margin:20px auto}#navi{padding-top:15px;padding-right:15px;float:right;width:420px}#title{padding-left:15px;width:460px;float:left}div.clear{clear:both}h2{font-size:2em}h3{font-size:1.5em}h4{font-size:1.2em}h5{font-size:1em;font-weight:bold}h6{font-size:1em;font-weight:bold}h1,h2,h3,h4,h5,h6{font-weight:normal;line-height:2.5rem;margin:1rem 0}.post p{max-width:580px}ol.list,ul.list{padding-left:3.333em;max-width:580px}.post h2{border-bottom:1px solid #EDEDED}h1:nth-child(1),h2:nth-child(1),h3:nth-child(1),h4:nth-child(1),h5:nth-child(1),h6:nth-child(1){margin-top:0}body{padding:1em}#wrapper{padding:1em}@media (min-width: 43.75em){body{padding:2em}#wrapper{padding:2em}}@media (min-width: 62em){body{padding:3em}#wrapper{max-width:740px;padding:3em}}
 | 
					                a{color:#e44a00}h3{background:#e1e1e1;padding:6px 12px}ul{background:#e9e9fd;padding-top:20px;padding-bottom:20px;border:1px solid #e3e3ec}ul li + li{margin-top:8px}li > em{font-size:0.75rem;color:gray}body{font-family:Helvetica, 'Helvetica Neuve', Arial, Tahoma, sans-serif;font-size:17px;color:#333}h1,h2,h3,h4,h5,h6{color:#222;margin:0 0 20px}dl,ol,p,pre,table,ul{margin:0 0 20px}h1,h2,h3{line-height:1.1}h1{font-size:20px;text-align:right;color:#387eea;font-weight:bold}h2{color:#393939}h3,h4,h5,h6{color:#494949}h3{display:flex}h3 > code{margin-right:5px;color:#b52dac}h3 > strong{margin-left:auto}a{color:#39c;font-weight:400;text-decoration:none}a small{font-size:11px;color:#777;margin-top:-0.6em;display:block}.wrapper{width:860px;margin:0 auto}blockquote{border-left:1px solid #e5e5e5;margin:0;padding:0 0 0 20px;font-style:italic}code,pre{font-size:12px}pre{padding:8px 15px;background:#f8f8f8;border-radius:5px;border:1px solid #e5e5e5;overflow-x:auto}table{width:100%;border-collapse:collapse}td,th{text-align:left;padding:5px 10px;border-bottom:1px solid #e5e5e5}dt{color:#444;font-weight:700}th{color:#444}img{max-width:100%}header{width:270px;float:left;position:fixed}header ul{list-style:none;height:40px;padding:0;background:#eee;background:-moz-linear-gradient(top, #f8f8f8 0%, #dddddd 100%);background:-webkit-gradient(linear, left top, left bottom, color-stop(0%,#f8f8f8), color-stop(100%,#dddddd));background:-webkit-linear-gradient(top, #f8f8f8 0%,#dddddd 100%);background:-o-linear-gradient(top, #f8f8f8 0%,#dddddd 100%);background:-ms-linear-gradient(top, #f8f8f8 0%,#dddddd 100%);background:linear-gradient(top, #f8f8f8 0%,#dddddd 100%);border-radius:5px;border:1px solid #d2d2d2;box-shadow:inset #fff 0 1px 0, inset rgba(0,0,0,0.03) 0 -1px 0;width:270px}header li{width:89px;float:left;border-right:1px solid #d2d2d2;height:40px}header ul a{line-height:1;font-size:11px;color:#999;display:block;text-align:center;padding-top:6px;height:40px}strong{color:#222;font-weight:700}header ul li + li{width:88px;border-left:1px solid #fff}header ul li + li + li{border-right:none;width:89px}header ul a strong{font-size:14px;display:block;color:#222}section{width:500px;float:right;padding-bottom:50px}small{font-size:11px}hr{border:0;background:#e5e5e5;height:1px;margin:0 0 20px}footer{width:270px;float:left;position:fixed;bottom:50px}@media print, screen and (max-width: 960px){div.wrapper{width:auto;margin:0}footer,header,section{float:none;position:static;width:auto}header{padding-right:320px}section{border:1px solid #e5e5e5;border-width:1px 0;padding:20px 0;margin:0 0 20px}header a small{display:inline}header ul{position:absolute;right:50px;top:52px}}@media print, screen and (max-width: 720px){body{word-wrap:break-word}header{padding:0}header p.view,header ul{position:static}code,pre{word-wrap:normal}}@media print, screen and (max-width: 480px){body{padding:15px}header ul{display:none}}@media print{body{padding:0.4in;font-size:12pt;color:#444}}#wrapper{margin-left:auto;margin-right:auto;background-color:white}.ca-menu{list-style:none;padding:0;margin:20px auto}#navi{padding-top:15px;padding-right:15px;float:right;width:420px}#title{padding-left:15px;width:460px;float:left}div.clear{clear:both}h2{font-size:2em}h3{font-size:1.5em}h4{font-size:1.2em}h5{font-size:1em;font-weight:bold}h6{font-size:1em;font-weight:bold}h1,h2,h3,h4,h5,h6{font-weight:normal;line-height:2.5rem;margin:1rem 0}.post p{max-width:580px}ol.list,ul.list{padding-left:3.333em;max-width:580px}.post h2{border-bottom:1px solid #EDEDED}h1:nth-child(1),h2:nth-child(1),h3:nth-child(1),h4:nth-child(1),h5:nth-child(1),h6:nth-child(1){margin-top:0}body{padding:1em}#wrapper{padding:1em}@media (min-width: 43.75em){body{padding:2em}#wrapper{padding:2em}}@media (min-width: 62em){body{padding:3em}#wrapper{max-width:740px;padding:3em}}
 | 
				
			||||||
                ol{background: #eff4f2;padding-top:20px;padding-bottom:20px;border:1px solid #e3e3ec}
 | 
					                ol{background: #eff4f2;padding-top:20px;padding-bottom:20px;border:1px solid #e3e3ec}
 | 
				
			||||||
                h4{background:#e0f7ed;padding:6px 12px; font-weight: bold!important;font-size:100%;margin-top:0}
 | 
					                h4{background:#e0f7ed;padding:6px 12px; font-weight: bold!important;font-size:100%;margin-top:0}
 | 
				
			||||||
                h5{text-decoration: underline}
 | 
					                h5{text-decoration: underline}
 | 
				
			||||||
                h3 {display: flex;align-items: center;padding: 0 15px 0 15px;font-variant: small-caps;border-bottom: 5px solid #ccc;line-height: 60px;}
 | 
					                h3 {display: flex;align-items: center;height: 60px;padding: 0 15px 0 15px;font-variant: small-caps;}
 | 
				
			||||||
                li.odd-even{border-top:1px solid #ccc;margin:10px 0;padding:15px 15px 10px 5px}
 | 
					                li.odd-even{border-top:1px solid #ccc;margin:10px 0;padding:15px 15px 10px 5px}
 | 
				
			||||||
                li.odd-even:first-child{border:0}
 | 
					                li.odd-even:first-child{border:0}
 | 
				
			||||||
                input, button {padding:5px; font-size:1em;margin:0}
 | 
					                input, button {padding:5px; font-size:1em;margin-top:10px}
 | 
				
			||||||
 | 
					 | 
				
			||||||
                .hide {display:none!important}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                ul {background:#f4f4f4; list-style: none; padding-left:20px}
 | 
					                ul {background:#f4f4f4; list-style: none; padding-left:20px}
 | 
				
			||||||
                ul ul {margin: 0;border: 0;padding: 5px 30px;}
 | 
					                ul ul {margin: 0;border: 0;padding: 5px 30px;}
 | 
				
			||||||
 | 
					                ul li + li {margin-top: 12px;}
 | 
				
			||||||
                ul ul > li:before {content:"↳"}
 | 
					                ul ul > li:before {content:"↳"}
 | 
				
			||||||
                ol .title { display: flex;justify-content: space-between;background: #ffffffb2;padding: 9px 5px;border: 1px solid #fff;}
 | 
					                ol .title { display: flex;justify-content: space-between;background: #ffffffb2;padding: 9px 5px;border: 1px solid #fff;}
 | 
				
			||||||
                .field-desc > div {padding:5px;}
 | 
					                .field-desc > div {padding:5px;}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                .api-console {padding:20px 15px;border:1px solid #aeaeae;border-left-width: 5px;background:#ccc}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                .forms ol {background: #ccdef2;}
 | 
					                .forms ol {background: #ccdef2;}
 | 
				
			||||||
                .forms li {border-color: #859aae;}
 | 
					                .forms li {border-color: #859aae;}
 | 
				
			||||||
                .forms .form-name {background: #9cc5e6;display:flex;justify-content: space-between}
 | 
					                .forms .form-name {background: #9cc5e6;color: #284168;font-size:110%}
 | 
				
			||||||
                .forms .form-name span {color: #284168;font-size:110%}
 | 
					 | 
				
			||||||
                .forms .form-name .btn {background:rgba(50,50,50,0.5);padding:0 15px;border: 1px solid rgba(50,50,50,0.8);font-family: 'Déja Vu', 'Courier New', Courier, monospace, serif;font-size: 90%;color: #fff;text-decoration: underline;}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                .routes-wrapper {padding:5px}
 | 
					 | 
				
			||||||
                .routes-wrapper li {display:flex;border: 1px solid #ccc;align-items: stretch;cursor:pointer}
 | 
					 | 
				
			||||||
                .routes-wrapper li:hover {filter: contrast(85%)}
 | 
					 | 
				
			||||||
                .routes-wrapper li + li {margin-top: 5px;}
 | 
					 | 
				
			||||||
                .routes-wrapper .route-method {display:flex;align-items: center; justify-content: center; line-height: 1.8rem;padding:6px 5px 0 5px;min-width:80px;text-align:center;font-weight:bold;color:#fff;}
 | 
					 | 
				
			||||||
                .routes-wrapper .route-link {line-height: 1.8rem;padding:0 10px;display: flex;align-items: center;}
 | 
					 | 
				
			||||||
                .routes-wrapper .route-link span {margin-left: 7px;}
 | 
					 | 
				
			||||||
                .routes-wrapper .route-link a {font-family:monospace;font-size:.85em;white-space: nowrap;}
 | 
					 | 
				
			||||||
                .routes-wrapper .route-name {margin-left:auto;font-weight:bold;min-width: 20%;text-align: right;background:rgba(0, 0, 0, 0.02);line-height: 1.4rem;padding:6px 7px 0 5px;align-content: center;}
 | 
					 | 
				
			||||||
                .routes-wrapper li.method-get {background:#e7eff7;border-color: #bfcfdd;}
 | 
					 | 
				
			||||||
                .routes-wrapper li.method-get .route-method {background:#0f6ab4;}
 | 
					 | 
				
			||||||
                .routes-wrapper li.method-get .route-link a, .routes-wrapper li.method-get .route-name {color: #0f6ab4;}
 | 
					 | 
				
			||||||
                .routes-wrapper li.method-head {background:#f5e8f2;border-color:#ffc0e7;}
 | 
					 | 
				
			||||||
                .routes-wrapper li.method-head .route-method {background:#ca6aa5;}
 | 
					 | 
				
			||||||
                .routes-wrapper li.method-head .route-link a, .routes-wrapper li.method-head .route-name {color: #ca6aa5;}
 | 
					 | 
				
			||||||
                .routes-wrapper li.method-post {background:#e6f5eb;border-color: #ace3c2;}
 | 
					 | 
				
			||||||
                .routes-wrapper li.method-post .route-method {background:#10a44a;}
 | 
					 | 
				
			||||||
                .routes-wrapper li.method-post .route-link a, .routes-wrapper li.method-post .route-name {color: #10a44a;}
 | 
					 | 
				
			||||||
                .routes-wrapper li.method-patch {background:#fce9e3;border-color:#ffd4b3}
 | 
					 | 
				
			||||||
                .routes-wrapper li.method-patch .route-method {background:#f4842f;}
 | 
					 | 
				
			||||||
                .routes-wrapper li.method-patch .route-link a, .routes-wrapper li.method-patch .route-name {color: #f4842f;}
 | 
					 | 
				
			||||||
                .routes-wrapper li.method-option {background:#eaeaea;border-color: #dbdbdb;}
 | 
					 | 
				
			||||||
                .routes-wrapper li.method-option .route-method {background:#a4a4a4;}
 | 
					 | 
				
			||||||
                .routes-wrapper li.method-option .route-link a, .routes-wrapper li.method-option .route-name {color: #717171;}
 | 
					 | 
				
			||||||
                .routes-wrapper li.method-delete {background:#f5e8e8;border-color: #ffadaf;}
 | 
					 | 
				
			||||||
                .routes-wrapper li.method-delete .route-method {background:#d73c41;}
 | 
					 | 
				
			||||||
                .routes-wrapper li.method-delete .route-link a, .routes-wrapper li.method-delete .route-name {color: #d73c41;}
 | 
					 | 
				
			||||||
                .routes-wrapper li.method-put {background:#fff5c2;border-color: #eadd9a;}
 | 
					 | 
				
			||||||
                .routes-wrapper li.method-put .route-method {background:#d7bf3c;}
 | 
					 | 
				
			||||||
                .routes-wrapper li.method-put .route-link a, .routes-wrapper li.method-put .route-name {color: #aa941c;}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                .forms{background: #e8f7ff;padding: 5px;}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                .entities {background: #f0e0e0;padding:5px;}
 | 
					 | 
				
			||||||
                .entity-wrapper .entity-name {background:#eaa1af;color: #682828;font-size:110%}
 | 
					                .entity-wrapper .entity-name {background:#eaa1af;color: #682828;font-size:110%}
 | 
				
			||||||
                .entity-wrapper ol {background: #e3d0d0;}
 | 
					                .entity-wrapper ol {background: #f0ddcd;}
 | 
				
			||||||
                .entity-wrapper li {border-color: #ae8585;}
 | 
					                .entity-wrapper li {border-color: #ae8585;}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                .search-request-name {background: #b6e6ae;color: #395332;font-size:110%}
 | 
					                .search-request-name {background: #b6e6ae;color: #395332;font-size:110%}
 | 
				
			||||||
                .search-request-wrapper {padding: 15px;margin-top:5px;border-left: 3px solid #72886a;background: #eeffe6;}
 | 
					                .search-request-wrapper {padding-left: 15px;border-left: 3px solid #72886a;}
 | 
				
			||||||
                .search-request-wrapper ol {background: #d8f0cd;}
 | 
					                .search-request-wrapper ol {background: #d8f0cd;}
 | 
				
			||||||
                .search-request-wrapper li {border-color: #72886a;}
 | 
					                .search-request-wrapper li {border-color: #72886a;}
 | 
				
			||||||
            </style>
 | 
					            </style>
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user