From f420144ca76f7b5c795eacd22766621a178dc8f2 Mon Sep 17 00:00:00 2001 From: bxel07 Date: Mon, 22 Apr 2024 23:39:59 +0700 Subject: [PATCH] feat : bootstrap app --- .env | 5 +- composer.json | 13 +- devise/AbstractService.php | 17 + .../AppClassBinder/ServiceRegister.php | 14 +- devise/BaseData/Projects.php | 34 + devise/BaseData/QueryHelper/ORM.php | 143 -- devise/BaseData/Users.php | 11 - devise/Display/auth/auth.php | 104 ++ devise/Display/landing.php | 174 +++ devise/Job/test.php | 14 + devise/Service/AbstractService.php | 46 - .../Service/Console/TokenGeneratorConsole.php | 50 + .../Service/Gemstone/Csrf_Token_Producer.php | 15 + devise/Service/Gemstone/DataProcessor.php | 62 + devise/Service/Gemstone/FileProcessor.php | 7 + devise/Service/Gemstone/Gemstone.php | 41 + .../Gemstone/GemstoneAuthorization.php | 126 ++ devise/Service/Middleware/Auth.php | 16 - devise/Service/Middleware/AuthMiddleware.php | 24 + devise/Service/Middleware/CorsMiddleware.php | 37 +- devise/Service/Middleware/CsrfMiddleware.php | 8 - devise/Service/RestApi/Authentication.php | 61 + .../RestApi/Gemstone/DataProcessor.php | 51 - devise/Service/RestApi/Service.php | 128 +- devise/Service/RestApi/sample.php | 52 + ...2232_users_roles.php => a_users_roles.php} | 10 +- ...{m_20240329_192231_roles.php => roles.php} | 6 +- ...{m_20240329_192226_users.php => users.php} | 6 +- public/css/input.css | 3 + public/css/output.css | 1229 +++++++++++++++++ public/css/style.css | 3 + setup/Bootstrap/App.php | 67 +- setup/Command/CommandRunner.php | 3 - setup/Config/DBConfig.php | 4 +- setup/Config/Server.php | 10 +- setup/Dock/DockEntry.php | 29 +- tailwind.config.js | 56 + writeable/Gemstone_log/black_list.php | 2 + writeable/routerCache/class.cache | 30 + 39 files changed, 2232 insertions(+), 479 deletions(-) create mode 100644 devise/AbstractService.php rename devise/{Service => }/AppClassBinder/ServiceRegister.php (81%) create mode 100644 devise/BaseData/Projects.php delete mode 100644 devise/BaseData/QueryHelper/ORM.php delete mode 100644 devise/BaseData/Users.php create mode 100644 devise/Display/auth/auth.php create mode 100644 devise/Display/landing.php create mode 100644 devise/Job/test.php delete mode 100644 devise/Service/AbstractService.php create mode 100755 devise/Service/Console/TokenGeneratorConsole.php create mode 100644 devise/Service/Gemstone/Csrf_Token_Producer.php create mode 100644 devise/Service/Gemstone/DataProcessor.php create mode 100644 devise/Service/Gemstone/FileProcessor.php create mode 100644 devise/Service/Gemstone/Gemstone.php create mode 100644 devise/Service/Gemstone/GemstoneAuthorization.php delete mode 100755 devise/Service/Middleware/Auth.php create mode 100644 devise/Service/Middleware/AuthMiddleware.php mode change 100644 => 100755 devise/Service/Middleware/CorsMiddleware.php delete mode 100644 devise/Service/Middleware/CsrfMiddleware.php create mode 100755 devise/Service/RestApi/Authentication.php delete mode 100644 devise/Service/RestApi/Gemstone/DataProcessor.php create mode 100755 devise/Service/RestApi/sample.php rename migration/{m_20240329_192232_users_roles.php => a_users_roles.php} (59%) rename migration/{m_20240329_192231_roles.php => roles.php} (70%) rename migration/{m_20240329_192226_users.php => users.php} (73%) create mode 100644 public/css/input.css create mode 100644 public/css/output.css create mode 100644 public/css/style.css create mode 100755 tailwind.config.js create mode 100644 writeable/Gemstone_log/black_list.php diff --git a/.env b/.env index f8b913f..6fb12e7 100644 --- a/.env +++ b/.env @@ -1,2 +1,5 @@ NAME=yogi -BUILD=dev \ No newline at end of file +BUILD=dev +CSRF_SECRET_KEY="dara" +GEMSTONE_SECRET=c6ee9e3efac2a6b4a47fdfa4a4dbef77ca3e45aa8dab8ca07c181373dea2f90e +GEMSTONE_ALGO=HS256 diff --git a/composer.json b/composer.json index 6dd9599..10df800 100644 --- a/composer.json +++ b/composer.json @@ -16,7 +16,8 @@ }, "files": [ "setup/Dock/DockEntry.php", - "devise/Service/AppClassBinder/ServiceRegister.php" + "devise/AppClassBinder/ServiceRegister.php", + "devise/Service/Gemstone/Csrf_Token_Producer.php" ] }, "require": { @@ -25,7 +26,13 @@ "xel/logger": "dev-main", "symfony/console": "7.1.x-dev", "vlucas/phpdotenv": "^5.6@dev", - "ext-pdo": "*" + "ext-pdo": "*", + "ext-memcached": "*", + "firebase/php-jwt": "dev-main", + "swoole/ide-helper": "@dev" }, - "minimum-stability": "dev" + "minimum-stability": "dev", + "scripts": { + "watcher-css": "./tailwindcss -i ./public/css/input.css -o ./public/css/output.css --watch" + } } diff --git a/devise/AbstractService.php b/devise/AbstractService.php new file mode 100644 index 0000000..d4a8327 --- /dev/null +++ b/devise/AbstractService.php @@ -0,0 +1,17 @@ + Projects::class ]; } function serviceMiddlewareGlobals(): array { return [ - CorsMiddleware::class ]; } @@ -56,6 +59,7 @@ function serviceConsoleRegister():array MigrationMigrateFresh::class, MigrationRollback::class, MigrationDrop::class, - CreateMigration::class + CreateMigration::class, + TokenGeneratorConsole::class ]; } \ No newline at end of file diff --git a/devise/BaseData/Projects.php b/devise/BaseData/Projects.php new file mode 100644 index 0000000..a93aaab --- /dev/null +++ b/devise/BaseData/Projects.php @@ -0,0 +1,34 @@ +queryDML + ->select($this->permitted) + ->from($this->table) + ->get(); + } + +} \ No newline at end of file diff --git a/devise/BaseData/QueryHelper/ORM.php b/devise/BaseData/QueryHelper/ORM.php deleted file mode 100644 index 1d04b96..0000000 --- a/devise/BaseData/QueryHelper/ORM.php +++ /dev/null @@ -1,143 +0,0 @@ -getQueryBuilder() - ->select() - ->from($table) - ->get(); - } - - /** - * @throws DependencyException - * @throws NotFoundException - * @throws Exception - */ - public function findById(string $table, $id): array - { - return $this->getQueryBuilder() - ->select() - ->from($table) - ->where('id', '=', $id) - ->get(); - } - - /** - * @throws DependencyException - * @throws NotFoundException - * @throws Exception - */ - public function latest(string $table, int $limit): array - { - return $this->getQueryBuilder() - ->select() - ->from($table) - ->latest($limit) - ->get(); - } - - /** - * @throws DependencyException - * @throws NotFoundException - * @throws Exception - */ - public function create(string $table, array $bind): bool - { - $this->getQueryBuilder() - ->insert($table, $bind) - ->run(); - return true; - } - - /** - * @throws DependencyException - * @throws NotFoundException - * @throws Exception - */ - public function update(string $table, array $bind, array $column): void - { - $this->getQueryBuilder() - ->update($table, $bind)->where(array_key_first($column), '=', $column[0]) - ->run(); - } - - /** - * @throws DependencyException - * @throws NotFoundException - * @throws Exception - */ - public function delete(string $table, array $condition): void - { - $this->getQueryBuilder() - ->delete($table) - ->where(array_key_first($condition), '=', $condition[0]) - ->run(); - } - - /*** - * Custom field for mini ORM - */ - public function createWhere() - {} - public function updateWhere() - {} - - /** - * @param string $table1 - * @param string $table2 - * @param string $condition - * @return array|null - * @throws DependencyException - * @throws NotFoundException - * @throws Exception - */ - public function oneToMany(string $table1, string $table2, string $condition): ?array - { - return $this->getQueryBuilder()->select() - ->from($table1)->innerJoin($table2, $condition) - ->get(); - } - - /*** - * @param string $table1 - * @param string $table2 - * @param string $pivot - * @param array $condition - * @return array|null - * @throws DependencyException - * @throws NotFoundException - * @throws Exception - */ - public function manyToMany(string $table1, string $table2, string $pivot, array $condition): ?array - { - return $this->getQueryBuilder()->select() - ->from($table1) - ->innerJoin($pivot, $condition[0]) - ->innerJoin($table2, $condition[1]) - ->get(); - } - - /** - * @throws DependencyException - * @throws NotFoundException - * @throws Exception - */ - public function oneToOne(string $table1, string $table2, string $condition): array - { - return $this->getQueryBuilder()->select() - ->from($table1)->innerJoin($table2, $condition) - ->getAsync(); - } -} \ No newline at end of file diff --git a/devise/BaseData/Users.php b/devise/BaseData/Users.php deleted file mode 100644 index 336b98c..0000000 --- a/devise/BaseData/Users.php +++ /dev/null @@ -1,11 +0,0 @@ - + + + + Login Page + + + + +
+

Login

+
+
+ + +
+
+ + +
+
+
+
+ +
+ +
+ Forgot Password? +
+ +
+
+ + +
+
+ + + + \ No newline at end of file diff --git a/devise/Display/landing.php b/devise/Display/landing.php new file mode 100644 index 0000000..0411389 --- /dev/null +++ b/devise/Display/landing.php @@ -0,0 +1,174 @@ + + + + + + + Landing + + + + + +
+ +
+ +
+ + +
+
+
+
+

Secure, Non-Blocking I/O, Coroutine with PHP

+

Xel-Framework is a powerful and efficient PHP framework that leverages non-blocking I/O and coroutines for exceptional performance and scalability. Xel also provide minimal server configuration and wrap it as Gemstone packet for all i one bundle security package to mitigate XSS, CSRF, DOS, DDOS(http request flood schema), and SQL Injction

+ +
+
+ Dummy Image +
+
+
+
+ +
+ + +
+
+

Features Collections

+
+
+ + + +

POOL DB Connection Management

+

Efficient database connection management using a connection pool.

+
+
+ + + +

Gemstone Security Package

+

Robust security features for authentication, authorization, and data protection.

+
+
+ + + +

Central Manager Runner (CMR)

+

Centralized task management and execution for background jobs and processes.

+
+
+ + + +

Async Job Dispatcher

+

Asynchronous task execution and job dispatching for improved performance.

+
+
+ + + +

Multi Mode Server

+

Flexible server modes for different application requirements.

+
+
+ + + +

HTTP Request & Response Bridger

+

Seamless integration with HTTP requests and responses.

+
+
+
+
+ +
+ + +
+
+
+

Let's Contribute

+
+

Join Our Community

+

Become a part of our community and contribute to our projects!

+
+
+ Join Us +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/devise/Job/test.php b/devise/Job/test.php new file mode 100644 index 0000000..95ba622 --- /dev/null +++ b/devise/Job/test.php @@ -0,0 +1,14 @@ +serverRequest = $serverRequest; - } - - public function setResponse(Response $serverResponse): void - { - $this->serverResponse = $serverResponse; - } - - public function setContainer(Container $container): void - { - $this->container = $container; - } - - /** - * @throws DependencyException - * @throws NotFoundException - */ - public function getQueryBuilder(): QueryDML - { - /**@var QueryDML $queryBuilder*/ - $queryBuilder = $this->container->get('xgen'); - return $queryBuilder; - } - -} \ No newline at end of file diff --git a/devise/Service/Console/TokenGeneratorConsole.php b/devise/Service/Console/TokenGeneratorConsole.php new file mode 100755 index 0000000..65b584e --- /dev/null +++ b/devise/Service/Console/TokenGeneratorConsole.php @@ -0,0 +1,50 @@ +setName(self::$TokenGeneratorConsole) + // the command description shown when running "php bin/console list" + ->setDescription('Generate Secret Token') + // the command help shown when running the command with the "--help" option + ->setHelp('This command allows you to Generate Secret Token') + ; + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $envPath = $this->getProjectDir().'/.env'; + $env = file_get_contents($envPath); + + if (preg_match("/^GEMSTONE_SECRET=/m", $env)) { + $env = preg_replace("/^GEMSTONE_SECRET=.*/m", "GEMSTONE_SECRET={$this->generateSecretKey()}", $env); + } else { + $env .= "\nGEMSTONE_SECRET={$this->generateSecretKey()}"; + } + + file_put_contents($envPath, $env); + return Command::SUCCESS; + } + + private function getProjectDir(): string + { + // Adjust this path as needed if your command is located elsewhere. + return dirname(__DIR__, 3); + } + + private function generateSecretKey(): string + { + $data = new Randomizer(); + return bin2hex($data->getBytes(32)); + } +} diff --git a/devise/Service/Gemstone/Csrf_Token_Producer.php b/devise/Service/Gemstone/Csrf_Token_Producer.php new file mode 100644 index 0000000..bc0051d --- /dev/null +++ b/devise/Service/Gemstone/Csrf_Token_Producer.php @@ -0,0 +1,15 @@ +generateCSRFToken($csrf_maker['gemstone_csrf']['key']); + } + + +} diff --git a/devise/Service/Gemstone/DataProcessor.php b/devise/Service/Gemstone/DataProcessor.php new file mode 100644 index 0000000..ecf4a9e --- /dev/null +++ b/devise/Service/Gemstone/DataProcessor.php @@ -0,0 +1,62 @@ +parser(); + if ($data !== false) { + return $data; + } + throw new Exception('Content is not valid'); + } + + /** + * @throws Exception + */ + private function parser(): false|object + { + $contentType = $this->serverRequest->header['content-type']; + switch ($contentType) { + case "application/x-www-form-urlencoded": + case "application/json": + $data = $this->parseAndSanitize($this->serverRequest->getContent(), $contentType); + return (object)$data; + default: + return false; + } + } + + /** + * @param string $content + * @param string $contentType + * @return array|false + */ + private function parseAndSanitize(string $content, string $contentType) + { + if ($contentType === "application/x-www-form-urlencoded") { + parse_str($content, $data); + } else { + $data = json_decode($content, true); + if (!is_array($data)) { + return false; + } + } + + array_walk_recursive($data, function (&$value) { + //$value = preg_replace('/[^a-zA-Z0-9\s]/', '', htmlspecialchars(filter_var($value, FILTER_SANITIZE_STRING), ENT_QUOTES | ENT_HTML5, 'UTF-8')); + $value = htmlspecialchars(filter_var($value, FILTER_SANITIZE_SPECIAL_CHARS), ENT_QUOTES | ENT_HTML5, 'UTF-8'); + + }); + + return $data; + } + +} \ No newline at end of file diff --git a/devise/Service/Gemstone/FileProcessor.php b/devise/Service/Gemstone/FileProcessor.php new file mode 100644 index 0000000..028ff41 --- /dev/null +++ b/devise/Service/Gemstone/FileProcessor.php @@ -0,0 +1,7 @@ + [ + "condition" => false, // default // ip_based_limit + "max_token" => 100, // max token fill in bucket + "interval" => 60, // "in second" + + // ? additional for DDOS to block service when pass the second threshold + // ? to disable it leave black array, and it will use regular limiter + // ? if already used and need to disable it, please clear the loaded black listed IP on Gemstone_log + // "block_ip" => [], + "block_ip" => [200, __DIR__."/../../../writeable/Gemstone_log/black_list.php"], + ], // implemented and underdeveloped + + + /*********************************************************************************************************************** + * Secure Data Protection (CORS) + ***********************************************************************************************************************/ + "securePost" => [ + 'condition' => true, + 'cors' => [ + 'allowOrigin' => "http://localhost", + 'allowMethods' => ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'], + 'allowHeaders' => ['Content-Type', 'Authorization', 'Origin', 'X-Requested-With,', 'X-CSRF-Token'], + 'maxAge' => 86400, + 'allowCredentials' => true, + ], + ], + + /*********************************************************************************************************************** + * Secure CSRF-Protector + ***********************************************************************************************************************/ + "gemstone_csrf" => [ + 'condition' => true, + 'key' => "dummykey" + ], +]; diff --git a/devise/Service/Gemstone/GemstoneAuthorization.php b/devise/Service/Gemstone/GemstoneAuthorization.php new file mode 100644 index 0000000..86593a6 --- /dev/null +++ b/devise/Service/Gemstone/GemstoneAuthorization.php @@ -0,0 +1,126 @@ +cookie['X-Requested-With'])){ + return false; + }else{ + $data = $request->cookie['X-Requested-With']; + try { + + $data = JWT::decode($data, new Key($_ENV["GEMSTONE_SECRET"], $_ENV["GEMSTONE_ALGO"])); + try { + if (self::userCheck($data, $container) === false){ + return false; + } + return true; + } catch (Exception $e) { + echo $e->getMessage(); + + return false; + } + } catch (Exception $e) { + echo $e->getMessage(); + return false; + } + } + } + + public static function attempt(array|stdClass $data, Responses $responses, Container $container): bool + { + try { + /** + * @var QueryDML $query + */ + $query = $container->get('xgen'); + $result = $query->select()->from('users')->where('email','=', $data->email)->get(); + if (count($result) > 0){ + return password_verify($data->password, $result[0]['password']); + } + + try { + if (self::userCheck($data, $container) === false){ + return false; + } + return true; + } catch (Exception $e) { + return false; + } + } catch (Exception $e) { + return false; + } + } + + /** + * @throws DependencyException + * @throws NotFoundException + * @throws Exception + */ + private static function userCheck(stdClass $user, Container $container): bool + { + $data = get_object_vars($user); + $keys = array_keys($data); + + /** + * @var QueryDML $query + */ + $query = $container->get('xgen'); + $result = $query->select([$keys[0], $keys[1]])->from('users')->where('email', '=', $data['email'])->get(); + if (password_verify($data['password'], $result[0]['password'])){ + return true; + } else { + // User check failed + return false; + } + } + + public static function encode(Responses $responses,stdClass $payload, int $expired): array + { + $data = get_object_vars($payload); + $data['expired'] = time() + $expired; + $token = JWT::encode($data, $_ENV["GEMSTONE_SECRET"], $_ENV["GEMSTONE_ALGO"]); + + $responses->setCookie( + name : "X-Requested-With", + value : $token, + expire : $data['expired'], + path : '/', + domain :'', + secure : false, + httponly : true, + sameSite : 'lax', + priority : '' + ); + return [ + 'Token' => $token, + 'Expired' => $data['expired'] + ]; + } + + public static function getData(Request $request): false|stdClass + { + $data = $request->header['Authorization']; + try { + return JWT::decode($data, new Key($_ENV["GEMSTONE_SECRET"], $_ENV["GEMSTONE_ALGO"])); + }catch (Exception $e){ + return false; + } + } +} \ No newline at end of file diff --git a/devise/Service/Middleware/Auth.php b/devise/Service/Middleware/Auth.php deleted file mode 100755 index f8aeb21..0000000 --- a/devise/Service/Middleware/Auth.php +++ /dev/null @@ -1,16 +0,0 @@ -handle($request); - return $request->withStatus(200); - } -} diff --git a/devise/Service/Middleware/AuthMiddleware.php b/devise/Service/Middleware/AuthMiddleware.php new file mode 100644 index 0000000..6bfb976 --- /dev/null +++ b/devise/Service/Middleware/AuthMiddleware.php @@ -0,0 +1,24 @@ +container) === false){ + $response->setStatusCode(401); + $response->end(); + } + $handler->handle($request); + } +} \ No newline at end of file diff --git a/devise/Service/Middleware/CorsMiddleware.php b/devise/Service/Middleware/CorsMiddleware.php old mode 100644 new mode 100755 index 54c6dad..7faedfd --- a/devise/Service/Middleware/CorsMiddleware.php +++ b/devise/Service/Middleware/CorsMiddleware.php @@ -1,19 +1,30 @@ handle($request); - return $response - ->withHeader('Access-Control-Allow-Origin', '*') - ->withHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE OPTIONS') - ->withHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization'); + $origin = $request->header['origin'] ?? '*'; // Allow any origin (less secure) + $response->header('Access-Control-Allow-Origin', $origin); + $response->header('Access-Control-Allow-Credentials', 'true'); + $response->header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS'); + $response->header('Access-Control-Allow-Headers', 'Content-Type, Authorization, Origin, X-GEMSTONE-AUTH'); + $response->header('Access-Control-Max-Age', 86400); + + if ($request->getMethod() == 'OPTIONS') { + $response->status(200); + $response->end(); + return; + } + + $handler->handle($request); } -} \ No newline at end of file +} diff --git a/devise/Service/Middleware/CsrfMiddleware.php b/devise/Service/Middleware/CsrfMiddleware.php deleted file mode 100644 index 3d6d453..0000000 --- a/devise/Service/Middleware/CsrfMiddleware.php +++ /dev/null @@ -1,8 +0,0 @@ -sanitizeData(); + + $this->return + ->workSpace(function (Responses $responses) use ($sanitize){ + if (GemstoneAuthorization::attempt($sanitize, $responses,$this->container)){ + $payload = GemstoneAuthorization::encode(responses: $responses,payload: $sanitize, expired: 3600); + $responses->json($payload, false, 201); + + } + $responses->json('not valid user', false, 401); + }); + } + + #[GET("/async")] + public function test(){ + $this->return + ->doProcess(function(){ + echo "hello"; + }) + ->afterExecute('test') + ->dispatch(); + } + + /** + * @throws DependencyException + * @throws NotFoundException + */ + #[GET("/protected", [AuthMiddleware::class])] + public function protectedSource(): void + { + $this->return + ->workSpace(function (Responses $responses){ + $responses->json('valid user', false, 200); + }); + } + + +} diff --git a/devise/Service/RestApi/Gemstone/DataProcessor.php b/devise/Service/RestApi/Gemstone/DataProcessor.php deleted file mode 100644 index 0a0dcf2..0000000 --- a/devise/Service/RestApi/Gemstone/DataProcessor.php +++ /dev/null @@ -1,51 +0,0 @@ -parser($serverRequest); - if($data !== false){ - return $data; - } - throw new Exception('Content is not valid'); - } - - /** - * @throws Exception - */ - private function parser(ServerRequestInterface $serverRequest): mixed - { - $contentType = $serverRequest->getHeaderLine('Content-Type'); - switch ($contentType){ - case "application/x-www-form-urlencoded" : - parse_str($serverRequest->getBody()->getContents(), $Content); - $sanitizedData = []; - foreach ($Content as $key => $value) { - $sanitizedData[$key] = htmlspecialchars($value, ENT_QUOTES | ENT_HTML5, 'UTF-8'); - } - return (object)$sanitizedData; - case "application/json" : - $data = json_decode($serverRequest->getBody()->getContents(), true); - if (is_array($data)) { - array_walk_recursive($data, function (&$value) { - $value = filter_var($value, FILTER_SANITIZE_SPECIAL_CHARS); - }); - } elseif (is_scalar($data)) { - $data = filter_var($data, FILTER_SANITIZE_SPECIAL_CHARS); - } - return (object)$data; - default : - return false; - } - } -} \ No newline at end of file diff --git a/devise/Service/RestApi/Service.php b/devise/Service/RestApi/Service.php index 64d399f..3a9b6c2 100644 --- a/devise/Service/RestApi/Service.php +++ b/devise/Service/RestApi/Service.php @@ -1,128 +1,32 @@ getQueryBuilder() - ->select() - ->from('projects') - ->get(); - - return $this->serverResponse->json($result, 200); - } - - /** - * @throws DependencyException - * @throws NotFoundException - * @throws Exception - */ - #[POST("/create")] - public function insert(): ResponseInterface - { - try { - // ? Model sanitize special char to prevent xss - $data = $this - ->sanitizeData($this->serverRequest); - - // ? GET Data - $this->getQueryBuilder()->insert('projects',[ - "name" => $data->name - ])->run(); - - - }catch (Exception $e){ - return $this->serverResponse->json(["error" => $e->getMessage(), "errorCode" => $e->getCode()], 422); - } - return $this->serverResponse->json(["message" => "data success inserted", "status" => true], 201); - } - - /** - * @throws DependencyException - * @throws NotFoundException - * @throws Exception - */ - #[GET("/userById/{id}")] - public function readById(int $id): ResponseInterface + public function index():void { - $users = $this - ->getQueryBuilder() - ->select() - ->from('project')->where('id', '=', $id) - ->get(); + $this->return + ->workSpace(function (Responses $response){ + $response->Display('landing.php'); + }); + - return $this->serverResponse->json($users, 200); } - /** - * @param int $id - * @return ResponseInterface - * @throws DependencyException - * @throws NotFoundException - */ - #[PUT('/update/{id}')] - public function renew(int $id): ResponseInterface - { - parse_str($this->serverRequest->getBody()->getContents(), $data); - - try { - // ? GET Data - $this->getQueryBuilder() - ->update - ( - 'users', - [ - 'fullname' => $data['fullname'], - 'email' => $data['email'], - 'password' => $data['password'], - 'date_of_birth' => $data['date_of_birth'], - 'gender' => $data['gender'], - 'contact' => $data['contact'], - 'religion' => $data['religion'], - ] - )->where('id', '=', $id) - ->run(); - }catch (Exception $e){ - return $this->serverResponse->json(["error" => $e->getMessage(), "errorCode" => $e->getCode()], 422); - } - return $this->serverResponse->json(["message" => "success updated"], 200); - } - - /** - * @param int $id - * @return ResponseInterface - * @throws DependencyException - * @throws NotFoundException - */ - #[DELETE("/delete/{id}")] - public function remove(int $id): ResponseInterface - { - try { - // ? GET Data - $this->getQueryBuilder() - ->delete('users') - ->where('id', '=', $id) - ->run(); - }catch (Exception $e){ - return $this->serverResponse->json(["error" => $e->getMessage(), "errorCode" => $e->getCode()], 422); - } - return $this->serverResponse->json(["message" => "success updated"], 200); + #[GET("/auth")] + public function landing(){ + $this->return + ->workSpace(function (Responses $response){ + $response->Display('auth/auth.php'); + }); } -} \ No newline at end of file +} diff --git a/devise/Service/RestApi/sample.php b/devise/Service/RestApi/sample.php new file mode 100755 index 0000000..f62cabe --- /dev/null +++ b/devise/Service/RestApi/sample.php @@ -0,0 +1,52 @@ +sanitizeData(); + $this->return->workSpace(function(Responses $responses)use($sanitized){ + var_dump($sanitized); + }); + } + + #[GET("/rate-limit/{id}")] + public function rateLimit($id): void + { + $this->return->workSpace(function(Responses $responses)use($id){ + var_dump($id); + }); + } + + #[GET("/query")] + public function query(): void + { + $this->return->workSpace(function(Responses $responses, QueryDML $queryDML){ + $result = $queryDML->select(['id', 'email'])->from('users')->get(); + $responses->json($result, false, 200); + }); + } + + #[GET("/query-bunch")] + public function queryBunch(): void + { + $this->return->workSpace(function(Responses $responses, QueryDML $queryDML){ + $result = $queryDML->select(['id', 'email'])->from('users')->get(); + $responses->json($result, false, 200); + }); + } +} diff --git a/migration/m_20240329_192232_users_roles.php b/migration/a_users_roles.php similarity index 59% rename from migration/m_20240329_192232_users_roles.php rename to migration/a_users_roles.php index 4b123f8..92f8c43 100755 --- a/migration/m_20240329_192232_users_roles.php +++ b/migration/a_users_roles.php @@ -5,19 +5,19 @@ use Xel\DB\QueryBuilder\Migration\Schema; use Xel\DB\QueryBuilder\Migration\TableBuilder; -class m_20240329_192232_users_roles extends Migration +class a_users_roles extends Migration { /** * @throws Exception */ public function up(): void { - Schema::create('m_20240329_192232_users_roles',function (TableBuilder $tableBuilder){ + Schema::create('a_users_roles',function (TableBuilder $tableBuilder){ $tableBuilder->id() ->unsignedINT('user_id') ->unsignedINT('role_id') - ->foreign('user_id','m_20240329_192226_users','id') - ->foreign('role_id','m_20240329_192231_roles','id'); + ->foreign('user_id','users','id') + ->foreign('role_id','roles','id'); })->execute(); } @@ -26,6 +26,6 @@ public function up(): void */ public function down(): void { - Schema::drop('m_20240329_192232_users_roles'); + Schema::drop('a_users_roles'); } } diff --git a/migration/m_20240329_192231_roles.php b/migration/roles.php similarity index 70% rename from migration/m_20240329_192231_roles.php rename to migration/roles.php index 116e737..b6b53b9 100755 --- a/migration/m_20240329_192231_roles.php +++ b/migration/roles.php @@ -5,14 +5,14 @@ use Xel\DB\QueryBuilder\Migration\Schema; use Xel\DB\QueryBuilder\Migration\TableBuilder; -class m_20240329_192231_roles extends Migration +class roles extends Migration { /** * @throws Exception */ public function up(): void { - Schema::create('m_20240329_192231_roles',function (TableBuilder $tableBuilder){ + Schema::create('roles',function (TableBuilder $tableBuilder){ $tableBuilder->id() ->string('name'); })->execute(); @@ -23,6 +23,6 @@ public function up(): void */ public function down(): void { - Schema::drop('m_20240329_192231_roles'); + Schema::drop('roles'); } } diff --git a/migration/m_20240329_192226_users.php b/migration/users.php similarity index 73% rename from migration/m_20240329_192226_users.php rename to migration/users.php index 3b6f7ec..173f88a 100755 --- a/migration/m_20240329_192226_users.php +++ b/migration/users.php @@ -6,14 +6,14 @@ use Xel\DB\QueryBuilder\Migration\TableBuilder; use function DI\string; -class m_20240329_192226_users extends Migration +class users extends Migration { /** * @throws Exception */ public function up(): void { - Schema::create('m_20240329_192226_users',function (TableBuilder $tableBuilder){ + Schema::create('users',function (TableBuilder $tableBuilder){ $tableBuilder->id() ->string('name') ->string('email'); @@ -25,6 +25,6 @@ public function up(): void */ public function down(): void { - Schema::drop('m_20240329_192226_users'); + Schema::drop('users'); } } diff --git a/public/css/input.css b/public/css/input.css new file mode 100644 index 0000000..bd6213e --- /dev/null +++ b/public/css/input.css @@ -0,0 +1,3 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; \ No newline at end of file diff --git a/public/css/output.css b/public/css/output.css new file mode 100644 index 0000000..cb58648 --- /dev/null +++ b/public/css/output.css @@ -0,0 +1,1229 @@ +/* +! tailwindcss v3.4.3 | MIT License | https://tailwindcss.com +*/ + +/* +1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4) +2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116) +*/ + +*, +::before, +::after { + box-sizing: border-box; + /* 1 */ + border-width: 0; + /* 2 */ + border-style: solid; + /* 2 */ + border-color: #e5e7eb; + /* 2 */ +} + +::before, +::after { + --tw-content: ''; +} + +/* +1. Use a consistent sensible line-height in all browsers. +2. Prevent adjustments of font size after orientation changes in iOS. +3. Use a more readable tab size. +4. Use the user's configured `sans` font-family by default. +5. Use the user's configured `sans` font-feature-settings by default. +6. Use the user's configured `sans` font-variation-settings by default. +7. Disable tap highlights on iOS +*/ + +html, +:host { + line-height: 1.5; + /* 1 */ + -webkit-text-size-adjust: 100%; + /* 2 */ + -moz-tab-size: 4; + /* 3 */ + -o-tab-size: 4; + tab-size: 4; + /* 3 */ + font-family: Roboto, ui-sans-serif, system-ui, -apple-system, system-ui, Segoe UI, Roboto, Helvetica Neue, Arial, Noto Sans, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol, Noto Color Emoji; + /* 4 */ + font-feature-settings: normal; + /* 5 */ + font-variation-settings: normal; + /* 6 */ + -webkit-tap-highlight-color: transparent; + /* 7 */ +} + +/* +1. Remove the margin in all browsers. +2. Inherit line-height from `html` so users can set them as a class directly on the `html` element. +*/ + +body { + margin: 0; + /* 1 */ + line-height: inherit; + /* 2 */ +} + +/* +1. Add the correct height in Firefox. +2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655) +3. Ensure horizontal rules are visible by default. +*/ + +hr { + height: 0; + /* 1 */ + color: inherit; + /* 2 */ + border-top-width: 1px; + /* 3 */ +} + +/* +Add the correct text decoration in Chrome, Edge, and Safari. +*/ + +abbr:where([title]) { + -webkit-text-decoration: underline dotted; + text-decoration: underline dotted; +} + +/* +Remove the default font size and weight for headings. +*/ + +h1, +h2, +h3, +h4, +h5, +h6 { + font-size: inherit; + font-weight: inherit; +} + +/* +Reset links to optimize for opt-in styling instead of opt-out. +*/ + +a { + color: inherit; + text-decoration: inherit; +} + +/* +Add the correct font weight in Edge and Safari. +*/ + +b, +strong { + font-weight: bolder; +} + +/* +1. Use the user's configured `mono` font-family by default. +2. Use the user's configured `mono` font-feature-settings by default. +3. Use the user's configured `mono` font-variation-settings by default. +4. Correct the odd `em` font sizing in all browsers. +*/ + +code, +kbd, +samp, +pre { + font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; + /* 1 */ + font-feature-settings: normal; + /* 2 */ + font-variation-settings: normal; + /* 3 */ + font-size: 1em; + /* 4 */ +} + +/* +Add the correct font size in all browsers. +*/ + +small { + font-size: 80%; +} + +/* +Prevent `sub` and `sup` elements from affecting the line height in all browsers. +*/ + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sub { + bottom: -0.25em; +} + +sup { + top: -0.5em; +} + +/* +1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297) +2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016) +3. Remove gaps between table borders by default. +*/ + +table { + text-indent: 0; + /* 1 */ + border-color: inherit; + /* 2 */ + border-collapse: collapse; + /* 3 */ +} + +/* +1. Change the font styles in all browsers. +2. Remove the margin in Firefox and Safari. +3. Remove default padding in all browsers. +*/ + +button, +input, +optgroup, +select, +textarea { + font-family: inherit; + /* 1 */ + font-feature-settings: inherit; + /* 1 */ + font-variation-settings: inherit; + /* 1 */ + font-size: 100%; + /* 1 */ + font-weight: inherit; + /* 1 */ + line-height: inherit; + /* 1 */ + letter-spacing: inherit; + /* 1 */ + color: inherit; + /* 1 */ + margin: 0; + /* 2 */ + padding: 0; + /* 3 */ +} + +/* +Remove the inheritance of text transform in Edge and Firefox. +*/ + +button, +select { + text-transform: none; +} + +/* +1. Correct the inability to style clickable types in iOS and Safari. +2. Remove default button styles. +*/ + +button, +input:where([type='button']), +input:where([type='reset']), +input:where([type='submit']) { + -webkit-appearance: button; + /* 1 */ + background-color: transparent; + /* 2 */ + background-image: none; + /* 2 */ +} + +/* +Use the modern Firefox focus style for all focusable elements. +*/ + +:-moz-focusring { + outline: auto; +} + +/* +Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737) +*/ + +:-moz-ui-invalid { + box-shadow: none; +} + +/* +Add the correct vertical alignment in Chrome and Firefox. +*/ + +progress { + vertical-align: baseline; +} + +/* +Correct the cursor style of increment and decrement buttons in Safari. +*/ + +::-webkit-inner-spin-button, +::-webkit-outer-spin-button { + height: auto; +} + +/* +1. Correct the odd appearance in Chrome and Safari. +2. Correct the outline style in Safari. +*/ + +[type='search'] { + -webkit-appearance: textfield; + /* 1 */ + outline-offset: -2px; + /* 2 */ +} + +/* +Remove the inner padding in Chrome and Safari on macOS. +*/ + +::-webkit-search-decoration { + -webkit-appearance: none; +} + +/* +1. Correct the inability to style clickable types in iOS and Safari. +2. Change font properties to `inherit` in Safari. +*/ + +::-webkit-file-upload-button { + -webkit-appearance: button; + /* 1 */ + font: inherit; + /* 2 */ +} + +/* +Add the correct display in Chrome and Safari. +*/ + +summary { + display: list-item; +} + +/* +Removes the default spacing and border for appropriate elements. +*/ + +blockquote, +dl, +dd, +h1, +h2, +h3, +h4, +h5, +h6, +hr, +figure, +p, +pre { + margin: 0; +} + +fieldset { + margin: 0; + padding: 0; +} + +legend { + padding: 0; +} + +ol, +ul, +menu { + list-style: none; + margin: 0; + padding: 0; +} + +/* +Reset default styling for dialogs. +*/ + +dialog { + padding: 0; +} + +/* +Prevent resizing textareas horizontally by default. +*/ + +textarea { + resize: vertical; +} + +/* +1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300) +2. Set the default placeholder color to the user's configured gray 400 color. +*/ + +input::-moz-placeholder, textarea::-moz-placeholder { + opacity: 1; + /* 1 */ + color: #9ca3af; + /* 2 */ +} + +input::placeholder, +textarea::placeholder { + opacity: 1; + /* 1 */ + color: #9ca3af; + /* 2 */ +} + +/* +Set the default cursor for buttons. +*/ + +button, +[role="button"] { + cursor: pointer; +} + +/* +Make sure disabled buttons don't get the pointer cursor. +*/ + +:disabled { + cursor: default; +} + +/* +1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14) +2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210) + This can trigger a poorly considered lint error in some tools but is included by design. +*/ + +img, +svg, +video, +canvas, +audio, +iframe, +embed, +object { + display: block; + /* 1 */ + vertical-align: middle; + /* 2 */ +} + +/* +Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14) +*/ + +img, +video { + max-width: 100%; + height: auto; +} + +/* Make elements with the HTML hidden attribute stay hidden by default */ + +[hidden] { + display: none; +} + +*, ::before, ::after { + --tw-border-spacing-x: 0; + --tw-border-spacing-y: 0; + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + --tw-pan-x: ; + --tw-pan-y: ; + --tw-pinch-zoom: ; + --tw-scroll-snap-strictness: proximity; + --tw-gradient-from-position: ; + --tw-gradient-via-position: ; + --tw-gradient-to-position: ; + --tw-ordinal: ; + --tw-slashed-zero: ; + --tw-numeric-figure: ; + --tw-numeric-spacing: ; + --tw-numeric-fraction: ; + --tw-ring-inset: ; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: rgb(59 130 246 / 0.5); + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + --tw-blur: ; + --tw-brightness: ; + --tw-contrast: ; + --tw-grayscale: ; + --tw-hue-rotate: ; + --tw-invert: ; + --tw-saturate: ; + --tw-sepia: ; + --tw-drop-shadow: ; + --tw-backdrop-blur: ; + --tw-backdrop-brightness: ; + --tw-backdrop-contrast: ; + --tw-backdrop-grayscale: ; + --tw-backdrop-hue-rotate: ; + --tw-backdrop-invert: ; + --tw-backdrop-opacity: ; + --tw-backdrop-saturate: ; + --tw-backdrop-sepia: ; + --tw-contain-size: ; + --tw-contain-layout: ; + --tw-contain-paint: ; + --tw-contain-style: ; +} + +::backdrop { + --tw-border-spacing-x: 0; + --tw-border-spacing-y: 0; + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + --tw-pan-x: ; + --tw-pan-y: ; + --tw-pinch-zoom: ; + --tw-scroll-snap-strictness: proximity; + --tw-gradient-from-position: ; + --tw-gradient-via-position: ; + --tw-gradient-to-position: ; + --tw-ordinal: ; + --tw-slashed-zero: ; + --tw-numeric-figure: ; + --tw-numeric-spacing: ; + --tw-numeric-fraction: ; + --tw-ring-inset: ; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: rgb(59 130 246 / 0.5); + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + --tw-blur: ; + --tw-brightness: ; + --tw-contrast: ; + --tw-grayscale: ; + --tw-hue-rotate: ; + --tw-invert: ; + --tw-saturate: ; + --tw-sepia: ; + --tw-drop-shadow: ; + --tw-backdrop-blur: ; + --tw-backdrop-brightness: ; + --tw-backdrop-contrast: ; + --tw-backdrop-grayscale: ; + --tw-backdrop-hue-rotate: ; + --tw-backdrop-invert: ; + --tw-backdrop-opacity: ; + --tw-backdrop-saturate: ; + --tw-backdrop-sepia: ; + --tw-contain-size: ; + --tw-contain-layout: ; + --tw-contain-paint: ; + --tw-contain-style: ; +} + +.container { + width: 100%; +} + +@media (min-width: 640px) { + .container { + max-width: 640px; + } +} + +@media (min-width: 768px) { + .container { + max-width: 768px; + } +} + +@media (min-width: 1024px) { + .container { + max-width: 1024px; + } +} + +@media (min-width: 1280px) { + .container { + max-width: 1280px; + } +} + +@media (min-width: 1536px) { + .container { + max-width: 1536px; + } +} + +.sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border-width: 0; +} + +.order-1 { + order: 1; +} + +.order-2 { + order: 2; +} + +.m-4 { + margin: 1rem; +} + +.mx-auto { + margin-left: auto; + margin-right: auto; +} + +.mb-2 { + margin-bottom: 0.5rem; +} + +.mb-4 { + margin-bottom: 1rem; +} + +.mb-6 { + margin-bottom: 1.5rem; +} + +.mb-8 { + margin-bottom: 2rem; +} + +.ml-2 { + margin-left: 0.5rem; +} + +.mr-4 { + margin-right: 1rem; +} + +.mt-3 { + margin-top: 0.75rem; +} + +.mt-4 { + margin-top: 1rem; +} + +.mt-6 { + margin-top: 1.5rem; +} + +.block { + display: block; +} + +.flex { + display: flex; +} + +.inline-flex { + display: inline-flex; +} + +.grid { + display: grid; +} + +.hidden { + display: none; +} + +.h-10 { + height: 2.5rem; +} + +.h-4 { + height: 1rem; +} + +.h-5 { + height: 1.25rem; +} + +.h-8 { + height: 2rem; +} + +.h-auto { + height: auto; +} + +.min-h-screen { + min-height: 100vh; +} + +.w-10 { + width: 2.5rem; +} + +.w-4 { + width: 1rem; +} + +.w-5 { + width: 1.25rem; +} + +.w-8 { + width: 2rem; +} + +.w-full { + width: 100%; +} + +.max-w-md { + max-width: 28rem; +} + +.max-w-screen-xl { + max-width: 1280px; +} + +.transform { + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); +} + +.grid-cols-1 { + grid-template-columns: repeat(1, minmax(0, 1fr)); +} + +.flex-col { + flex-direction: column; +} + +.flex-wrap { + flex-wrap: wrap; +} + +.items-start { + align-items: flex-start; +} + +.items-center { + align-items: center; +} + +.justify-center { + justify-content: center; +} + +.justify-between { + justify-content: space-between; +} + +.gap-6 { + gap: 1.5rem; +} + +.gap-8 { + gap: 2rem; +} + +.space-x-3 > :not([hidden]) ~ :not([hidden]) { + --tw-space-x-reverse: 0; + margin-right: calc(0.75rem * var(--tw-space-x-reverse)); + margin-left: calc(0.75rem * calc(1 - var(--tw-space-x-reverse))); +} + +.space-y-4 > :not([hidden]) ~ :not([hidden]) { + --tw-space-y-reverse: 0; + margin-top: calc(1rem * calc(1 - var(--tw-space-y-reverse))); + margin-bottom: calc(1rem * var(--tw-space-y-reverse)); +} + +.self-center { + align-self: center; +} + +.whitespace-nowrap { + white-space: nowrap; +} + +.rounded { + border-radius: 0.25rem; +} + +.rounded-lg { + border-radius: 0.5rem; +} + +.rounded-md { + border-radius: 0.375rem; +} + +.border { + border-width: 1px; +} + +.border-2 { + border-width: 2px; +} + +.border-gray-300 { + --tw-border-opacity: 1; + border-color: rgb(209 213 219 / var(--tw-border-opacity)); +} + +.border-purple-xel { + --tw-border-opacity: 1; + border-color: rgb(78 89 140 / var(--tw-border-opacity)); +} + +.bg-blue-500 { + --tw-bg-opacity: 1; + background-color: rgb(59 130 246 / var(--tw-bg-opacity)); +} + +.bg-blue-600 { + --tw-bg-opacity: 1; + background-color: rgb(37 99 235 / var(--tw-bg-opacity)); +} + +.bg-blue-700 { + --tw-bg-opacity: 1; + background-color: rgb(29 78 216 / var(--tw-bg-opacity)); +} + +.bg-gray-100 { + --tw-bg-opacity: 1; + background-color: rgb(243 244 246 / var(--tw-bg-opacity)); +} + +.bg-gray-50 { + --tw-bg-opacity: 1; + background-color: rgb(249 250 251 / var(--tw-bg-opacity)); +} + +.bg-gray-500 { + --tw-bg-opacity: 1; + background-color: rgb(107 114 128 / var(--tw-bg-opacity)); +} + +.bg-green-500 { + --tw-bg-opacity: 1; + background-color: rgb(34 197 94 / var(--tw-bg-opacity)); +} + +.bg-orange-xel { + --tw-bg-opacity: 1; + background-color: rgb(249 199 132 / var(--tw-bg-opacity)); +} + +.bg-purple-xel { + --tw-bg-opacity: 1; + background-color: rgb(78 89 140 / var(--tw-bg-opacity)); +} + +.bg-white { + --tw-bg-opacity: 1; + background-color: rgb(255 255 255 / var(--tw-bg-opacity)); +} + +.bg-white-xel { + --tw-bg-opacity: 1; + background-color: rgb(255 255 255 / var(--tw-bg-opacity)); +} + +.p-2 { + padding: 0.5rem; +} + +.p-4 { + padding: 1rem; +} + +.p-6 { + padding: 1.5rem; +} + +.p-8 { + padding: 2rem; +} + +.px-3 { + padding-left: 0.75rem; + padding-right: 0.75rem; +} + +.px-4 { + padding-left: 1rem; + padding-right: 1rem; +} + +.px-6 { + padding-left: 1.5rem; + padding-right: 1.5rem; +} + +.px-8 { + padding-left: 2rem; + padding-right: 2rem; +} + +.py-10 { + padding-top: 2.5rem; + padding-bottom: 2.5rem; +} + +.py-12 { + padding-top: 3rem; + padding-bottom: 3rem; +} + +.py-2 { + padding-top: 0.5rem; + padding-bottom: 0.5rem; +} + +.py-3 { + padding-top: 0.75rem; + padding-bottom: 0.75rem; +} + +.text-center { + text-align: center; +} + +.text-2xl { + font-size: 1.5rem; + line-height: 2rem; +} + +.text-3xl { + font-size: 1.875rem; + line-height: 2.25rem; +} + +.text-4xl { + font-size: 2.25rem; + line-height: 2.5rem; +} + +.text-lg { + font-size: 1.125rem; + line-height: 1.75rem; +} + +.text-sm { + font-size: 0.875rem; + line-height: 1.25rem; +} + +.font-bold { + font-weight: 700; +} + +.font-medium { + font-weight: 500; +} + +.font-semibold { + font-weight: 600; +} + +.text-gray-500 { + --tw-text-opacity: 1; + color: rgb(107 114 128 / var(--tw-text-opacity)); +} + +.text-gray-600 { + --tw-text-opacity: 1; + color: rgb(75 85 99 / var(--tw-text-opacity)); +} + +.text-gray-700 { + --tw-text-opacity: 1; + color: rgb(55 65 81 / var(--tw-text-opacity)); +} + +.text-gray-900 { + --tw-text-opacity: 1; + color: rgb(17 24 39 / var(--tw-text-opacity)); +} + +.text-orange-xel { + --tw-text-opacity: 1; + color: rgb(249 199 132 / var(--tw-text-opacity)); +} + +.text-purple-xel { + --tw-text-opacity: 1; + color: rgb(78 89 140 / var(--tw-text-opacity)); +} + +.text-white { + --tw-text-opacity: 1; + color: rgb(255 255 255 / var(--tw-text-opacity)); +} + +.text-white-xel { + --tw-text-opacity: 1; + color: rgb(255 255 255 / var(--tw-text-opacity)); +} + +.shadow { + --tw-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1); + --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); +} + +.shadow-lg { + --tw-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1); + --tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); +} + +.shadow-md { + --tw-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1); + --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); +} + +.transition { + transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, -webkit-backdrop-filter; + transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter; + transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter, -webkit-backdrop-filter; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-duration: 150ms; +} + +.duration-300 { + transition-duration: 300ms; +} + +.hover\:scale-105:hover { + --tw-scale-x: 1.05; + --tw-scale-y: 1.05; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); +} + +.hover\:bg-blue-600:hover { + --tw-bg-opacity: 1; + background-color: rgb(37 99 235 / var(--tw-bg-opacity)); +} + +.hover\:bg-blue-700:hover { + --tw-bg-opacity: 1; + background-color: rgb(29 78 216 / var(--tw-bg-opacity)); +} + +.hover\:bg-gray-100:hover { + --tw-bg-opacity: 1; + background-color: rgb(243 244 246 / var(--tw-bg-opacity)); +} + +.hover\:bg-gray-600:hover { + --tw-bg-opacity: 1; + background-color: rgb(75 85 99 / var(--tw-bg-opacity)); +} + +.hover\:bg-green-600:hover { + --tw-bg-opacity: 1; + background-color: rgb(22 163 74 / var(--tw-bg-opacity)); +} + +.hover\:bg-orange-600:hover { + --tw-bg-opacity: 1; + background-color: rgb(234 88 12 / var(--tw-bg-opacity)); +} + +.hover\:bg-purple-700:hover { + --tw-bg-opacity: 1; + background-color: rgb(126 34 206 / var(--tw-bg-opacity)); +} + +.hover\:text-orange-600:hover { + --tw-text-opacity: 1; + color: rgb(234 88 12 / var(--tw-text-opacity)); +} + +.hover\:text-orange-xel:hover { + --tw-text-opacity: 1; + color: rgb(249 199 132 / var(--tw-text-opacity)); +} + +.hover\:underline:hover { + text-decoration-line: underline; +} + +.focus\:outline-none:focus { + outline: 2px solid transparent; + outline-offset: 2px; +} + +.focus\:ring-2:focus { + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); +} + +.focus\:ring-gray-200:focus { + --tw-ring-opacity: 1; + --tw-ring-color: rgb(229 231 235 / var(--tw-ring-opacity)); +} + +.focus\:ring-purple-xel:focus { + --tw-ring-opacity: 1; + --tw-ring-color: rgb(78 89 140 / var(--tw-ring-opacity)); +} + +.dark\:border-gray-700:is(.dark *) { + --tw-border-opacity: 1; + border-color: rgb(55 65 81 / var(--tw-border-opacity)); +} + +.dark\:bg-blue-600:is(.dark *) { + --tw-bg-opacity: 1; + background-color: rgb(37 99 235 / var(--tw-bg-opacity)); +} + +.dark\:bg-gray-800:is(.dark *) { + --tw-bg-opacity: 1; + background-color: rgb(31 41 55 / var(--tw-bg-opacity)); +} + +.dark\:text-gray-400:is(.dark *) { + --tw-text-opacity: 1; + color: rgb(156 163 175 / var(--tw-text-opacity)); +} + +.dark\:hover\:bg-gray-700:hover:is(.dark *) { + --tw-bg-opacity: 1; + background-color: rgb(55 65 81 / var(--tw-bg-opacity)); +} + +.dark\:hover\:text-white:hover:is(.dark *) { + --tw-text-opacity: 1; + color: rgb(255 255 255 / var(--tw-text-opacity)); +} + +.dark\:focus\:ring-gray-600:focus:is(.dark *) { + --tw-ring-opacity: 1; + --tw-ring-color: rgb(75 85 99 / var(--tw-ring-opacity)); +} + +@media (min-width: 640px) { + .sm\:mt-0 { + margin-top: 0px; + } + + .sm\:text-center { + text-align: center; + } +} + +@media (min-width: 768px) { + .md\:order-1 { + order: 1; + } + + .md\:order-2 { + order: 2; + } + + .md\:block { + display: block; + } + + .md\:flex { + display: flex; + } + + .md\:grid-cols-2 { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + + .md\:items-center { + align-items: center; + } + + .md\:justify-between { + justify-content: space-between; + } + + .md\:py-20 { + padding-top: 5rem; + padding-bottom: 5rem; + } + + .md\:py-8 { + padding-top: 2rem; + padding-bottom: 2rem; + } + + .md\:text-3xl { + font-size: 1.875rem; + line-height: 2.25rem; + } + + .md\:text-4xl { + font-size: 2.25rem; + line-height: 2.5rem; + } + + .md\:text-5xl { + font-size: 3rem; + line-height: 1; + } + + .md\:dark\:hover\:text-white:hover:is(.dark *) { + --tw-text-opacity: 1; + color: rgb(255 255 255 / var(--tw-text-opacity)); + } +} + +@media (min-width: 1024px) { + .lg\:grid-cols-3 { + grid-template-columns: repeat(3, minmax(0, 1fr)); + } +} + +.rtl\:space-x-reverse:where([dir="rtl"], [dir="rtl"] *) > :not([hidden]) ~ :not([hidden]) { + --tw-space-x-reverse: 1; +} \ No newline at end of file diff --git a/public/css/style.css b/public/css/style.css new file mode 100644 index 0000000..99dec54 --- /dev/null +++ b/public/css/style.css @@ -0,0 +1,3 @@ +h1{ + color: aqua; +} \ No newline at end of file diff --git a/setup/Bootstrap/App.php b/setup/Bootstrap/App.php index 3b1b829..559af79 100644 --- a/setup/Bootstrap/App.php +++ b/setup/Bootstrap/App.php @@ -1,13 +1,12 @@ containerBuilder = $dock->launch(); + $dependency = $dock->launch(); /** * @var array */ - $serverConfig = $this->containerInstance()->get('server'); + $serverConfig = $dependency->get('server'); /** * DOTENV init @@ -47,57 +44,35 @@ public function init(): void $dotenv = Dotenv::createImmutable(__DIR__."/../../"); $dotenv->safeLoad(); - /** - * Logger init - */ - $this->loggerInit(); - - $app = new Applications( - $serverConfig, - $this->routerConfig(), - $this->containerInstance()->get('dbConfig'), - $this->containerInstance() - ); - $app->initialize(); - } - - private function containerInstance(): Container - { - return $this->containerBuilder; - } - /** - * @throws DependencyException - * @throws NotFoundException - */ - private function routerConfig(): ?array - { /** * Router class collection and path */ - $class = $this->containerInstance()->get('ServiceDock'); - $cache = $this->containerInstance()->get('RouterCachePath'); + $class = $dependency->get('ServiceDock'); + $cache = $dependency->get('RouterCachePath'); + $loaderClass = loaderClass($class, $cache, $_ENV['BUILD']); /** - * Load clas and Generate route cache + * Logger init */ + $loggerConfig = $dependency->get('Logging'); + $FireHandler = $dependency->get('FirePHPHandler'); - return loaderClass($class, $cache, $_ENV['BUILD']); - } + ApplicationLogger::init($loggerConfig, $FireHandler); - /** - * @throws DependencyException - * @throws NotFoundException - */ - private function loggerInit(): void - { /** - * Logger Init + * Launch Instance */ - $loggerConfig = $this->containerInstance()->get('Logging'); - $FireHandler = $this->containerInstance()->get('FirePHPHandler'); - - ApplicationLogger::init($loggerConfig, $FireHandler); + $app = new Application_v3( + $serverConfig, + $loaderClass, + $dependency->get('dbConfig'), + $dependency + ); + $app + ->gemstoneLimiter() + ->router() + ->init(); } } \ No newline at end of file diff --git a/setup/Command/CommandRunner.php b/setup/Command/CommandRunner.php index 368ae00..cb12c1a 100644 --- a/setup/Command/CommandRunner.php +++ b/setup/Command/CommandRunner.php @@ -21,9 +21,6 @@ public static function init(Application $app): void $app->run(); } - /** - * @return void - */ private static function makeInstance(): void { $commandList = serviceConsoleRegister(); diff --git a/setup/Config/DBConfig.php b/setup/Config/DBConfig.php index 12a0f84..f8f0c28 100644 --- a/setup/Config/DBConfig.php +++ b/setup/Config/DBConfig.php @@ -5,13 +5,13 @@ 'charset' => 'utf8mb4', 'username' => 'root', 'password' => 'Todokana1ko!', - 'dbname' => 'absensi', + 'dbname' => 'sample', 'options' =>[ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, ], - 'pool' => swoole_cpu_num(), + 'pool' => 10, 'poolMode' => true, 'migration' => "\\Xel\\Migration", diff --git a/setup/Config/Server.php b/setup/Config/Server.php index f015fc3..a31d7c9 100644 --- a/setup/Config/Server.php +++ b/setup/Config/Server.php @@ -3,9 +3,13 @@ 'api_server' => [ 'host' => 'http://localhost', 'port' => 9501, - 'mode' => 2, + 'mode' => 1, 'options' => [ - 'worker_num' => 35, + "enable_static_handler" => true, + "document_root" => dirname(__DIR__, 2), + 'worker_num' => swoole_cpu_num(), +// 'task_worker_num'=>16, + 'task_enable_coroutine' => true, // optional to turn on task coroutine support // 'daemonize' => 1, // 'http_gzip_level' => 9, @@ -20,10 +24,8 @@ 'enable_reuse_port' => true, 'enable_coroutine' => true, 'http_compression' => true, - 'enable_static_handler' => false, 'buffer_output_size' => swoole_cpu_num() * 1024 * 1024, ], ], - ]; diff --git a/setup/Dock/DockEntry.php b/setup/Dock/DockEntry.php index dd8da76..3534f87 100644 --- a/setup/Dock/DockEntry.php +++ b/setup/Dock/DockEntry.php @@ -5,11 +5,12 @@ use Nyholm\Psr7\Factory\Psr17Factory; use Xel\Async\Http\Response; use Xel\Async\Router\RouterRunner; -use Xel\Devise\BaseData\Basedata; -use Xel\Devise\Service\AbstractService; +use Xel\Devise\AbstractService; +use Xel\Devise\Job\test; use function DI\create; use function Xel\Container\dependency\containerEntry; use function Xel\Devise\Service\AppClassBinder\serviceMiddlewareGlobals; +use function Xel\Devise\Service\AppClassBinder\serviceModelRegister; use function Xel\Devise\Service\AppClassBinder\serviceRegister; function DockEntry(): array @@ -17,7 +18,7 @@ function DockEntry(): array $config = require __DIR__ . "/../Config/Server.php"; $logging = require __DIR__."/../Config/Logging.php"; $dbConfig = require __DIR__."/../Config/DBConfig.php"; - + $gemstone = require __DIR__."/../../devise/Service/Gemstone/Gemstone.php"; return containerEntry( [ /** @@ -46,7 +47,6 @@ function DockEntry(): array /** * Http Protocol Container */ - "ServerFactory" => create(Psr17Factory::class), "StreamFactory" => create(Psr17Factory::class), "UploadFactory" => create(Psr17Factory::class), @@ -62,6 +62,27 @@ function DockEntry(): array * Global Middleware */ "GlobalMiddleware" => serviceMiddlewareGlobals(), + + /** + * Job Dispatcher + */ + 'test' => test::class, + + /*** + * Gemstone + */ + 'gemstone' => $gemstone, + + /** + * BaseData + */ + 'basedata' => serviceModelRegister(), + + /** + * Display Path + */ + 'display_path' => __DIR__."/../../devise/Display/", + ] ); } \ No newline at end of file diff --git a/tailwind.config.js b/tailwind.config.js new file mode 100755 index 0000000..6731a23 --- /dev/null +++ b/tailwind.config.js @@ -0,0 +1,56 @@ +/** @type {import('tailwindcss').Config} */ +module.exports = { + content: [ + './devise/Display/*.{html,js,php}', + './devise/Display/auth/*.{html,js,php}', + ], + darkMode: 'class', + theme: { + extend: { + colors: { + 'purple-xel': '#4e598c', + 'white-xel': '#ffffff', + 'orange-xel': '#f9c784', + } + }, + + fontFamily: { + 'body': [ + 'Roboto', + 'ui-sans-serif', + 'system-ui', + '-apple-system', + 'system-ui', + 'Segoe UI', + 'Roboto', + 'Helvetica Neue', + 'Arial', + 'Noto Sans', + 'sans-serif', + 'Apple Color Emoji', + 'Segoe UI Emoji', + 'Segoe UI Symbol', + 'Noto Color Emoji' + ], + 'sans': [ + 'Roboto', + 'ui-sans-serif', + 'system-ui', + '-apple-system', + 'system-ui', + 'Segoe UI', + 'Roboto', + 'Helvetica Neue', + 'Arial', + 'Noto Sans', + 'sans-serif', + 'Apple Color Emoji', + 'Segoe UI Emoji', + 'Segoe UI Symbol', + 'Noto Color Emoji' + ] + } + }, + plugins: [], +} + diff --git a/writeable/Gemstone_log/black_list.php b/writeable/Gemstone_log/black_list.php new file mode 100644 index 0000000..a359f03 --- /dev/null +++ b/writeable/Gemstone_log/black_list.php @@ -0,0 +1,2 @@ + + array ( + 'Uri' => '/create', + 'RequestMethod' => 'POST', + 'Class' => 'Xel\\Devise\\Service\\RestApi\\Service', + 'Method' => 'create', + 'Middlewares' => + array ( + ), + ), + 2 => + array ( + 'Uri' => '/update/{id}', + 'RequestMethod' => 'PUT', + 'Class' => 'Xel\\Devise\\Service\\RestApi\\Service', + 'Method' => 'update', + 'Middlewares' => + array ( + ), + ), + 3 => + array ( + 'Uri' => '/delete/{id}', + 'RequestMethod' => 'DELETE', + 'Class' => 'Xel\\Devise\\Service\\RestApi\\Service', + 'Method' => 'delete', + 'Middlewares' => + array ( + ), + ), ); \ No newline at end of file