diff --git a/docs/NewProject.md b/docs/NewProject.md index e4ff255..36934cc 100644 --- a/docs/NewProject.md +++ b/docs/NewProject.md @@ -6,14 +6,14 @@ Open a terminal and go on the directory where you want create your project (Exem - [ ] Check [PHP](https://www.php.net/) version is >= 8.2 by using : -```sh {"id":"01HQDDF3C07BXVQ0PTJKW5NSWW"} +```sh php -v # PHP 8.3.0RC3 (cli) (built: Oct 2 2023 09:38:17) (NTS) ``` - [ ] Check [Composer](https://getcomposer.org/) version is >= 2.5.8 by using : -```sh {"id":"01HQDDF3C07BXVQ0PTJMHR6M50"} +```sh composer -V # Composer version 2.5.8 2023-05-24 15:00:39 ``` @@ -22,7 +22,7 @@ composer -V - [ ] Install last version of [CrazyPHP](https://github.com/kekefreedog/CrazyPHP) by using : -```sh {"id":"01HQDDF3C07BXVQ0PTJP6NNGWV"} +```sh composer require kzarshenas/crazyphp ``` @@ -32,7 +32,7 @@ composer require kzarshenas/crazyphp > If you are using OS Windows, make sure to execute `npm i` into the CrazyPHP folder -```json {"id":"01HQDDF3C07BXVQ0PTJS0562AD"} +```json { "require": { "kzarshenas/crazyphp": "@dev" @@ -53,13 +53,13 @@ composer require kzarshenas/crazyphp And then execute the command below in the terminal : -```sh {"id":"01HQDDF3C07BXVQ0PTJWJD40WV"} +```sh composer update ``` - [ ] Execute the new project cli command by using : -```sh {"id":"01HQDDF3C07BXVQ0PTJXFK2VNA"} +```sh php vendor/kzarshenas/crazyphp/bin/CrazyCommand new project # 🎉 New project created with success 🎉 ``` diff --git a/resources/Extensions/CrazyAuth/Scripts/Interface/AuthInterface.php b/resources/Extensions/CrazyAuth/Scripts/Interface/AuthInterface.php new file mode 100644 index 0000000..5712dcc --- /dev/null +++ b/resources/Extensions/CrazyAuth/Scripts/Interface/AuthInterface.php @@ -0,0 +1,169 @@ + + * @copyright 2022-2024 Kévin Zarshenas + */ +namespace App\Core; + +/** + * Dependances + */ +use CrazyPHP\Library\Exception\ExceptionResponse; +use App\Core\CredentialInterface; +use App\Core\UserInterface; + +/** + * Auth Interface + * + * Interface for authentification + * + * @source https://github.com/PHPAuth/PHPAuth/blob/master/sources/AuthInterface.php + * + * @package kzarshenas/crazyphp + * @author kekefreedog + * @copyright 2022-2024 Kévin Zarshenas + */ +interface AuthInterface { + + /** + * Constructor + * + * @param CredentialInterface $credentials + * @param ?UserInterface $user (Null means you are registering a new user) + * @param array $options + * @param self + */ + public function __construct(CredentialInterface $credentials, ?UserInterface $user = null, array $options = []); + + /** Public method | Action + ****************************************************** + */ + + /** + * Register + * + * Register new user + * + * @return self + */ + public function register():self; + + /** + * Login + * + * Login existing user + * + * @return self + */ + public function login():self; + + /** + * Logout + * + * Logout existing user + * + * @return self + */ + public function logout():self; + + /** + * Logout + * + * Logout all user + * + * @return self + */ + public function logoutAll():self; + + /** + * Activate + * + * Activate existing user + * + * @return self + */ + public function activate():self; + + /** + * Delete + * + * Delete existing user + * + * @return self + */ + public function delete():self; + + /** + * Change Email + * + * Change email of existing user + * + * @return self + */ + public function changeEmail(); + + /** + * Change Password + * + * Change password of existing user + * + * @return self + */ + public function changePassword(); + + + /** Public method | Validator + ****************************************************** + */ + + /** + * Is User Connected + * + * Check if user is connected + * + * @return bool + */ + public function isUserConnected():bool; + + /** + * Is User Valid + * + * Check if user is valid + * + * @return bool + */ + public function isUserValid():bool; + + /** + * Is User Locked + * + * Check if user is locked + * + * @return bool + */ + public function isUserLocked():bool; + + /** Public method | Get + ****************************************************** + */ + + /** + * Get UID + * + * Get unique ID of the auth + */ + public function getUID():int; + + /** + * Get user + * + * @return ?UserInterface + */ + public function getUser():?UserInterface; + +} \ No newline at end of file diff --git a/resources/Extensions/CrazyAuth/Scripts/Interface/CredentialInterface.php b/resources/Extensions/CrazyAuth/Scripts/Interface/CredentialInterface.php new file mode 100644 index 0000000..145a1b5 --- /dev/null +++ b/resources/Extensions/CrazyAuth/Scripts/Interface/CredentialInterface.php @@ -0,0 +1,52 @@ + + * @copyright 2022-2024 Kévin Zarshenas + */ +namespace App\Core; + +/** + * Dependances + */ +use CrazyPHP\Library\Exception\ExceptionResponse; +use App\Core\UserInterface; + +/** + * Credential Interface + * + * Interface for credential + * + * @package kzarshenas/crazyphp + * @author kekefreedog + * @copyright 2022-2024 Kévin Zarshenas + */ +interface CredentialInterface { + + /** + * Constructor + * + * @param array $form + * @param array $options + * @param self + */ + public function __construct(array $form, array $options = []); + + /** Public method | Validator + ****************************************************** + */ + + /** + * Is Email Taken + * + * Check if email is already given + * + * @return bool + */ + public function isEmailTaken():bool; + +} \ No newline at end of file diff --git a/resources/Extensions/CrazyAuth/Scripts/Interface/UserInterface.php b/resources/Extensions/CrazyAuth/Scripts/Interface/UserInterface.php new file mode 100644 index 0000000..42d0082 --- /dev/null +++ b/resources/Extensions/CrazyAuth/Scripts/Interface/UserInterface.php @@ -0,0 +1,114 @@ + + * @copyright 2022-2024 Kévin Zarshenas + */ +namespace App\Core; + +/** + * Dependances + */ +use CrazyPHP\Library\Exception\ExceptionResponse; + +/** + * User Interface + * + * Interface for users + * + * @package kzarshenas/crazyphp + * @author kekefreedog + * @copyright 2022-2024 Kévin Zarshenas + */ +interface UserInterface { + + /** Public method | Get + ****************************************************** + */ + + /** + * Get User Identifier + * + * The public representation of the user (e.g. a username, an email address, etc.) + * + * @return string + */ + public function getUserIdentifier():string; + + /** + * Get Id + * + * @return ?int + */ + public function getId():?int; + + /** + * Get Email + * + * @return ?string + */ + public function getEmail():?string; + + /** + * Get Roles + * + * Returns the roles granted to the user. + * + * @return array + */ + public function getRoles():array; + + /** + * Get Password + * + * @return string + */ + public function getPassword():string; + + /** + * Set Lock + * + * @return string + */ + public function setLock():string; + + /** Public method | Set + ****************************************************** + */ + + /** + * Set Email + * + * @param string $email + * @return self + */ + public function setEmail(string $email):self; + + /** + * Set Password + * + * @param string $password + * @return self + */ + public function setPassword(string $password):self; + + /** + * Set Roles + * + * @param array $roles + * @return self + */ + public function setRoles(array $roles):self; + + /** + * Get Lock + * + * @return string + */ + public function getLock():string; + +} \ No newline at end of file diff --git a/resources/Extensions/CrazyAuth/properties.yml b/resources/Extensions/CrazyAuth/properties.yml new file mode 100644 index 0000000..d9cb9fc --- /dev/null +++ b/resources/Extensions/CrazyAuth/properties.yml @@ -0,0 +1,27 @@ +# # +# Crazy Auth +# +# Properties of the crazy auth extension +# +# YAML version 1.2 +# +# @package kzarshenas/crazyphp +# @author kekefreedog +# @copyright 2022-2024 Kévin Zarshenas +# # +CrazyAuth: + name: CrazyAuth + description: Core extension for manage authentification and user on your crazy app + version: 1.0.0 + scripts: + AuthInterface.php: + source: "@crazyphp_root/resources/Extensions/CrazyAuth/Scripts/Interface/AuthInterface.php" + destination: "@app_root/app/Library/CrazyAuth/Interface/AuthInterface.php" + CredentialInterface.php: + source: "@crazyphp_root/resources/Extensions/CrazyAuth/Scripts/Interface/CredentialInterface.php" + destination: "@app_root/app/Library/CrazyAuth/Interface/CredentialInterface.php" + UserInterface.php: + source: "@crazyphp_root/resources/Extensions/CrazyAuth/Scripts/Interface/UserInterface.php" + destination: "@app_root/app/Library/CrazyAuth/Interface/UserInterface.php" + dependencies: + composer: [] \ No newline at end of file diff --git a/src/Library/File/File.php b/src/Library/File/File.php index c376d84..80a079a 100644 --- a/src/Library/File/File.php +++ b/src/Library/File/File.php @@ -624,6 +624,83 @@ public static function pathReverse(string $input, string|array $env):string { } + /** + * Symelink + * + * Symelink of folders or file based on its path + * + * @param string $source Source to copy + * @param string $target Target where copy + * @param bool $replace Replace symlink if it exists + * @return bool + */ + public static function symlink(string $source = "", string $target = "", bool $replace = true):bool { + + # Declare result + $result = false; + + # Path source + $path_source = self::path($source); + + # Path target + $path_target = self::path($target); + + # Path target parent folder + $path_folder = dirname($path_target); + + # Check folder target exists + if(!is_dir($path_folder)) + + # Create folder + mkdir($path_folder, 0777, true); + + # Check if path_source is dir + /* if(is_dir($path_source)){ + + }else */ + + # Check if source file and target folder + if(is_file($path_source) && is_dir($path_target)) + + # New Exception + throw new CrazyException( + "Can't link file to directory.", + 500, + [ + "custom_code" => "file-005", + ] + ); + + # Check is link + if(is_link($path_target)){ + + # Check replace + if($replace) + + # Unlink + unlink($path_target); + + else + + # New Exception + throw new CrazyException( + "Symlink already exists", + 500, + [ + "custom_code" => "file-004", + ] + ); + + } + + # Set result + $result = symlink($path_source, $path_target); + + # Return result + return $result; + + } + /** * Copy * @@ -773,6 +850,32 @@ public static function isEmpty(string $path = ""):bool { } + /** + * Is Symlink + * + * Check if path given is symlink + * + * @param string $path Path to process + * @return bool + */ + public static function isSymlink(string $path = ""):bool { + + # Set result + $result = false; + + # Get real path + $path = self::path($path); + + # Check folder exists + if(self::exists($path) && is_link($path)) + + $result = true; + + # Return result + return $result; + + } + /** * Remove All * diff --git a/src/Model/Extension/Create.php b/src/Model/Extension/Create.php index 7124727..d42fee0 100644 --- a/src/Model/Extension/Create.php +++ b/src/Model/Extension/Create.php @@ -21,8 +21,10 @@ use CrazyPHP\Exception\CrazyException; use CrazyPHP\Interface\CrazyCommand; use CrazyPHP\Library\File\Composer; +use CrazyPHP\Library\Form\Process; use CrazyPHP\Library\Array\Arrays; use CrazyPHP\Library\File\File; +use CrazyPHP\Library\System\Os; /** * Create Extension @@ -50,6 +52,19 @@ class Create extends CrazyModel implements CrazyCommand { "select" => "CrazyPHP\Library\Extension\Extension::getAllAvailable", "multiple" => true ], + # Symlink + [ + "name" => "symlink", + "description" => "Symlinks for script files", + "type" => "BOOL", + "required" => true, + "default" => false, + "select" => [ + false => "False", + true => "True" + ], + "process" => ["bool"] + ], ]; /** Private Parameters @@ -118,6 +133,12 @@ public static function getRequiredValues():array { */ public function run():self { + /** + * Run Check Os + * - Check OS and symlink compatibility + */ + $this->runCheckOs(); + /** * Run Get Extension * - Search extension @@ -164,6 +185,38 @@ public function run():self { ****************************************************** */ + /** + * Run Check Os + * + * Check OS and symlink compatibility + * + * @return self + */ + public function runCheckOs():self { + + # Check symlink + $inputSymlink = Arrays::filterByKey($this->inputs["extension"], "name", "symlink"); + + # Get values of names + $symlink = $inputSymlink[array_key_first($inputSymlink)]["value"] ?? []; + + # Check symlink and is windows + if($symlink && Os::isWindows()) + + # Extension already installed + throw new CrazyException( + "Symlink with Windows OS isn't supported yet.", + 500, + [ + "custom_code" => "extension-create-001" + ] + ); + + # Return instance + return $this; + + } + /** * Run Get Extension * @@ -327,6 +380,12 @@ public function runInstallDependances():self { */ public function runInstallScripts():self { + # Check symlink + $inputSymlink = Arrays::filterByKey($this->inputs["extension"], "name", "symlink"); + + # Get values of names + $symlink = $inputSymlink[array_key_first($inputSymlink)]["value"] ?? []; + # Check extension to install if(!empty($this->data["toInstall"])) @@ -341,7 +400,7 @@ public function runInstallScripts():self { # Check and get source $source = isset($script["source"]) && File::exists($script["source"]) - ? $script["source"] + ? $script["source"] : "" ; @@ -352,20 +411,40 @@ public function runInstallScripts():self { ; # Check source and destination - if($source && $destination) + if($source && $destination){ + + # Check symlink + if($symlink){ + + # Process symlink + if(!File::symlink($source, $destination)){ + + # New error + throw new CrazyException( + "Failed to create symlink of the file '".File::path($source)."'", + 500, + [ + "custom_code" => "extension-create-002" + ] + ); + + } + }else # Start copy if(!File::copy($source, $destination)) # New error throw new CrazyException( - "Failed the copy of the file '".File::path($source)."'", + "Failed to copy the file '".File::path($source)."'", 500, [ - "custom_code" => "extension-create-001" + "custom_code" => "extension-create-003" ] ); + } + } # Return instance @@ -380,9 +459,24 @@ public function runInstallScripts():self { */ public function runAppendExtensionIntoConfig():self { + # Check symlink + $inputSymlink = Arrays::filterByKey($this->inputs["extension"], "name", "symlink"); + + # Get values of names + $symlink = $inputSymlink[array_key_first($inputSymlink)]["value"] ?? []; + # Check extensions to installed if(isset($this->data["toInstall"]) && !empty($this->data["toInstall"])){ + # Iteration to install + foreach($this->data["toInstall"] as &$extension) + + # Check symlink + if($symlink) + + # Set symlink into extension property + $extension["symlink"] = true; + # Get extensions installed $extensionsInstalled = FileConfig::getValue("Extension.installed"); diff --git a/tests/Library/File/FileTest.php b/tests/Library/File/FileTest.php new file mode 100644 index 0000000..2563a6b --- /dev/null +++ b/tests/Library/File/FileTest.php @@ -0,0 +1,155 @@ + + * @copyright 2022-2024 Kévin Zarshenas + */ +namespace Tests\Library\File; + +/** + * Dependances + */ + +use CrazyPHP\Exception\CrazyException; +use CrazyPHP\Library\File\File; +use PHPUnit\Framework\TestCase; +use CrazyPHP\Model\Env; + +/** + * File Test + * + * Methods for test file methods + * + * @package kzarshenas/crazyphp + * @author kekefreedog + * @copyright 2022-2024 Kévin Zarshenas + */ +class FileTest extends TestCase { + + /** Variables + ****************************************************** + */ + + /** Public method | Preparation + ****************************************************** + */ + + /** + * Set Up Before Class + * + * This method is called before the first test of this test class is run. + * + * @return void + */ + public static function setUpBeforeClass():void { + + # Setup env + Env::set([ + "phpunit_test" => true, + "crazyphp_root" => getcwd(), + ]); + + # Check folder exists + if(File::exists(self::TEST_PATH)){ + + # Remove cache folder + File::removeAll(self::TEST_PATH); + + }else{ + + # Create dir + File::createDirectory(self::TEST_PATH); + + } + + } + + + /** + * Tear Down After Class + * + * This method is called after the last test of this test class is run. + * + * @return void + */ + public static function tearDownAfterClass():void { + + # Remove cache folder + File::removeAll(self::TEST_PATH); + + # Remove folder + File::remove(self::TEST_PATH); + + # Reset env + Env::reset(); + + } + + /** Public method | Tests + ****************************************************** + */ + + /** + * test Symlink + * + * @return void + */ + public function testSymlink():void { + + # Collections + $collections = [ + # File + [ + "source" => "@crazyphp_root/composer.json", + "target" => self::TEST_PATH."/file/composer.json" + ], + # Folder + [ + "source" => "@crazyphp_root/tests", + "target" => self::TEST_PATH."/directory" + ], + ]; + + # Iteration collections + foreach($collections as $value){ + + # Create file symlink + $this->assertTrue(File::symlink($value["source"], $value["target"])); + + # Check is symlink + $this->assertTrue(File::isSymlink($value["target"])); + + } + + # Catch error + try { + + # Impossible actio + File::symlink("@crazyphp_root/composer.json", self::TEST_PATH); + + }catch(CrazyException $e){ + + # Get message + $message = $e->getMessage(); + + # Assert + $this->assertEquals($message, "Can't link file to directory."); + + } + + } + + /** Public constants + ****************************************************** + */ + + /* Path */ + public const TEST_PATH = "@crazyphp_root/tests/.cache/cache/"; + +} \ No newline at end of file diff --git a/tests/Model/ExtensionTest.php b/tests/Model/ExtensionTest.php index 502c3b4..f659fad 100644 --- a/tests/Model/ExtensionTest.php +++ b/tests/Model/ExtensionTest.php @@ -154,7 +154,7 @@ public function testAllExtensionsAvailable():void { $key = array_key_first($properties); # Check key - $this->assertEquals($extensionName, $key); + $this->assertEquals($extensionName, $key, "Check key in extension property is the extension name"); # Iteration of content foreach($properties[$key] as $k => $v){