- Added a new Email defintion (which will soon see it's components changed)
- Added a new post-install script for composer which adds a project skeleton "ready to use". - Error 500 are now handled properly in production; waiting to see if adjustements will be required before adding other code pages.
This commit is contained in:
parent
09b3e47c19
commit
01bb926ca7
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
use function DI\autowire, DI\create, DI\get;
|
||||
|
||||
use TheBugs\Email\EmailConfiguration,
|
||||
TheBugs\Email\MailerInterface,
|
||||
TheBugs\Email\SwiftMailer;
|
||||
|
||||
return [
|
||||
EmailConfiguration::class => function($c) {
|
||||
$email = new EmailConfiguration( EmailConfiguration::AUTH_TYPE_SMTP );
|
||||
$email->smtpHost = getenv('SMTP_HOST');
|
||||
$email->smtpPort = getenv('SMTP_PORT');
|
||||
$email->smtpUsername = getenv('SMTP_USERNAME');
|
||||
$email->smtpPassword = getenv('SMTP_PASSWORD');
|
||||
$email->smtpUseTLS = getenv('SMTP_TLS');
|
||||
$email->toAddress = getenv("TO_EMAIL");
|
||||
$email->fromAddress = getenv("FROM_EMAIL");
|
||||
$email->fromName = getenv("FROM_NAME");
|
||||
return $email;
|
||||
},
|
||||
|
||||
MailerInterface::class => autowire(SwiftMailer::class),
|
||||
];
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"month": {
|
||||
"list": [
|
||||
"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "Décember"
|
||||
],
|
||||
|
||||
"short": [
|
||||
"Jan", "Feb", "Mar", "Apr", "May", "June", "July", "Aug", "Sept", "Oct", "Nov", "Dec"
|
||||
],
|
||||
|
||||
"letter": [
|
||||
"J", "F", "M", "A", "M", "J", "J", "A", "S", "O", "N", "D"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"month": {
|
||||
"list": [
|
||||
"Janvier", "Février", "Mars", "Avril", "Mai", "Juin", "Juillet", "Août", "Septembre", "Octobre", "Novembre", "Décembre"
|
||||
],
|
||||
|
||||
"short": [
|
||||
"Jan", "Fév", "Mars", "Avr", "Mai", "Juin", "Jui", "Août", "Sept", "Oct", "Nov", "Déc"
|
||||
],
|
||||
|
||||
"letter": [
|
||||
"J", "F", "M", "A", "M", "J", "J", "A", "S", "O", "N", "D"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -5,5 +5,12 @@
|
|||
"subtitle": "Vous avez peut-être suivi un lien expiré ou invalide...",
|
||||
"message": "Il semblerait que l'action que vous avez tentez à mener vers une page qui n'existe pas / plus. Une notification a été envoyé au développeur de l'application.",
|
||||
"back": "Revenir à la page précédente"
|
||||
},
|
||||
"500": {
|
||||
"title": "Une erreur semble s'être produite",
|
||||
"page-title": "Une erreur semble s'être produite",
|
||||
"subtitle": "L'action que vous avez tenté d'effectué semble avoir échoué.",
|
||||
"message": "Un message d'erreur a été envoyé au développeur de cette application.",
|
||||
"back": "Revenir à la page précédente"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
APP_ENV = dev
|
||||
DEBUG = 1
|
||||
KEYS = "dev:dev"
|
||||
CRON_KEY = dev
|
||||
|
||||
# Route
|
||||
URL_BASE = ""
|
||||
APP_URL = "dev.cslsj.qc.ca"
|
||||
|
||||
# Path
|
||||
CACHE_DIR = "var/cache"
|
||||
META_DIR = "meta"
|
||||
LOGS_DIR = "var/logs"
|
||||
PUBLIC_DIR = "public"
|
||||
PRIVATE_DIR = "private"
|
||||
VIEW_DIR = "view"
|
||||
I18N_DIR = "i18n"
|
||||
|
||||
DEFAULT_TIMEZONE = "America/Toronto"
|
||||
DEFAULT_LOCAL = "fr_CA.UTF-8"
|
||||
DEFAULT_TIME = "fr.UTF-8"
|
||||
DEFAULT_TIME_FALLBACK = "french.UTF-8"
|
||||
|
||||
# MS Authentication
|
||||
# MS_OAUTH_CLIENT_ID = ""
|
||||
# MS_OAUTH_CLIENT_SECRET = ""
|
||||
|
||||
# MS Graph
|
||||
# MS_GRAPH_CLIENT_ID = ""
|
||||
# MS_GRAPH_CLIENT_SECRET = ""
|
||||
# MS_GRAPH_ACCESS_TOKEN_URL = ""
|
||||
|
||||
# Database
|
||||
DATABASE_PORT = "3306"
|
||||
DATABASE_HOST = "appsdb.cslsj.qc.ca"
|
||||
DATABASE_NAME = ""
|
||||
DATABASE_USERNAME = ""
|
||||
DATABASE_PASSWORD = ""
|
||||
DATABASE_CHARSET = "utf8"
|
||||
DATABASE_ADAPTER = "MariaDB"
|
||||
|
||||
LEAN_RANDOM = "%RAND64%"
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
'lean' => [
|
||||
'autoload' => [
|
||||
'lean.default',
|
||||
getenv('DEBUG') ? 'lean.console' : null,
|
||||
'%APPKEY%',
|
||||
],
|
||||
],
|
||||
|
||||
'keys' => (function() {
|
||||
foreach(explode(',', getenv('KEYS') ?? "") as $item) {
|
||||
list($var, $value) = explode(":", trim($item));
|
||||
$list[$var] = $value;
|
||||
}
|
||||
|
||||
return $list;
|
||||
})(),
|
||||
|
||||
'meta' => [
|
||||
'application_name' => "",
|
||||
],
|
||||
|
||||
'ulmus' => [
|
||||
'connections' => [
|
||||
'default' => [
|
||||
'adapter' => getenv("DATABASE_ADAPTER"),
|
||||
'host' => getenv("DATABASE_HOST"),
|
||||
'port' => getenv("DATABASE_PORT"),
|
||||
'database' => getenv("DATABASE_NAME"),
|
||||
'username' => getenv("DATABASE_USERNAME"),
|
||||
'password' => getenv("DATABASE_PASSWORD"),
|
||||
'settings' => [
|
||||
'charset' => getenv("DATABASE_CHARSET"),
|
||||
],
|
||||
],
|
||||
]
|
||||
]
|
||||
];
|
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
use Psr\Http\Message\ResponseInterface,
|
||||
Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
/*
|
||||
Min Hour Day Mon Weekday
|
||||
* * * * *
|
||||
┬ ┬ ┬ ┬ ┬
|
||||
│ │ │ │ └─ Weekday (0=Sun .. 6=Sat)
|
||||
│ │ │ └────── Month (1..12)
|
||||
│ │ └─────────── Day (1..31)
|
||||
│ └──────────────── Hour (0..23)
|
||||
└───────────────────── Minute (0..59)
|
||||
|
||||
ex:
|
||||
0 * * * * Chaque heure
|
||||
15 2 * * 0 Tout les dimanches soir a 2h15 AM
|
||||
*/
|
||||
|
||||
return [
|
||||
"* * * * *" => function(ServerRequestInterface $request, ResponseInterface $response) : ResponseInterface
|
||||
{
|
||||
|
||||
},
|
||||
];
|
|
@ -0,0 +1,52 @@
|
|||
<?php
|
||||
|
||||
use function DI\autowire, DI\create, DI\get;
|
||||
|
||||
use %NAMESPACE%\Entity;
|
||||
|
||||
use Ulmus\Entity\Field\Datetime,
|
||||
Ulmus\User\Lib\Authenticate;
|
||||
|
||||
use Storage\{ Session, Cookie };
|
||||
|
||||
use Laminas\Diactoros\Response\{ RedirectResponse, HtmlResponse };
|
||||
|
||||
use Notes\Security\SecurityHandler;
|
||||
|
||||
use Picea\Picea;
|
||||
|
||||
use TheBugs\Email\{ EmailConfiguration, MailerInterface, SwiftMailer };
|
||||
|
||||
return [
|
||||
Entity\User::class => autowire(Entity\User::class),
|
||||
|
||||
Authenticate::class => create(Authenticate::class)->constructor(get(Session::class), get(Cookie::class), get('authentication.method')),
|
||||
|
||||
SecurityHandler::class => create(SecurityHandler::class)->constructor(function() {
|
||||
return new RedirectResponse(getenv("URL_BASE")."/connexion");
|
||||
}),
|
||||
|
||||
'authentication.error' => function($c, Picea $picea) {
|
||||
return function($message) use ($picea) {
|
||||
return new HtmlResponse($picea->renderHtml('lean/error/500', [
|
||||
'title' => "",
|
||||
'subtitle' => "",
|
||||
'message' => $message,
|
||||
]));
|
||||
};
|
||||
},
|
||||
|
||||
EmailConfiguration::class => function($c) {
|
||||
$email = new EmailConfiguration( EmailConfiguration::AUTH_TYPE_SMTP );
|
||||
$email->smtpHost = getenv('SMTP_HOST');
|
||||
$email->smtpPort = getenv('SMTP_PORT');
|
||||
$email->smtpUsername = getenv('SMTP_USERNAME');
|
||||
$email->smtpPassword = getenv('SMTP_PASSWORD');
|
||||
$email->smtpUseTLS = getenv('SMTP_TLS');
|
||||
$email->toAddress = getenv("TO_EMAIL");
|
||||
$email->fromAddress = getenv("FROM_EMAIL");
|
||||
$email->fromName = getenv("FROM_NAME");
|
||||
|
||||
return $email;
|
||||
},
|
||||
];
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
use function DI\autowire, DI\create, DI\get;
|
||||
|
||||
$dir = getenv("META_PATH") . "/definitions";
|
||||
|
||||
return array_merge(
|
||||
Lean\Lean::definitions(),
|
||||
|
||||
Lean\Console\Lean::definitions(),
|
||||
|
||||
[
|
||||
'%APPKEY%' => [
|
||||
'picea' => [
|
||||
'context' => "%ESCAPED_NAMESPACE%\\View",
|
||||
|
||||
'extensions' => [
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
'ulmus' => [
|
||||
'entities' => [ '%ESCAPED_NAMESPACE%\\Entity' => getenv("PROJECT_PATH") . '/src/Entity/' ],
|
||||
],
|
||||
|
||||
'routes' => [
|
||||
'%ESCAPED_NAMESPACE%\\Controller' => getenv("PROJECT_PATH") . '/src/Controller/',
|
||||
],
|
||||
],
|
||||
],
|
||||
|
||||
require("$dir/auth.php"),
|
||||
require("$dir/storage.php"),
|
||||
require("$dir/env/" . getenv('APP_ENV') . ".php"),
|
||||
[ 'config' => function () { return require(getenv("META_PATH")."/config.php"); } ]
|
||||
);
|
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
|
||||
use function DI\create, DI\autowire, DI\get;
|
||||
|
||||
use Dump\DumpMiddleware;
|
||||
|
||||
if ($_GET['sql'] ?? false) {
|
||||
\Ulmus\Common\PdoObject::$dump = "dump";
|
||||
}
|
||||
|
||||
return [
|
||||
"dump" => create(DumpMiddleware::class),
|
||||
"errorHandler" => create(Middlewares\Whoops::class),
|
||||
];
|
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
use Picea\Picea;
|
||||
|
||||
use CSLSJ\Debogueur\DebogueurMiddleware;
|
||||
|
||||
use Laminas\Diactoros\Response\HtmlResponse;
|
||||
|
||||
use Psr\Http\Server\MiddlewareInterface,
|
||||
Psr\Http\Message\ServerRequestInterface,
|
||||
Psr\Http\Server\RequestHandlerInterface,
|
||||
Psr\Http\Message\ResponseInterface;
|
||||
|
||||
use function DI\{ create, get, autowire };
|
||||
|
||||
error_reporting(getenv('ERROR_REPORTING') ?: ( E_ALL & ~E_USER_DEPRECATED & ~E_DEPRECATED & ~E_STRICT & ~E_NOTICE ));
|
||||
|
||||
return [
|
||||
/* do nothing in production !*/
|
||||
"dump" => function($c) {
|
||||
if (! function_exists('dump') ) {
|
||||
function dump(...$what) {}
|
||||
}
|
||||
|
||||
return new class implements MiddlewareInterface {
|
||||
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler) : ResponseInterface { return $handler->handle($request); }
|
||||
};
|
||||
},
|
||||
|
||||
"errorHandler" => create(DebogueurMiddleware::class)->constructor(getenv('DEBOGUEUR_HASH') ?: "", null, get('app.errorhandler.html')),
|
||||
|
||||
'app.errorhandler.html' => function($c, Picea $picea) {
|
||||
return function(\Throwable $exception) use ($picea) {
|
||||
return new HtmlResponse($picea->renderHtml('lean/error/500', [
|
||||
'title' => "Une erreur s'est produite lors de l'exécution du script.",
|
||||
'subtitle' => "Êtes-vous connecté avec le bon compte ?",
|
||||
'message' => $exception->getMessage(),
|
||||
'exception' => $exception,
|
||||
]));
|
||||
};
|
||||
},
|
||||
];
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
use Psr\Container\ContainerInterface;
|
||||
|
||||
use Ulmus\ConnectionAdapter,
|
||||
Ulmus\Container\AdapterProxy;
|
||||
|
||||
use LdapRecord\Connection;
|
||||
|
||||
return [
|
||||
ConnectionAdapter::class => function($c) {
|
||||
$adapter = new ConnectionAdapter('default', $c->get('config')['ulmus'], true);
|
||||
$adapter->resolveConfiguration();
|
||||
|
||||
$adapter->connect();
|
||||
|
||||
return $adapter;
|
||||
},
|
||||
|
||||
AdapterProxy::class => function (ContainerInterface $c) {
|
||||
return new AdapterProxy(
|
||||
$c->get(ConnectionAdapter::class)
|
||||
);
|
||||
}
|
||||
];
|
|
@ -0,0 +1,8 @@
|
|||
<IfModule mod_rewrite.c>
|
||||
RewriteEngine On
|
||||
|
||||
# Remove trailing slashes from request URL
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteCond %{REQUEST_URI} (.+)/$
|
||||
RewriteRule ^ %1 [R=301,L]
|
||||
</IfModule>
|
|
@ -0,0 +1,3 @@
|
|||
<?php
|
||||
|
||||
require_once("../src/Kernel.php");
|
|
@ -0,0 +1,45 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<system.webServer>
|
||||
<rewrite>
|
||||
<rules>
|
||||
<rule name="Remove trailing slash" stopProcessing="true">
|
||||
<match url="(.*)/$" />
|
||||
<conditions>
|
||||
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
|
||||
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
|
||||
</conditions>
|
||||
<action type="Redirect" redirectType="Permanent" url="{R:1}" />
|
||||
</rule>
|
||||
<rule name="Framework Routing" stopProcessing="true">
|
||||
<match url="." ignoreCase="false" />
|
||||
<conditions logicalGrouping="MatchAll">
|
||||
<add input="{REQUEST_FILENAME}" matchType="IsFile" ignoreCase="false" negate="true" />
|
||||
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" ignoreCase="false" negate="true" />
|
||||
</conditions>
|
||||
<action type="Rewrite" url="index.php" />
|
||||
</rule>
|
||||
</rules>
|
||||
</rewrite>
|
||||
<staticContent>
|
||||
<remove fileExtension=".js" />
|
||||
<mimeMap fileExtension=".js" mimeType="application/x-javascript; charset=UTF-8" />
|
||||
<remove fileExtension=".css" />
|
||||
<mimeMap fileExtension=".css" mimeType="text/css; charset=UTF-8" />
|
||||
<remove fileExtension=".woff" />
|
||||
<remove fileExtension=".eot" />
|
||||
<remove fileExtension=".ttf" />
|
||||
<remove fileExtension=".svg" />
|
||||
|
||||
<mimeMap fileExtension=".eot" mimeType="application/vnd.ms-fontobject" />
|
||||
<mimeMap fileExtension=".ttf" mimeType="application/font-sfnt" />
|
||||
<mimeMap fileExtension=".svg" mimeType="image/svg+xml" />
|
||||
<mimeMap fileExtension=".woff" mimeType="application/font-woff" />
|
||||
</staticContent>
|
||||
<handlers>
|
||||
<remove name="PHP7.3" />
|
||||
<add name="PHP7.3" path="*.php" verb="*" modules="FastCgiModule" scriptProcessor="C:\php\7.4.0\php-cgi.exe" resourceType="File" requireAccess="Script" />
|
||||
</handlers>
|
||||
<httpErrors errorMode="Detailed" />
|
||||
</system.webServer>
|
||||
</configuration>
|
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
namespace %NAMESPACE%\Controller;
|
||||
|
||||
use Psr\Http\Message\{ServerRequestInterface, ResponseInterface };
|
||||
|
||||
use %NAMESPACE%\{ Lib, Entity, Form, };
|
||||
|
||||
use function %NAMESPACE%\View\{ _, lang, url, route, form };
|
||||
|
||||
/**
|
||||
* @Language("%APPKEY%.home")
|
||||
*/
|
||||
class Home {
|
||||
use Lib\ControllerTrait;
|
||||
|
||||
/**
|
||||
* @Route("/", "name" => "home")
|
||||
*/
|
||||
public function index(ServerRequestInterface $request, array $arguments) : ResponseInterface
|
||||
{
|
||||
form(new Form\Form(), $this->pushContext(new Lib\FormContext($request, "form.name")));
|
||||
|
||||
return $this->renderView('home');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
|
||||
namespace %NAMESPACE%\Entity;
|
||||
|
||||
use Ulmus\Entity\Field\Datetime;
|
||||
|
||||
use %NAMESPACE%\Lib;
|
||||
|
||||
/**
|
||||
* # Table('name' => "user")
|
||||
*/
|
||||
class User extends \Ulmus\User\Entity\User implements \JsonSerializable
|
||||
{
|
||||
use Lib\EntityTrait;
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
namespace %NAMESPACE%\Form;
|
||||
|
||||
use %NAMESPACE%\{ Lib, Entity };
|
||||
use Picea\Ui\Method\{ FormContextInterface, Message\ErrorMessage };
|
||||
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
use function %NAMESPACE%\View\{ lang };
|
||||
|
||||
class Form implements \Picea\Ui\Method\FormInterface {
|
||||
|
||||
public function initialize(FormContextInterface $context) : void
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public function validate(FormContextInterface $context) : bool
|
||||
{
|
||||
return $context->valid();
|
||||
}
|
||||
|
||||
public function execute(FormContextInterface $context) : void
|
||||
{
|
||||
$context->pushMessage(Message::generateSuccess(
|
||||
lang("form.success")
|
||||
));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace %NAMESPACE%;
|
||||
|
||||
use Ulmus\ConnectionAdapter;
|
||||
|
||||
require_once dirname(__DIR__) . '/vendor/autoload.php';
|
||||
|
||||
new class(dirname(__DIR__)) extends \Lean\Kernel {
|
||||
|
||||
public array $paths = [
|
||||
'CACHE_PATH' => "CACHE_DIR",
|
||||
'LOGS_PATH' => "LOGS_DIR",
|
||||
'META_PATH' => "META_DIR",
|
||||
'PUBLIC_PATH' => "PUBLIC_DIR",
|
||||
'PRIVATE_PATH' => "PRIVATE_DIR",
|
||||
'VIEW_PATH' => "VIEW_DIR",
|
||||
];
|
||||
|
||||
protected function initializeEngine() : self
|
||||
{
|
||||
$this->errorLogPath = getenv("LOGS_PATH") . DIRECTORY_SEPARATOR. date("Y-m").".log";
|
||||
|
||||
$this->definitionFilePath = implode(DIRECTORY_SEPARATOR, [ getenv('META_PATH'), 'definitions', 'definitions.php' ]);
|
||||
|
||||
return parent::initializeEngine();
|
||||
}
|
||||
|
||||
protected function serviceContainer() : self
|
||||
{
|
||||
# $this->container->get(ConnectionAdapter::class);
|
||||
|
||||
return parent::serviceContainer();
|
||||
}
|
||||
|
||||
};
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
namespace %NAMESPACE%\Lib;
|
||||
|
||||
use Picea\Picea;
|
||||
use Storage\Session;
|
||||
use Ulmus\User\Entity\User;
|
||||
use Ulmus\User\Lib\Authenticate;
|
||||
use %NAMESPACE%\Entity;
|
||||
|
||||
/**
|
||||
* @Security("locked" => false)
|
||||
* @RouteParam("methods" => [ "GET", "POST" ])
|
||||
*/
|
||||
trait ControllerTrait {
|
||||
use \Lean\ControllerTrait;
|
||||
|
||||
public ? \Ulmus\User\Entity\User $user;
|
||||
|
||||
protected Authenticate $authenticate;
|
||||
|
||||
public function __construct(Picea $picea, Session $session, Authenticate $authenticate) {
|
||||
$this->initializeController($picea, $session, $authenticate);
|
||||
}
|
||||
|
||||
public function initializeController(Picea $picea, Session $session, Authenticate $authenticate) {
|
||||
$this->picea = $picea;
|
||||
$this->authenticate = $authenticate;
|
||||
$this->session = $session;
|
||||
$this->user = $authenticate->rememberMe( Entity\User::repository() ) ?: new User();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
<?php
|
||||
|
||||
namespace %NAMESPACE%\Lib;
|
||||
|
||||
trait EntityTrait {
|
||||
use \Ulmus\EntityTrait;
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
<?php
|
||||
|
||||
namespace %NAMESPACE%\Lib;
|
||||
|
||||
class FormContext extends \Picea\Ui\Method\FormContext { }
|
|
@ -0,0 +1,103 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace %NAMESPACE%\Lib;
|
||||
|
||||
use Picea\Ui\Method\FormMessage;
|
||||
|
||||
class Message implements FormMessage {
|
||||
|
||||
const MESSAGE_TYPE = [
|
||||
'success' => [
|
||||
'class' => 'success',
|
||||
'header' => 'Succès !',
|
||||
'message' => ''
|
||||
],
|
||||
|
||||
'error' => [
|
||||
'class' => 'danger',
|
||||
'header' => 'Error !',
|
||||
'message' => ''
|
||||
],
|
||||
|
||||
'warning' => [
|
||||
'class' => 'warning',
|
||||
'header' => 'Attention !',
|
||||
'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' => 'show-notification',
|
||||
'type' => [
|
||||
'error' => 'danger',
|
||||
'success' => 'success',
|
||||
'warning' => 'warning',
|
||||
][$this->type],
|
||||
'shake' => '.wrapper',
|
||||
'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);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
<?php
|
||||
|
||||
namespace %NAMESPACE%\Middleware;
|
||||
|
||||
use Psr\Http\Server\MiddlewareInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
use Storage\Session;
|
||||
|
||||
class Authentication implements MiddlewareInterface {
|
||||
|
||||
public Session $session;
|
||||
|
||||
public string $sessionUserVariable = 'user';
|
||||
|
||||
public ResponseInterface $loginRedirect;
|
||||
|
||||
public function __construct(ResponseInterface $loginRedirect, Session $session)
|
||||
{
|
||||
$this->loginRedirect = $loginRedirect;
|
||||
$this->session = $session;
|
||||
}
|
||||
|
||||
/**
|
||||
* Middleware request handling
|
||||
*
|
||||
* @param ServerRequestInterface $request
|
||||
* @param RequestHandlerInterface $handler
|
||||
* @return ResponseInterface
|
||||
*/
|
||||
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler) : ResponseInterface
|
||||
{
|
||||
$user = $this->session->get( $this->sessionUserVariable() );
|
||||
|
||||
if ( ! $user ) {
|
||||
return $this->loginRedirect;
|
||||
}
|
||||
|
||||
return $handler->handle($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter / setter of Session User Variable
|
||||
*
|
||||
* @param string|null sessionUserVariable
|
||||
* @return mixed
|
||||
*/
|
||||
public function sessionUserVariable(?string $set = null) : string
|
||||
{
|
||||
return $set !== null ? $this->sessionUserVariable = $set : $this->sessionUserVariable;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
{% section "head" %}
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<title>{% section "head.title" %}{{ title() }} — {{ lang('application_name') }}{% endsection %}</title>
|
||||
<link rel="stylesheet" href="{% asset 'static/css/main.e39066da.css' %}">
|
||||
<style>
|
||||
@font-face{
|
||||
font-family:FontAwesome;
|
||||
src:url({% asset 'static/fonts/fontawesome-webfont.674f50d2.eot' %});
|
||||
src:url({% asset 'static/fonts/fontawesome-webfont.674f50d2.eot' %}) format("embedded-opentype"),
|
||||
url({% asset 'static/fonts/fontawesome-webfont.af7ae505.woff2' %}) format("woff2"),
|
||||
url({% asset 'static/fonts/fontawesome-webfont.fee66e71.woff' %}) format("woff"),
|
||||
url({% asset 'static/fonts/fontawesome-webfont.b06871f2.ttf' %}) format("truetype"),
|
||||
url({% asset 'static/images/fontawesome-webfont.912ec66d.svg' %}) format("svg");
|
||||
font-weight:400;
|
||||
font-style:normal;
|
||||
}
|
||||
</style>
|
||||
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="{% asset 'static/favicon/apple-touch-icon.png' %}">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="{% asset 'static/favicon/favicon-32x32.png' %}">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="{% asset 'static/favicon/favicon-16x16.png' %}">
|
||||
<link rel="manifest" href="{% asset 'static/favicon/site.webmanifest' %}">
|
||||
<link rel="mask-icon" href="{% asset 'static/favicon/safari-pinned-tab.svg' %}" color="#5bbad5">
|
||||
<meta name="msapplication-TileColor" content="#2d89ef">
|
||||
<meta name="theme-color" content="#ffffff">
|
||||
</head>
|
||||
{% endsection %}
|
||||
|
||||
{% section "body" %}
|
||||
<body>
|
||||
{% section "body.header" %}{% endsection %}
|
||||
|
||||
{% section "header" %}{% endsection %}
|
||||
|
||||
{% section "message" %}
|
||||
{% view "lean/widget/message" %}
|
||||
{% endsection %}
|
||||
|
||||
<main role="main" class="content">{% section "main" %}{% endsection %}</main>
|
||||
|
||||
<footer>{% section "footer" %}{% endsection %}</footer>
|
||||
|
||||
{% section "body.footer" %}{% endsection %}
|
||||
</body>
|
||||
{% endsection %}
|
||||
</html>
|
|
@ -0,0 +1,9 @@
|
|||
{% extends 'base/layout/default' %}
|
||||
|
||||
{% title "Home" %}
|
||||
|
||||
{% section "main" %}
|
||||
<div class="main">
|
||||
Hello World :) !
|
||||
</div>
|
||||
{% endsection %}
|
|
@ -0,0 +1,92 @@
|
|||
<?php
|
||||
|
||||
namespace Lean;
|
||||
|
||||
use Composer\EventDispatcher\Event;
|
||||
|
||||
class Composer
|
||||
{
|
||||
public static function postInstall(Event $event) : void
|
||||
{
|
||||
$event->getIO()->write("post-install script executing ...");
|
||||
|
||||
if ( $event->getIO()->askConfirmation("Do you want to install Lean's Project Skeleton ? ( 'yes' or 'no' (default) ): ", false) ) {
|
||||
$ns = trim(static::getNamespaceFromAutoload($event), '\\');
|
||||
|
||||
$replace = [
|
||||
'%NAMESPACE%' => $ns,
|
||||
'%ESCAPED_NAMESPACE%' => addslashes($ns),
|
||||
'%APPKEY%' => strtolower(str_replace('\\', '.', $ns)),
|
||||
'%RAND64%' => substr(base64_encode(random_bytes(100)), 0, 64),
|
||||
];
|
||||
|
||||
$dir = static::createPath();
|
||||
|
||||
if ( is_writable($dir) ) {
|
||||
$source = static::createPath('vendor', 'mcnd', 'lean', 'skeleton');
|
||||
$dest = static::createPath('skeleton');
|
||||
|
||||
`cp -a $source $dest`;
|
||||
|
||||
$iterator = new \RecursiveDirectoryIterator($dest);
|
||||
$iterator->setFlags(\RecursiveDirectoryIterator::SKIP_DOTS);
|
||||
|
||||
foreach (new \RecursiveIteratorIterator($iterator) as $file) {
|
||||
if ( in_array($file->getExtension(), [ 'php', 'phtml', 'env' ]) ) {
|
||||
$content = str_replace(array_keys($replace), array_values($replace), file_get_contents($file->getPathname()));
|
||||
|
||||
file_put_contents($file->getPathname(), $content);
|
||||
}
|
||||
}
|
||||
|
||||
foreach(scandir(static::createPath('skeleton')) as $item) {
|
||||
if ( in_array($item, [ '.', '..' ]) ) continue;
|
||||
|
||||
rename(static::createPath('skeleton', $item), static::createPath($item));
|
||||
}
|
||||
|
||||
rmdir($dest);
|
||||
|
||||
$event->getIO()->write("Installation completed.");
|
||||
}
|
||||
else {
|
||||
$event->getIO()->writeError(sprintf("The user you are running this script with doesn't seem to have a writable permission on directory %s", static::createPath()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected static function readComposerJson(Event $event) : ? array
|
||||
{
|
||||
$path = static::createPath('composer.json');
|
||||
|
||||
return file_exists($path) ? json_decode(file_get_contents($path), true) : null;
|
||||
}
|
||||
|
||||
protected static function getNamespaceFromAutoload(Event $event) : ? string
|
||||
{
|
||||
if ( null !== $composerJson = static::readComposerJson($event) ) {
|
||||
if ( $psr4 = $composerJson['autoload']['psr-4'] ?? false ) {
|
||||
foreach($psr4 as $ns => $directory) {
|
||||
if ($directory === 'src/') {
|
||||
return $ns;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
$event->getIO()->writeError("Your composer file do not seem to contains a valid psr-4 project of it's autoload array.");
|
||||
}
|
||||
}
|
||||
else {
|
||||
$event->getIO()->writeError("Composer.json file not found. Have this script been launch from the Composer CLI at the root of your project ?");
|
||||
}
|
||||
|
||||
$event->getIO()->writeError("Your composer file do not seem to contains a valid psr-4 project pointing to the src folder.");
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected static function createPath(... $path) : string
|
||||
{
|
||||
return implode(DIRECTORY_SEPARATOR, array_merge([ $_SERVER['PWD'] ], $path));
|
||||
}
|
||||
}
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
namespace Lean;
|
||||
|
||||
use CSLSJ\Common\RequestResponse\DownloadResponse;
|
||||
use CSLSJ\Common\RequestResponse\ImageResponse;
|
||||
use CSLSJ\Common\RequestResponse\{ PdfResponse, ImageResponse, DownloadResponse };
|
||||
|
||||
use Picea,
|
||||
Picea\Ui\Method\FormContext;
|
||||
|
||||
|
@ -63,6 +63,11 @@ trait ControllerTrait {
|
|||
return new RedirectResponse($url, $code, $headers);
|
||||
}
|
||||
|
||||
public function renderPdf($rawdata, int $status = 200, array $headers = []) : PdfResponse
|
||||
{
|
||||
return new PdfResponse($rawdata, $status, $headers);
|
||||
}
|
||||
|
||||
public static function renderText(string $html, int $code = 200, array $headers = []) : ResponseInterface
|
||||
{
|
||||
return new TextResponse($html, $code, $headers);
|
||||
|
|
|
@ -107,6 +107,7 @@ class Lean
|
|||
$path = dirname(__DIR__) . "/meta/definitions/";
|
||||
|
||||
return array_merge(
|
||||
require($path . "email.php"),
|
||||
require($path . "http.php"),
|
||||
require($path . "language.php"),
|
||||
require($path . "routes.php"),
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
{% extends "lean/layout/error" %}
|
||||
|
||||
{% language.set "lean.error.500" %}
|
||||
|
||||
{% title _('page-title') %}
|
||||
|
||||
{% section "content-right" %}
|
||||
<div>
|
||||
<div class="title">{% _ "title" %}</div>
|
||||
<div class="subtitle">{{= isset($subtitle) ? nl2br($subtitle) : _("subtitle") }}</div>
|
||||
<div class="content">{{= isset($message) ? nl2br($message) : _("message") }}</div>
|
||||
<u><a href="#" onclick="history.back()">{% _ "back" %}</a></u>
|
||||
</div>
|
||||
{% endsection %}
|
||||
|
||||
{% section "content-left" %}
|
||||
<img class="picto-login" src="{% asset 'static/img/bugs.svg' %}">
|
||||
{% endsection %}
|
||||
|
||||
{% section "head.css" %}
|
||||
.title {font-size:2rem}
|
||||
.subtitle {font-size:1.25rem; padding-top: 1rem;}
|
||||
.content {padding-top:1rem}
|
||||
{% endsection %}
|
Loading…
Reference in New Issue