diff --git a/Dockerfile b/Dockerfile index fafa7c72..5a372288 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,4 +14,4 @@ COPY . ./ EXPOSE 8080 -CMD php console server:start --host=0.0.0.0 --port=8080 \ No newline at end of file +CMD php console serve --host=0.0.0.0 --port=8080 \ No newline at end of file diff --git a/app/Http/Actions/UserActions.php b/app/Http/Actions/UserActions.php index 1070c780..be76c015 100644 --- a/app/Http/Actions/UserActions.php +++ b/app/Http/Actions/UserActions.php @@ -30,9 +30,8 @@ public static function update(array $data, string $email) } $user->fill($data); - $user = $user->save(); - - return $user; + + return $user->save(); } public static function updatPassword(string $password, string $email) diff --git a/app/Http/Controllers/Auth/EmailVerificationController.php b/app/Http/Controllers/Auth/EmailVerificationController.php index 275cddf2..9a0f178b 100644 --- a/app/Http/Controllers/Auth/EmailVerificationController.php +++ b/app/Http/Controllers/Auth/EmailVerificationController.php @@ -45,17 +45,17 @@ public function notify(Request $request, Response $response) public function verify(Request $request, Response $response) { if (!$request->hasQuery('email', 'token')) { - $response->send(__('bad_request'), [], 400); + $response->send(data: __('bad_request'), code: 400); } $token = Token::findBy('email', $request->email); if (!$token || $token->token !== $request->token) { - $response->send(__('invalid_password_reset_link'), [], 400); + $response->send(data: __('invalid_password_reset_link'), code: 400); } if (Carbon::parse($token->expire)->lt(Carbon::now())) { - $response->send(__('expired_password_reset_link'), [], 400); + $response->send(data: __('expired_password_reset_link'), code: 400); } $token->delete(); diff --git a/app/Http/Controllers/Auth/ForgotPasswordController.php b/app/Http/Controllers/Auth/ForgotPasswordController.php index 4f74275f..cfe7e6a9 100644 --- a/app/Http/Controllers/Auth/ForgotPasswordController.php +++ b/app/Http/Controllers/Auth/ForgotPasswordController.php @@ -45,17 +45,17 @@ public function notify(Request $request, Response $response) public function reset(Request $request, Response $response) { if (!$request->hasQuery('email', 'token')) { - $response->send(__('bad_request'), [], 400); + $response->send(data: __('bad_request'), code: 400); } $token = Token::findBy('email', $request->email); if (!$token || $token->token !== $request->token) { - $response->send(__('invalid_password_reset_link'), [], 400); + $response->send(data: __('invalid_password_reset_link'), code: 400); } if (Carbon::parse($token->expire)->lt(Carbon::now())) { - $response->send(__('expired_password_reset_link'), [], 400); + $response->send(data: __('expired_password_reset_link'), code: 400); } $token->delete(); @@ -64,7 +64,7 @@ public function reset(Request $request, Response $response) public function update(Request $request, Response $response, LoginValidator $loginValidator) { - $loginValidator->validate($request->inputs()); + $loginValidator->validate($request->inputs(), $response); $user = UserActions::updatPassword($request->password, $request->email); if (!$user) { diff --git a/app/Http/Controllers/Auth/LoginController.php b/app/Http/Controllers/Auth/LoginController.php index 91b261ee..6556c022 100644 --- a/app/Http/Controllers/Auth/LoginController.php +++ b/app/Http/Controllers/Auth/LoginController.php @@ -8,7 +8,6 @@ namespace App\Http\Controllers\Auth; -use Carbon\Carbon; use Core\Http\Request; use Core\Support\Auth; use Core\Support\Alert; @@ -28,19 +27,15 @@ public function index(Request $request, Response $response) public function authenticate(Request $request, Response $response, LoginValidator $loginValidator) { - $loginValidator->validate($request->inputs()); + $loginValidator->validate($request->inputs(), $response); - if (Auth::attempt($request->only('email', 'password'), $request->has('remember'))) { + if (Auth::attempt($response, $request->only('email', 'password'), $request->has('remember'))) { $uri = !Session::has('intended') ? config('app.home') : Session::pull('intended'); Alert::toast(__('welcome', ['name' => Auth::get('name')]))->success(); $response->redirect()->to($uri)->go(); } - if (Auth::attemptsExceeded()) { - $response->redirect()->back()->with('auth_attempts_timeout', Carbon::now()->addMinutes(config('security.auth.unlock_timeout'))->toDateTimeString())->go(); - } - Alert::default(__('login_failed'))->error(); $response->redirect()->to('login')->withInputs($request->only('email', 'password'))->withErrors([__('login_failed')])->go(); } diff --git a/app/Http/Controllers/Auth/RegisterController.php b/app/Http/Controllers/Auth/RegisterController.php index a67fea4f..952d13d5 100644 --- a/app/Http/Controllers/Auth/RegisterController.php +++ b/app/Http/Controllers/Auth/RegisterController.php @@ -30,16 +30,16 @@ public function index(Request $request, Response $response) public function register(Request $request, Response $response, RegisterValidator $registerValidator) { - $data = $registerValidator->validate($request->inputs())->validated(); - $user = UserActions::create($data); - - if (!config('security.auth.email_verification')) { - Mail::send(new WelcomeMail($user->email, $user->name)); - Alert::default(__('account_created'))->success(); - - $response->redirect()->to('login')->go(); + $validator = $registerValidator->validate($request->inputs(), $response); + $user = UserActions::create($validator->validated()); + + if (config('security.auth.email_verification')) { + $response->redirect()->to('email/notify')->go(); } - $response->redirect()->to('email/notify')->go(); + Mail::send(new WelcomeMail($user->email, $user->name)); + Alert::default(__('account_created'))->success(); + + $response->redirect()->to('login')->go(); } } diff --git a/config/routes.php b/config/routes.php index 8b3427a6..4364f79b 100644 --- a/config/routes.php +++ b/config/routes.php @@ -7,9 +7,9 @@ */ /** - * Custom routes paths configuration + * Routes paths configuration */ return [ - 'paths' => [], + 'paths' => ['/'], ]; diff --git a/core/Application.php b/core/Application.php index db44d4e9..d05aef61 100644 --- a/core/Application.php +++ b/core/Application.php @@ -24,7 +24,7 @@ public function __construct() Whoops::register(); } - public function execute() + public function run() { $response = new Response(); diff --git a/core/Exceptions/RoutesPathsNotDefinedException.php b/core/Exceptions/RoutesPathsNotDefinedException.php new file mode 100644 index 00000000..2d1b18c6 --- /dev/null +++ b/core/Exceptions/RoutesPathsNotDefinedException.php @@ -0,0 +1,21 @@ +headers('Location', url($this->uri), $code)); } - public function withCookie(string $name, string $value, int $expire = 3600, bool $secure = false, string $domain = ''): self - { - Cookies::create($name, $value, $expire, $secure, $domain); - return $this; - } - public function with(string $key, $data): self { Session::create($key, $data); @@ -76,4 +70,10 @@ public function withInputs(array $inputs): self Session::create('inputs', $inputs); return $this; } + + public function withCookie(string $name, string $value, int $expire = 3600, bool $secure = false, string $domain = ''): self + { + Cookies::create($name, $value, $expire, $secure, $domain); + return $this; + } } diff --git a/core/Http/Validator/Validator.php b/core/Http/Validator/Validator.php index d297ca1c..dd640308 100644 --- a/core/Http/Validator/Validator.php +++ b/core/Http/Validator/Validator.php @@ -21,12 +21,12 @@ class Validator implements ValidatorInterface protected $errors; protected array $inputs = []; - public function validate(array $inputs): self + public function validate(array $inputs, Response $response): self { $this->inputs = $inputs; $this->errors = GUMP::is_valid($this->inputs, $this->rules(), $this->messages()); - if ($this->fails()) (new Response())->redirect()->back()->withErrors($this->errors())->withInputs($this->inputs)->go(); + if ($this->fails()) $response->redirect()->back()->withErrors($this->errors())->withInputs($this->inputs)->go(); return $this; } diff --git a/core/Http/Validator/ValidatorInterface.php b/core/Http/Validator/ValidatorInterface.php index 669fe6ab..f7d2f409 100644 --- a/core/Http/Validator/ValidatorInterface.php +++ b/core/Http/Validator/ValidatorInterface.php @@ -8,11 +8,13 @@ namespace Core\Http\Validator; +use Core\Http\Response\Response; + interface ValidatorInterface { public function addCustomRule(string $rule, callable $callback, string $error_message): self; - public function validate(array $inputs): self; + public function validate(array $inputs, Response $response): self; public function fails(): bool; diff --git a/core/Routing/Route.php b/core/Routing/Route.php index f4b4650b..ce2ebe9e 100644 --- a/core/Routing/Route.php +++ b/core/Routing/Route.php @@ -8,6 +8,7 @@ namespace Core\Routing; +use Core\Exceptions\RoutesPathsNotDefinedException; use Core\Support\Storage; use Core\Http\Response\Response; @@ -62,6 +63,18 @@ public static function any(string $uri, $handler): self return static::add('GET|POST|DELETE|PUT|OPTIONS|PATCH ' . $uri, $handler); } + public static function all(string $name, string $controller): self + { + return self::group(function() use ($name, $controller) { + self::get('/' . $name, 'index')->name('index'); + self::post('/' . $name, 'store')->name('store'); + self::match('PATCH|PUT', '/' . $name . '/{id:num}', 'update')->name('update'); + self::get('/' . $name . '/{id:num}', 'show')->name('show'); + self::get('/' . $name . '/{id:num}/edit', 'edit')->name('edit'); + self::delete('/' . $name . '/{id:num}', 'delete')->name('delete'); + })->byController($controller)->byName($name); + } + public static function match(string $methods, string $uri, $handler): self { return static::add($methods . ' ' . $uri, $handler); @@ -192,20 +205,20 @@ private static function update(string $old, string $new) public static function load() { - $routes = Storage::path(config('storage.routes'))->getFiles(); - - foreach ($routes as $route) { - require_once config('storage.routes') . $route; + if (empty(config('routes.paths'))) { + throw new RoutesPathsNotDefinedException(); } - $paths = config('routes.paths'); + $paths = array_map(function ($path) { + $path = Storage::path(config('storage.routes'))->addPath($path, '')->getPath(); + return str_replace(['//', '//"'], ['/', '/"'], $path); + }, config('routes.paths')); foreach ($paths as $path) { - $storage = Storage::path(config('storage.routes'))->addPath($path); - $custom_routes = $storage->getFiles(); + $routes = Storage::path($path)->getFiles(); - foreach ($custom_routes as $custom_route) { - require_once $storage->file($custom_route); + foreach ($routes as $route) { + require_once config('storage.routes') . $route; } } } diff --git a/core/Support/Auth.php b/core/Support/Auth.php index c6e930f0..189d3239 100644 --- a/core/Support/Auth.php +++ b/core/Support/Auth.php @@ -8,12 +8,14 @@ namespace Core\Support; +use Carbon\Carbon; use Core\Http\Request; use Core\Support\Cookies; use Core\Support\Session; use Core\Support\Encryption; use App\Database\Models\User; use App\Database\Models\Token; +use Core\Http\Response\Response; /** * Manage authentications @@ -25,16 +27,17 @@ public static function getAttempts() return Session::get('auth_attempts', 0); } - public static function attemptsExceeded() - { - return config('security.auth.max_attempts') > 0 && Auth::getAttempts() >= config('security.auth.max_attempts'); - } - - public static function attempt(array $credentials, bool $remember = false) + public static function attempt(Response $response, array $credentials, bool $remember = false) { Session::push('auth_attempts', 1, 0); - if (!self::checkCredentials($credentials['email'], $credentials['password'], $user)) return false; + if (!self::checkCredentials($credentials['email'], $credentials['password'], $user)) { + if (config('security.auth.max_attempts') > 0 && Auth::getAttempts() >= config('security.auth.max_attempts')) { + $response->redirect()->back()->with('auth_attempts_timeout', Carbon::now()->addMinutes(config('security.auth.unlock_timeout'))->toDateTimeString())->go(); + } + + return false; + } Session::forget('auth_attempts', 'auth_attempts_timeout'); Session::create('user', $user); diff --git a/core/Support/Storage.php b/core/Support/Storage.php index c2b5c668..0a63232c 100644 --- a/core/Support/Storage.php +++ b/core/Support/Storage.php @@ -31,9 +31,9 @@ public function getPath() return self::$path; } - public function addPath(string $path): self + public function addPath(string $path, string $trailling_slash = DS): self { - self::$path .= real_path($path) . DS; + self::$path .= real_path($path) . $trailling_slash; return $this; } @@ -50,7 +50,7 @@ public function createDir(string $pathname = '', bool $recursive = false, int $m public function writeFile(string $filename, $content, bool $append = false) { if (!$this->isDir()) { - if (!$this->createDir('', true)) return false; + if (!$this->createDir(recursive: true)) return false; } $flag = $append ? FILE_APPEND | LOCK_EX : 0; @@ -105,10 +105,7 @@ public function deleteDir(string $pathname = '') foreach ($objects as $object) { if ($object != '.' && $object != '..') { - if ( - $this->isDir($pathname . $object) && - !is_link(self::$path . $pathname . $object) - ) { + if ($this->isDir($pathname . $object) && !is_link(self::$path . $pathname . $object)) { $this->deleteDir($pathname . $object); } else { $this->deleteFile($pathname . $object); diff --git a/index.php b/index.php index e0d2da35..2dfb51ff 100644 --- a/index.php +++ b/index.php @@ -15,5 +15,4 @@ require 'vendor/autoload.php'; require_once 'bootstrap.php'; -$app = new Application(); -$app->execute(); +(new Application())->run(); diff --git a/routes/auth.php b/routes/auth.php index bbb81e93..d5466efe 100644 --- a/routes/auth.php +++ b/routes/auth.php @@ -33,7 +33,7 @@ Route::view('/forgot', 'auth.password.forgot'); Route::get('/new', function (Request $request, Response $response) { - $response->view('auth.password.new', ['email' => $request->queries('email')]); + $response->view('auth.password.new', $request->only('email')); }); })->byPrefix('password')->register();