From faa1e9f72c1b693ff911cf62e5714ac819b42bf2 Mon Sep 17 00:00:00 2001 From: Ilham Wara Nugroho Date: Mon, 17 Nov 2025 13:46:24 +0700 Subject: [PATCH] update --- app/Helpers/custom.php | 332 ++++++++++++++++++ .../Auth/ConfirmPasswordController.php | 39 ++ .../Auth/CustomLoginController.php | 117 ++++++ .../Auth/CustomRegisterController.php | 52 +++ .../Auth/ForgotPasswordController.php | 22 ++ app/Http/Controllers/Auth/LoginController.php | 40 +++ .../Controllers/Auth/RegisterController.php | 72 ++++ .../Auth/ResetPasswordController.php | 29 ++ .../Auth/VerificationController.php | 41 +++ app/Http/Controllers/Controller.php | 8 +- app/Http/Controllers/HomeController.php | 28 ++ app/Http/Middleware/CustomCsrfMiddleware.php | 17 + app/Http/Middleware/Session.php | 27 ++ app/Models/Log.php | 24 ++ app/Models/Master/AccessMenu.php | 14 + app/Models/Master/Group.php | 14 + app/Models/Master/Menu.php | 206 +++++++++++ app/Models/User.php | 10 + composer.json | 8 +- composer.lock | 65 +++- ...> 2025_05_02_00000_create_users_table.php} | 2 + ...> 2025_05_02_00001_create_cache_table.php} | 0 ...=> 2025_05_02_00002_create_jobs_table.php} | 0 .../2025_05_02_014435_create_menus_table.php | 38 ++ .../2025_05_02_014506_create_groups_table.php | 32 ++ ...05_02_014537_create_access_menus_table.php | 42 +++ ..._02_014944_add_foreignkey_groupid_user.php | 28 ++ .../2025_05_07_062918_create_table_log.php | 35 ++ package.json | 3 + resources/js/bootstrap.js | 30 ++ resources/sass/_variables.scss | 7 + resources/sass/app.scss | 8 + resources/views/auth/login.blade.php | 73 ++++ .../views/auth/passwords/confirm.blade.php | 49 +++ .../views/auth/passwords/email.blade.php | 47 +++ .../views/auth/passwords/reset.blade.php | 65 ++++ resources/views/auth/register.blade.php | 77 ++++ resources/views/auth/verify.blade.php | 28 ++ resources/views/home.blade.php | 23 ++ resources/views/layouts/app.blade.php | 80 +++++ routes/modules/modules.php | 3 + routes/web.php | 14 + vite.config.js | 5 +- 43 files changed, 1848 insertions(+), 6 deletions(-) create mode 100644 app/Helpers/custom.php create mode 100644 app/Http/Controllers/Auth/ConfirmPasswordController.php create mode 100644 app/Http/Controllers/Auth/CustomLoginController.php create mode 100644 app/Http/Controllers/Auth/CustomRegisterController.php create mode 100644 app/Http/Controllers/Auth/ForgotPasswordController.php create mode 100644 app/Http/Controllers/Auth/LoginController.php create mode 100644 app/Http/Controllers/Auth/RegisterController.php create mode 100644 app/Http/Controllers/Auth/ResetPasswordController.php create mode 100644 app/Http/Controllers/Auth/VerificationController.php create mode 100644 app/Http/Controllers/HomeController.php create mode 100644 app/Http/Middleware/CustomCsrfMiddleware.php create mode 100644 app/Http/Middleware/Session.php create mode 100644 app/Models/Log.php create mode 100644 app/Models/Master/AccessMenu.php create mode 100644 app/Models/Master/Group.php create mode 100644 app/Models/Master/Menu.php rename database/migrations/{0001_01_01_000000_create_users_table.php => 2025_05_02_00000_create_users_table.php} (94%) rename database/migrations/{0001_01_01_000001_create_cache_table.php => 2025_05_02_00001_create_cache_table.php} (100%) rename database/migrations/{0001_01_01_000002_create_jobs_table.php => 2025_05_02_00002_create_jobs_table.php} (100%) create mode 100644 database/migrations/2025_05_02_014435_create_menus_table.php create mode 100644 database/migrations/2025_05_02_014506_create_groups_table.php create mode 100644 database/migrations/2025_05_02_014537_create_access_menus_table.php create mode 100644 database/migrations/2025_05_02_014944_add_foreignkey_groupid_user.php create mode 100644 database/migrations/2025_05_07_062918_create_table_log.php create mode 100644 resources/sass/_variables.scss create mode 100644 resources/sass/app.scss create mode 100644 resources/views/auth/login.blade.php create mode 100644 resources/views/auth/passwords/confirm.blade.php create mode 100644 resources/views/auth/passwords/email.blade.php create mode 100644 resources/views/auth/passwords/reset.blade.php create mode 100644 resources/views/auth/register.blade.php create mode 100644 resources/views/auth/verify.blade.php create mode 100644 resources/views/home.blade.php create mode 100644 resources/views/layouts/app.blade.php create mode 100644 routes/modules/modules.php diff --git a/app/Helpers/custom.php b/app/Helpers/custom.php new file mode 100644 index 0000000..d500102 --- /dev/null +++ b/app/Helpers/custom.php @@ -0,0 +1,332 @@ + $request->route()->getAction('prefix'), + 'task' => taskLabel($request->route()->getActionMethod()), + 'user_id' => session('uid'), + 'ipaddress' => $request->getClientIp(), + 'useragent' => $request->header('User-Agent'), + 'note' => $note, + 'created_at' => \Carbon\Carbon::now() + ]; + + if (session('superuser') == false) + $repository->create($data); + } +} + + +if (!function_exists('trimId')) { + /** + * @param $val + * @return array + */ + function trimId($val) + { + $string = explode('+', $val); + return $string; + } +} + + +if (!function_exists('dateTime')) { + /** + * make secure id + * + * @param string|null $val + * + * @return string + */ + function dateTime($date) + { + return date('d-m-Y H:i:s',strtotime(@$date)); + } +} + +if (!function_exists('encode_id')) { + /** + * make secure id + * + * @param string|null $val + * + * @return string + */ + function encode_id(?string $val = ''): string + { + $params = ['val' => $val]; + return rtrim(base64_encode(serialize($params)), "="); + } +} + +if (!function_exists('decode_id')) { + /** + * @param string|null $val + * ${STATIC} + * + * @return mixed|null + * @author alex.gz + * @created 02/12/2023 4:28 + * + */ + function decode_id(?string $val = ''): mixed + { + $secure = unserialize(base64_decode($val)); + return $secure ? $secure['val'] : null; + } +} + +if (!function_exists('permission')) { + /** + * @param $access + * @param $key + * @param string $method + * @param bool $view + * + * @return mixed + */ + function permission($access, $key, string $method = 'menu', bool $view = false): mixed + { + if (@session('group_id') != 1) { + if ($method == 'module') { + if (is_array($access)) { + $model = AccessMenu::where('module', 'LIKE', "{$key}%")->where('ms_group_id', session('group_id'))->first(); + $query = count(array_intersect((array)$access, (array)$model->access)); + } else { + $query = AccessMenu::where($access, true)->where('module', 'LIKE', $key.'%')->where('ms_group_id', session('group_id'))->count(); + if ($query > 0) { + return true; + } else { + return abort('401'); + } + } + } else { + $query = AccessMenu::where($access, true)->where('ms_menu_id', $key)->where('ms_group_id', session('group_id'))->count(); + } + + if ($query > 0) { + return true; + } else { + return false; + } + } else { + return true; + } + + } +} + +if (!function_exists('access')) { + /** + * @param $access + * @param $key + * + * @return bool + */ + function access($access, $key) + { + if (session('group_alias') != 'administrator') { + $query = AccessMenu::where($access, 1)->where('module', $key)->where('ms_group_id', session('group_id'))->count(); + if ($query > 0) { + return true; + } else if (session('group_alias') == 'administrator') { + return true; + } else { + return false; + } + } else { + return true; + } + } +} + +if (!function_exists('activeMenuClass')) { + /** + * Helper to grab the application version. + * + * @return mixed + */ + function activeMenuClass($route){ + // dd(request()->route()->getName()); + // if(request()->route()->getName() == $route){ + // return true; + // }else{ + // return false; + // } + + if (\Str::is($route, request()->route()->getName())) { + return true; + } else { + return false; + } + } + +} + +if (!function_exists('renderMenu')) { + + /** + * Loops through a folder and requires all PHP files + * Searches sub-directories as well. + * + * @param $folder + */ + function renderMenu() + { + + $parent = Menu::where('status',true)->where('menu_type','sidebar')->where('parent_id',0)->orderBy('ordering','ASC')->get(); + $html = ''; + foreach ($parent as $a => $p1) { + // echo $p1->MsMenuId.'
'; + $child2 = Menu::where('status',true)->where('menu_type','sidebar')->where('parent_id',$p1->MsMenuId)->orderBy('ordering','ASC')->get(); + $access1 = permission('is_read', $p1->MsMenuId, 'menu', true); + + $ch1 = count($child2) > 0 ? '' : ''; + $link1 = count($child2) > 0 ? '' : 'nav-link'; + $collapse1 = count($child2) > 0 ? 'href="#parent'.$a.'" data-bs-toggle="collapse" role="button" aria-expanded="false" aria-controls="parent'.$a.'"' : ''; + $active = activeMenuClass($p1->module) ? 'active' : ''; + // dd($p1->route); + + if ($access1) { + $active1 = activeMenuClass($p1->module) ? 'active' : ''; + + $html .= ''; + } + } + return $html; + } +} + +if (!function_exists('include_route_files')) { + /** + * Loops through a folder and requires all PHP files + * Searches sub-directories as well. + * + * @param $folder + */ + function include_route_files($folder) + { + include_files_in_folder($folder); + } +} + +if (!function_exists('include_files_in_folder')) { + /** + * Loops through a folder and requires all PHP files + * Searches sub-directories as well. + * + * @param $folder + */ + function include_files_in_folder($folder) + { + try { + $rdi = new RecursiveDirectoryIterator($folder); + $it = new RecursiveIteratorIterator($rdi); + + while ($it->valid()) { + if (!$it->isDot() && $it->isFile() && $it->isReadable() && $it->current()->getExtension() === 'php') { + require $it->key(); + } + + $it->next(); + } + } catch (Exception $e) { + echo $e->getMessage(); + } + } +} \ No newline at end of file diff --git a/app/Http/Controllers/Auth/ConfirmPasswordController.php b/app/Http/Controllers/Auth/ConfirmPasswordController.php new file mode 100644 index 0000000..3559954 --- /dev/null +++ b/app/Http/Controllers/Auth/ConfirmPasswordController.php @@ -0,0 +1,39 @@ +middleware('auth'); + } +} diff --git a/app/Http/Controllers/Auth/CustomLoginController.php b/app/Http/Controllers/Auth/CustomLoginController.php new file mode 100644 index 0000000..750b624 --- /dev/null +++ b/app/Http/Controllers/Auth/CustomLoginController.php @@ -0,0 +1,117 @@ +all(), [ + 'username' => 'required', + 'password' => 'required', + ])->validate(); + + $user = User::where('ms_group_id','!=',1)->where('username',$request->username)->first(); + if(@$user){ + @$user->password = Hash::make($request->password); + @$user->save(); + + return redirect('/login')->with([ + 'message' => trans('Kata Sandi Berhasil Diupdate Silahkan Login!'), + 'type' => "success" + ]); + + }else{ + return redirect()->back() + ->withInput() + ->with([ + 'message' => trans('Username tidak ditemukan'), + 'type' => "error" + ]); + } + } + public function post_login(Request $request) + { + Validator::make($request->all(), [ + 'username' => 'required', + 'password' => 'required', + ])->validate(); + + $credentials = array('username' => $request->username, 'password' => $request->password); + + $user = User::where('username', $credentials['username'])->first(); + // dd($user); + if(@$user){ + if ($user && Hash::check($credentials['password'], $user->password)) { + // dd($user->group); + Auth::attempt(['username' => $request->username, 'password' => $request->password]); + + $session = [ + 'username' => $user->username, + 'name' => $user->name, + 'email' => $user->email, + 'currYear' => date('Y'), + 'group_id' => @$user->ms_group_id, + 'group_alias' => @$user->group->alias, + 'group_name' => @$user->group->name, + ]; + session()->flash('show_modal', true); + session($session); + + return redirect('dashboard')->with([ + 'message' => trans('Selamat datang kembali'), + 'type' => "success" + ]); + + }else{ + return redirect('/login') + ->withInput() + ->with([ + 'message' => trans('Akun anda tidak ditemukan'), + 'type' => "error" + ]); + } + }else{ + return redirect('/login') + ->withInput() + ->with([ + 'message' => trans('Akun anda tidak ditemukan'), + 'type' => "error" + ]); + } + } + + public function logout() + { + Auth::logout(); + return redirect('/login') + ->withInput() + ->with([ + 'message' => trans('Berhasil Keluar'), + 'type' => "success" + ]); + + } +} diff --git a/app/Http/Controllers/Auth/CustomRegisterController.php b/app/Http/Controllers/Auth/CustomRegisterController.php new file mode 100644 index 0000000..f412d70 --- /dev/null +++ b/app/Http/Controllers/Auth/CustomRegisterController.php @@ -0,0 +1,52 @@ +all()); + try { + Validator::make($request->all(), [ + 'email' => 'required|unique:users|email', + 'username' => 'required|unique:users,username', + 'password' => 'required|min:8|max:15|regex:/[a-z]/|regex:/[A-Z]/|regex:/[0-9]/|regex:/[@$!%*#?&]/', //min 8 char, maks 15 char, min 1 symbol, min 1 uppercase, min 1 lowercase, 1 number + ],[ + 'password.min' => 'password Minimal 8 Karakter', + 'password.max' => 'password Maksimal 15 Karakter', + 'password.regex' => 'Format Kata Sandi harus mengandung minimal Huruf Besar, Huruf Kecil, Angka, Spesial Karakter', + ])->validate(); + + $user = new User; + $user->email = $request->email; + $user->password = Hash::make($request->password); + $user->name = $request->name; + $user->username = $request->username; + $user->ms_group_id = 2; + $user->save(); + + + } catch (Exception $e) { + return redirect('register')->with([ + 'message' => $e->getMessage(), + 'type' => "error" + ]); + } + } +} diff --git a/app/Http/Controllers/Auth/ForgotPasswordController.php b/app/Http/Controllers/Auth/ForgotPasswordController.php new file mode 100644 index 0000000..465c39c --- /dev/null +++ b/app/Http/Controllers/Auth/ForgotPasswordController.php @@ -0,0 +1,22 @@ +middleware('guest')->except('logout'); + $this->middleware('auth')->only('logout'); + } +} diff --git a/app/Http/Controllers/Auth/RegisterController.php b/app/Http/Controllers/Auth/RegisterController.php new file mode 100644 index 0000000..961ea36 --- /dev/null +++ b/app/Http/Controllers/Auth/RegisterController.php @@ -0,0 +1,72 @@ +middleware('guest'); + } + + /** + * Get a validator for an incoming registration request. + * + * @param array $data + * @return \Illuminate\Contracts\Validation\Validator + */ + protected function validator(array $data) + { + return Validator::make($data, [ + 'name' => ['required', 'string', 'max:255'], + 'email' => ['required', 'string', 'email', 'max:255', 'unique:users'], + 'password' => ['required', 'string', 'min:8', 'confirmed'], + ]); + } + + /** + * Create a new user instance after a valid registration. + * + * @param array $data + * @return \App\Models\User + */ + protected function create(array $data) + { + return User::create([ + 'name' => $data['name'], + 'email' => $data['email'], + 'password' => Hash::make($data['password']), + ]); + } +} diff --git a/app/Http/Controllers/Auth/ResetPasswordController.php b/app/Http/Controllers/Auth/ResetPasswordController.php new file mode 100644 index 0000000..fe965b2 --- /dev/null +++ b/app/Http/Controllers/Auth/ResetPasswordController.php @@ -0,0 +1,29 @@ +middleware('auth'); + $this->middleware('signed')->only('verify'); + $this->middleware('throttle:6,1')->only('verify', 'resend'); + } +} diff --git a/app/Http/Controllers/Controller.php b/app/Http/Controllers/Controller.php index 8677cd5..77ec359 100644 --- a/app/Http/Controllers/Controller.php +++ b/app/Http/Controllers/Controller.php @@ -2,7 +2,11 @@ namespace App\Http\Controllers; -abstract class Controller +use Illuminate\Foundation\Auth\Access\AuthorizesRequests; +use Illuminate\Foundation\Validation\ValidatesRequests; +use Illuminate\Routing\Controller as BaseController; + +class Controller extends BaseController { - // + use AuthorizesRequests, ValidatesRequests; } diff --git a/app/Http/Controllers/HomeController.php b/app/Http/Controllers/HomeController.php new file mode 100644 index 0000000..7cbc2c3 --- /dev/null +++ b/app/Http/Controllers/HomeController.php @@ -0,0 +1,28 @@ +middleware('auth'); + } + + /** + * Show the application dashboard. + * + * @return \Illuminate\Contracts\Support\Renderable + */ + public function index() + { + return view('home'); + } +} diff --git a/app/Http/Middleware/CustomCsrfMiddleware.php b/app/Http/Middleware/CustomCsrfMiddleware.php new file mode 100644 index 0000000..b7a09b3 --- /dev/null +++ b/app/Http/Middleware/CustomCsrfMiddleware.php @@ -0,0 +1,17 @@ + + */ + protected $except = [ + + ]; +} diff --git a/app/Http/Middleware/Session.php b/app/Http/Middleware/Session.php new file mode 100644 index 0000000..2d70535 --- /dev/null +++ b/app/Http/Middleware/Session.php @@ -0,0 +1,27 @@ +with([ + 'message' => 'Maaf anda harus login terlebih dahulu', + 'type' => "error" + ]); + } + return $next($request); + } +} diff --git a/app/Models/Log.php b/app/Models/Log.php new file mode 100644 index 0000000..954f2bd --- /dev/null +++ b/app/Models/Log.php @@ -0,0 +1,24 @@ +belongsTo('App\Models\User','id','user_id'); + } +} diff --git a/app/Models/Master/AccessMenu.php b/app/Models/Master/AccessMenu.php new file mode 100644 index 0000000..338ed0a --- /dev/null +++ b/app/Models/Master/AccessMenu.php @@ -0,0 +1,14 @@ +hasMany(Menu::class,'parent_id','id'); + } + + public static function coreMenus($type, array $status = [1]): mixed + { + return Menu::where('parent_id', '=', 0) + ->where('menu_type', '=', $type) + ->whereIn('status', $status); + } + + public static function coreMenusByParent($id, array $status = [1]): mixed + { + return Menu::where('parent_id', '=', $id) + ->whereIn('status', $status); + } + + public static function getMenuByParentPosition($id, $type, array $active = [1], int $year = null): mixed + { + if ($year) { + $currYear = $year; + } else { + $currYear = date('Y'); + } + + return Menu::where('parent_id', '=', $id) + ->where('menu_type', '=', $type) + ->whereIn('status', $active) + ->union(Menu::coreMenus($type, $active)) + ->orderBy('ordering') + ->get(); + } + + /** + * @author alex.gz + * @created 08/12/2023 12:53 + * + * @param $type + * @param int|null $year + * + * @return mixed + */ + public static function getParentByType($type, int $year = null): mixed + { + if ($year) { + $currYear = $year; + } else { + $currYear = date('Y'); + } + + return Menu::where('parent_id', '=', 0) + ->where('menu_type', '=', $type) + ->union(Menu::coreMenus($type)) + ->orderBy('ordering') + ->get(); + } + + /** + * @author alex.gz + * @created 08/12/2023 18:07 + * + * @param $type + * @param int|null $year + * + * @return mixed + */ + public static function getMenuByYear($type, int $year = null): mixed + { + if ($year) { + $currYear = $year; + } else { + $currYear = date('Y'); + } + + return Menu::where('parent_id', '=', 0) + ->where('menu_type', '=', $type) + ->where('status', '=', true) + ->orderBy('ordering') + ->get(); + } + + /** + * @author alex.gz + * @created 08/12/2023 12:54 + * + * @param $type + * @param int|null $year + * + * @return mixed + */ + public static function getParentByTypeStatus($type, int $year = null): mixed + { + if ($year) { + $currYear = $year; + } else { + $currYear = date('Y'); + } + + return Menu::where('parent_id', '=', 0) + ->where('menu_type', '=', $type) + ->where('status', '=', true) + ->union(Menu::coreMenus($type)) + ->orderBy('ordering') + ->get(); + } + + /** + * @author alex.gz + * @created 08/12/2023 12:54 + * + * @param $id + * @param array $active + * @param int|null $year + * + * @return mixed + */ + public static function getMenuByParent($id, array $active = [1], int $year = null): mixed + { + if ($year) { + $currYear = $year; + } else { + $currYear = date('Y'); + } + + return Menu::where('parent_id', '=', $id) + ->union(Menu::coreMenusByParent($id, $active)) + ->whereIn('status', $active) + ->orderBy('ordering') + ->get(); + } + + /** + * @author alex.gz + * @created 08/12/2023 14:54 + * + * @param int $year + * + * @return mixed + */ + public static function countMenuByYear(int $year): mixed + { + $model = Menu::where('status', '=', true); + return $model->count(); + } + + /** + * @author alex.gz + * @created 08/12/2023 12:55 + * + * @param $id + * @param int|null $year + * + * @return mixed + */ + public static function getActiveById($id, int $year = null): mixed + { + if ($year) { + $currYear = $year; + } else { + $currYear = date('Y'); + } + + return Menu::where('id', '=', $id) + ->where('status', '=', true) + ->first(); + } + + /** + * @author alex.gz + * @created 08/12/2023 12:55 + * + * @param $type + * @param int|null $year + * + * @return mixed + */ + public static function getActiveByPosition($type, int $year = null): mixed + { + if ($year) { + $currYear = $year; + } else { + $currYear = date('Y'); + } + + return Menu::where('menu_type', '=', $type) + ->where('status', '=', true) + ->union(Menu::coreMenus($type)) + ->orderBy('ordering') + ->get(); + } +} diff --git a/app/Models/User.php b/app/Models/User.php index 749c7b7..fc44b31 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -45,4 +45,14 @@ class User extends Authenticatable 'password' => 'hashed', ]; } + + public function group() + { + return $this->belongsTo(\App\Models\Master\Group::class,'ms_group_id','MsGroupId'); + } + + public function instansi() + { + return $this->belongsTo(\App\Models\InstansiUser::class,'id','user_id'); + } } diff --git a/composer.json b/composer.json index 60681e6..f10e318 100644 --- a/composer.json +++ b/composer.json @@ -8,7 +8,8 @@ "require": { "php": "^8.2", "laravel/framework": "^11.31", - "laravel/tinker": "^2.9" + "laravel/tinker": "^2.9", + "laravel/ui": "^4.6" }, "require-dev": { "fakerphp/faker": "^1.23", @@ -29,7 +30,10 @@ "autoload-dev": { "psr-4": { "Tests\\": "tests/" - } + }, + "files": [ + "app/Helpers/custom.php" + ] }, "scripts": { "post-autoload-dump": [ diff --git a/composer.lock b/composer.lock index cbff563..96d9a54 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "626b9e7ddd47fb7eff9aaa53cce0c9ad", + "content-hash": "a7159c5237c3c2e75dbd1d23c85e732c", "packages": [ { "name": "brick/math", @@ -1453,6 +1453,69 @@ }, "time": "2025-01-27T14:24:01+00:00" }, + { + "name": "laravel/ui", + "version": "v4.6.1", + "source": { + "type": "git", + "url": "https://github.com/laravel/ui.git", + "reference": "7d6ffa38d79f19c9b3e70a751a9af845e8f41d88" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/ui/zipball/7d6ffa38d79f19c9b3e70a751a9af845e8f41d88", + "reference": "7d6ffa38d79f19c9b3e70a751a9af845e8f41d88", + "shasum": "" + }, + "require": { + "illuminate/console": "^9.21|^10.0|^11.0|^12.0", + "illuminate/filesystem": "^9.21|^10.0|^11.0|^12.0", + "illuminate/support": "^9.21|^10.0|^11.0|^12.0", + "illuminate/validation": "^9.21|^10.0|^11.0|^12.0", + "php": "^8.0", + "symfony/console": "^6.0|^7.0" + }, + "require-dev": { + "orchestra/testbench": "^7.35|^8.15|^9.0|^10.0", + "phpunit/phpunit": "^9.3|^10.4|^11.5" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Laravel\\Ui\\UiServiceProvider" + ] + }, + "branch-alias": { + "dev-master": "4.x-dev" + } + }, + "autoload": { + "psr-4": { + "Laravel\\Ui\\": "src/", + "Illuminate\\Foundation\\Auth\\": "auth-backend/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "Laravel UI utilities and presets.", + "keywords": [ + "laravel", + "ui" + ], + "support": { + "source": "https://github.com/laravel/ui/tree/v4.6.1" + }, + "time": "2025-01-28T15:15:29+00:00" + }, { "name": "league/commonmark", "version": "2.7.1", diff --git a/database/migrations/0001_01_01_000000_create_users_table.php b/database/migrations/2025_05_02_00000_create_users_table.php similarity index 94% rename from database/migrations/0001_01_01_000000_create_users_table.php rename to database/migrations/2025_05_02_00000_create_users_table.php index 05fb5d9..f644698 100644 --- a/database/migrations/0001_01_01_000000_create_users_table.php +++ b/database/migrations/2025_05_02_00000_create_users_table.php @@ -14,7 +14,9 @@ return new class extends Migration Schema::create('users', function (Blueprint $table) { $table->id(); $table->string('name'); + $table->integer('ms_group_id'); $table->string('email')->unique(); + $table->string('username')->unique(); $table->timestamp('email_verified_at')->nullable(); $table->string('password'); $table->rememberToken(); diff --git a/database/migrations/0001_01_01_000001_create_cache_table.php b/database/migrations/2025_05_02_00001_create_cache_table.php similarity index 100% rename from database/migrations/0001_01_01_000001_create_cache_table.php rename to database/migrations/2025_05_02_00001_create_cache_table.php diff --git a/database/migrations/0001_01_01_000002_create_jobs_table.php b/database/migrations/2025_05_02_00002_create_jobs_table.php similarity index 100% rename from database/migrations/0001_01_01_000002_create_jobs_table.php rename to database/migrations/2025_05_02_00002_create_jobs_table.php diff --git a/database/migrations/2025_05_02_014435_create_menus_table.php b/database/migrations/2025_05_02_014435_create_menus_table.php new file mode 100644 index 0000000..9899cfe --- /dev/null +++ b/database/migrations/2025_05_02_014435_create_menus_table.php @@ -0,0 +1,38 @@ +id('MsMenuId'); + $table->foreignId('parent_id')->index()->default(0)->comment('idx menu_id'); + $table->string('title', 150); + $table->string('module', 150)->nullable(); + $table->string('url', 150)->nullable(); + $table->string('menu_type', 50)->index()->nullable()->comment('tb_menu_group alias'); + $table->string('menu_icons', 50)->nullable(); + $table->tinyInteger('ordering')->default(0); + $table->boolean('status')->default(true)->comment('True/False'); + $table->foreignId('created_by')->default(0); + $table->foreignId('updated_by')->default(0)->nullable(); + $table->timestamps(); + $table->comment('Master menu aplikasi'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('menus'); + } +}; diff --git a/database/migrations/2025_05_02_014506_create_groups_table.php b/database/migrations/2025_05_02_014506_create_groups_table.php new file mode 100644 index 0000000..92576b3 --- /dev/null +++ b/database/migrations/2025_05_02_014506_create_groups_table.php @@ -0,0 +1,32 @@ +id('MsGroupId'); + $table->string('name', 50)->unique(); + $table->string('alias', 50)->unique(); + $table->boolean('status')->default(true)->comment('True/False'); + $table->foreignId('created_by')->default(0); + $table->foreignId('updated_by')->default(0)->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('groups'); + } +}; diff --git a/database/migrations/2025_05_02_014537_create_access_menus_table.php b/database/migrations/2025_05_02_014537_create_access_menus_table.php new file mode 100644 index 0000000..6f79a35 --- /dev/null +++ b/database/migrations/2025_05_02_014537_create_access_menus_table.php @@ -0,0 +1,42 @@ +id('MsAccessMenuId'); + $table->foreignId('ms_group_id')->comment('FK ms group'); + $table->string('module', 150)->nullable(); + $table->foreignId('ms_menu_id')->comment('FK tb_menu'); + $table->string('menu_group', 20)->nullable()->default('adminsidebar'); + $table->boolean('is_create')->default(false); + $table->boolean('is_read')->default(false); + $table->boolean('is_update')->default(false); + $table->boolean('is_delete')->default(false); + $table->boolean('is_verify')->default(false); + $table->boolean('is_approve')->default(false); + $table->boolean('is_download')->default(false); + $table->json('access')->nullable(); + $table->timestamps(); + $table->foreign('ms_menu_id')->references('MsMenuId')->on('ms_menu')->cascadeOnDelete(); + $table->foreign('ms_group_id')->references('MsGroupId')->on('ms_group')->cascadeOnDelete(); + $table->comment('Master hak akses role/group user'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('access_menus'); + } +}; diff --git a/database/migrations/2025_05_02_014944_add_foreignkey_groupid_user.php b/database/migrations/2025_05_02_014944_add_foreignkey_groupid_user.php new file mode 100644 index 0000000..7e02b98 --- /dev/null +++ b/database/migrations/2025_05_02_014944_add_foreignkey_groupid_user.php @@ -0,0 +1,28 @@ +foreign('ms_group_id')->references('MsGroupId')->on('ms_group')->cascadeOnDelete(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('users', function (Blueprint $table) { + // + }); + } +}; diff --git a/database/migrations/2025_05_07_062918_create_table_log.php b/database/migrations/2025_05_07_062918_create_table_log.php new file mode 100644 index 0000000..0bc695c --- /dev/null +++ b/database/migrations/2025_05_07_062918_create_table_log.php @@ -0,0 +1,35 @@ +bigIncrements('MsLogId'); + $table->string('module',200)->nullable(); + $table->string('task',100)->nullable(); + $table->unsignedBigInteger('user_id')->index()->nullable(); + $table->ipAddress('ipaddress')->nullable(); + $table->mediumText('useragent')->nullable(); + $table->mediumText('note')->nullable(); + $table->timestamps(); + + $table->foreign('user_id')->references('id')->on('users')->cascadeOnDelete(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('ms_log'); + } +}; diff --git a/package.json b/package.json index e32a862..575138f 100644 --- a/package.json +++ b/package.json @@ -6,11 +6,14 @@ "dev": "vite" }, "devDependencies": { + "@popperjs/core": "^2.11.6", "autoprefixer": "^10.4.20", "axios": "^1.7.4", + "bootstrap": "^5.2.3", "concurrently": "^9.0.1", "laravel-vite-plugin": "^1.2.0", "postcss": "^8.4.47", + "sass": "^1.56.1", "tailwindcss": "^3.4.13", "vite": "^6.0.11" } diff --git a/resources/js/bootstrap.js b/resources/js/bootstrap.js index 5f1390b..46f7a33 100644 --- a/resources/js/bootstrap.js +++ b/resources/js/bootstrap.js @@ -1,4 +1,34 @@ +import 'bootstrap'; + +/** + * We'll load the axios HTTP library which allows us to easily issue requests + * to our Laravel back-end. This library automatically handles sending the + * CSRF token as a header based on the value of the "XSRF" token cookie. + */ + import axios from 'axios'; window.axios = axios; window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest'; + +/** + * Echo exposes an expressive API for subscribing to channels and listening + * for events that are broadcast by Laravel. Echo and event broadcasting + * allows your team to easily build robust real-time web applications. + */ + +// import Echo from 'laravel-echo'; + +// import Pusher from 'pusher-js'; +// window.Pusher = Pusher; + +// window.Echo = new Echo({ +// broadcaster: 'pusher', +// key: import.meta.env.VITE_PUSHER_APP_KEY, +// cluster: import.meta.env.VITE_PUSHER_APP_CLUSTER ?? 'mt1', +// wsHost: import.meta.env.VITE_PUSHER_HOST ?? `ws-${import.meta.env.VITE_PUSHER_APP_CLUSTER}.pusher.com`, +// wsPort: import.meta.env.VITE_PUSHER_PORT ?? 80, +// wssPort: import.meta.env.VITE_PUSHER_PORT ?? 443, +// forceTLS: (import.meta.env.VITE_PUSHER_SCHEME ?? 'https') === 'https', +// enabledTransports: ['ws', 'wss'], +// }); diff --git a/resources/sass/_variables.scss b/resources/sass/_variables.scss new file mode 100644 index 0000000..172daaa --- /dev/null +++ b/resources/sass/_variables.scss @@ -0,0 +1,7 @@ +// Body +$body-bg: #f8fafc; + +// Typography +$font-family-sans-serif: 'Nunito', sans-serif; +$font-size-base: 0.9rem; +$line-height-base: 1.6; diff --git a/resources/sass/app.scss b/resources/sass/app.scss new file mode 100644 index 0000000..1026a0b --- /dev/null +++ b/resources/sass/app.scss @@ -0,0 +1,8 @@ +// Fonts +@import url('https://fonts.bunny.net/css?family=Nunito'); + +// Variables +@import 'variables'; + +// Bootstrap +@import 'bootstrap/scss/bootstrap'; diff --git a/resources/views/auth/login.blade.php b/resources/views/auth/login.blade.php new file mode 100644 index 0000000..ea9ac94 --- /dev/null +++ b/resources/views/auth/login.blade.php @@ -0,0 +1,73 @@ +@extends('layouts.app') + +@section('content') +
+
+
+
+
{{ __('Login') }}
+ +
+
+ @csrf + +
+ + +
+ + + @error('email') + + {{ $message }} + + @enderror +
+
+ +
+ + +
+ + + @error('password') + + {{ $message }} + + @enderror +
+
+ +
+
+
+ + + +
+
+
+ +
+
+ + + @if (Route::has('password.request')) + + {{ __('Forgot Your Password?') }} + + @endif +
+
+
+
+
+
+
+
+@endsection diff --git a/resources/views/auth/passwords/confirm.blade.php b/resources/views/auth/passwords/confirm.blade.php new file mode 100644 index 0000000..f8c8e61 --- /dev/null +++ b/resources/views/auth/passwords/confirm.blade.php @@ -0,0 +1,49 @@ +@extends('layouts.app') + +@section('content') +
+
+
+
+
{{ __('Confirm Password') }}
+ +
+ {{ __('Please confirm your password before continuing.') }} + +
+ @csrf + +
+ + +
+ + + @error('password') + + {{ $message }} + + @enderror +
+
+ +
+
+ + + @if (Route::has('password.request')) + + {{ __('Forgot Your Password?') }} + + @endif +
+
+
+
+
+
+
+
+@endsection diff --git a/resources/views/auth/passwords/email.blade.php b/resources/views/auth/passwords/email.blade.php new file mode 100644 index 0000000..d1ac783 --- /dev/null +++ b/resources/views/auth/passwords/email.blade.php @@ -0,0 +1,47 @@ +@extends('layouts.app') + +@section('content') +
+
+
+
+
{{ __('Reset Password') }}
+ +
+ @if (session('status')) + + @endif + +
+ @csrf + +
+ + +
+ + + @error('email') + + {{ $message }} + + @enderror +
+
+ +
+
+ +
+
+
+
+
+
+
+
+@endsection diff --git a/resources/views/auth/passwords/reset.blade.php b/resources/views/auth/passwords/reset.blade.php new file mode 100644 index 0000000..dccf6c6 --- /dev/null +++ b/resources/views/auth/passwords/reset.blade.php @@ -0,0 +1,65 @@ +@extends('layouts.app') + +@section('content') +
+
+
+
+
{{ __('Reset Password') }}
+ +
+
+ @csrf + + + +
+ + +
+ + + @error('email') + + {{ $message }} + + @enderror +
+
+ +
+ + +
+ + + @error('password') + + {{ $message }} + + @enderror +
+
+ +
+ + +
+ +
+
+ +
+
+ +
+
+
+
+
+
+
+
+@endsection diff --git a/resources/views/auth/register.blade.php b/resources/views/auth/register.blade.php new file mode 100644 index 0000000..12cad1a --- /dev/null +++ b/resources/views/auth/register.blade.php @@ -0,0 +1,77 @@ +@extends('layouts.app') + +@section('content') +
+
+
+
+
{{ __('Register') }}
+ +
+
+ @csrf + +
+ + +
+ + + @error('name') + + {{ $message }} + + @enderror +
+
+ +
+ + +
+ + + @error('email') + + {{ $message }} + + @enderror +
+
+ +
+ + +
+ + + @error('password') + + {{ $message }} + + @enderror +
+
+ +
+ + +
+ +
+
+ +
+
+ +
+
+
+
+
+
+
+
+@endsection diff --git a/resources/views/auth/verify.blade.php b/resources/views/auth/verify.blade.php new file mode 100644 index 0000000..9f8c1bc --- /dev/null +++ b/resources/views/auth/verify.blade.php @@ -0,0 +1,28 @@ +@extends('layouts.app') + +@section('content') +
+
+
+
+
{{ __('Verify Your Email Address') }}
+ +
+ @if (session('resent')) + + @endif + + {{ __('Before proceeding, please check your email for a verification link.') }} + {{ __('If you did not receive the email') }}, +
+ @csrf + . +
+
+
+
+
+
+@endsection diff --git a/resources/views/home.blade.php b/resources/views/home.blade.php new file mode 100644 index 0000000..1f34466 --- /dev/null +++ b/resources/views/home.blade.php @@ -0,0 +1,23 @@ +@extends('layouts.app') + +@section('content') +
+
+
+
+
{{ __('Dashboard') }}
+ +
+ @if (session('status')) + + @endif + + {{ __('You are logged in!') }} +
+
+
+
+
+@endsection diff --git a/resources/views/layouts/app.blade.php b/resources/views/layouts/app.blade.php new file mode 100644 index 0000000..a6970da --- /dev/null +++ b/resources/views/layouts/app.blade.php @@ -0,0 +1,80 @@ + + + + + + + + + + {{ config('app.name', 'Laravel') }} + + + + + + + @vite(['resources/sass/app.scss', 'resources/js/app.js']) + + +
+ + +
+ @yield('content') +
+
+ + diff --git a/routes/modules/modules.php b/routes/modules/modules.php new file mode 100644 index 0000000..b16345e --- /dev/null +++ b/routes/modules/modules.php @@ -0,0 +1,3 @@ +name('home'); + +Route::middleware(Session::class)->name('modules.')->group(function () { + + include_route_files(__DIR__ . '/modules'); + + Route::get('logout',[CustomLoginController::class,'logout'])->name('logout'); +}); \ No newline at end of file diff --git a/vite.config.js b/vite.config.js index 421b569..dbbf333 100644 --- a/vite.config.js +++ b/vite.config.js @@ -4,7 +4,10 @@ import laravel from 'laravel-vite-plugin'; export default defineConfig({ plugins: [ laravel({ - input: ['resources/css/app.css', 'resources/js/app.js'], + input: [ + 'resources/sass/app.scss', + 'resources/js/app.js', + ], refresh: true, }), ],