update metronic 8.2

This commit is contained in:
Daeng Deni Mardaeni 2023-09-26 16:51:59 +07:00
parent 4c730a3b7a
commit c73ea1b54c
1429 changed files with 231438 additions and 0 deletions

View File

@ -0,0 +1,24 @@
<?php
namespace App\Actions;
class GetThemeType
{
public array $types = ['primary', 'success', 'info', 'danger', 'warning'];
public int $seed;
public function handle($format = '?', $seed = '')
{
$this->seed = crc32($seed);
return str_replace('?', $this->randomType(), $format);
}
public function randomType()
{
srand($this->seed);
return $this->types[rand(0, count($this->types) - 1)] ?? '';
}
}

45
app/Core/KTBootstrap.php Normal file
View File

@ -0,0 +1,45 @@
<?php
namespace App\Core;
class KTBootstrap
{
// Init theme mode option from settings
public static function init()
{
KTBootstrap::initThemeMode();
KTBootstrap::initThemeDirection();
KTBootstrap::initLayout();
}
// Init theme direction option (RTL or LTR) from settings
// Init RTL html attributes by checking if RTL is enabled.
// This function is being called for the html tag
public static function initThemeMode()
{
setModeSwitch(config('settings.KT_THEME_MODE_SWITCH_ENABLED'));
setModeDefault(config('settings.KT_THEME_MODE_DEFAULT'));
}
// Init layout html attributes and classes
public static function initThemeDirection()
{
setDirection(config('settings.KT_THEME_DIRECTION'));
if (isRtlDirection()) {
addHtmlAttribute('html', 'direction', 'rtl');
addHtmlAttribute('html', 'dir', 'rtl');
addHtmlAttribute('html', 'style', 'direction: rtl');
}
}
// Main initialization
public static function initLayout()
{
addHtmlAttribute('body', 'id', 'kt_app_body');
addHtmlAttribute('body', 'data-kt-name', getName());
}
}

View File

@ -0,0 +1,85 @@
<?php
namespace App\DataTables;
use Illuminate\Database\Eloquent\Builder as QueryBuilder;
use Spatie\Permission\Models\Permission;
use Yajra\DataTables\EloquentDataTable;
use Yajra\DataTables\Html\Builder as HtmlBuilder;
use Yajra\DataTables\Html\Column;
use Yajra\DataTables\Services\DataTable;
class PermissionsDataTable extends DataTable
{
/**
* Build the DataTable class.
*
* @param QueryBuilder $query Results from query() method.
*/
public function dataTable(QueryBuilder $query): EloquentDataTable
{
return (new EloquentDataTable($query))
->editColumn('name', function (Permission $permission) {
return ucwords($permission->name);
})
->addColumn('assigned_to', function (Permission $permission) {
$roles = $permission->roles;
return view('pages.apps.user-management.permissions.columns._assign-to', compact('roles'));
})
->editColumn('created_at', function (Permission $permission) {
return $permission->created_at->format('d M Y, h:i a');
})
->addColumn('actions', function (Permission $permission) {
return view('pages.apps.user-management.permissions.columns._actions', compact('permission'));
})
->setRowId('id');
}
/**
* Get the query source of dataTable.
*/
public function query(Permission $model): QueryBuilder
{
return $model->newQuery();
}
/**
* Optional method if you want to use the html builder.
*/
public function html(): HtmlBuilder
{
return $this->builder()
->setTableId('permissions-table')
->columns($this->getColumns())
->minifiedAjax()
->dom('rt' . "<'row'<'col-sm-12 col-md-5'l><'col-sm-12 col-md-7'p>>",)
->addTableClass('table align-middle table-row-dashed fs-6 gy-5 dataTable no-footer text-gray-600 fw-semibold')
->setTableHeadClass('text-start text-muted fw-bold fs-7 text-uppercase gs-0')
->orderBy(0)
->drawCallback("function() {" . file_get_contents(resource_path('views/pages//apps/user-management/permissions/columns/_draw-scripts.js')) . "}");
}
/**
* Get the dataTable columns definition.
*/
public function getColumns(): array
{
return [
Column::make('name'),
Column::make('assigned_to'),
Column::make('created_at')->addClass('text-nowrap'),
Column::computed('actions')
->addClass('text-end text-nowrap')
->exportable(false)
->printable(false),
];
}
/**
* Get the filename for export.
*/
protected function filename(): string
{
return 'Permissions_' . date('YmdHis');
}
}

View File

@ -0,0 +1,88 @@
<?php
namespace App\DataTables;
use App\Models\User;
use App\Models\UsersAssingedRole;
use Illuminate\Contracts\Database\Query\Builder;
use Illuminate\Database\Eloquent\Builder as QueryBuilder;
use Yajra\DataTables\EloquentDataTable;
use Yajra\DataTables\Html\Builder as HtmlBuilder;
use Yajra\DataTables\Html\Column;
use Yajra\DataTables\Services\DataTable;
class UsersAssignedRoleDataTable extends DataTable
{
/**
* Build the DataTable class.
*
* @param QueryBuilder $query Results from query() method.
*/
public function dataTable(QueryBuilder $query): EloquentDataTable
{
return (new EloquentDataTable($query))
->rawColumns(['user'])
->editColumn('user', function (User $user) {
return view('pages.apps.user-management.roles.columns._user', compact('user'));
})
->editColumn('created_at', function (User $user) {
return $user->created_at->format('d M Y, h:i a');
})
->addColumn('action', function (User $user) {
return view('pages.apps.user-management.roles.columns._actions', compact('user'));
})
->setRowId('id');
}
/**
* Get the query source of dataTable.
*/
public function query(User $model): QueryBuilder
{
return $model->newQuery()->whereHas('roles', function (Builder $query) {
$query->where('role_id', $this->role->getKey());
});
}
/**
* Optional method if you want to use the html builder.
*/
public function html(): HtmlBuilder
{
return $this->builder()
->setTableId('usersassingedrole-table')
->columns($this->getColumns())
->minifiedAjax()
->dom('rt' . "<'row'<'col-sm-12 col-md-5'l><'col-sm-12 col-md-7'p>>",)
->addTableClass('table align-middle table-row-dashed fs-6 gy-5 dataTable no-footer text-gray-600 fw-semibold')
->setTableHeadClass('text-start text-muted fw-bold fs-7 text-uppercase gs-0')
->orderBy(1)
->drawCallback("function() {" . file_get_contents(resource_path('views/pages//apps/user-management/users/columns/_draw-scripts.js')) . "}");
}
/**
* Get the dataTable columns definition.
*/
public function getColumns(): array
{
return [
Column::make('id'),
Column::make('user')->addClass('d-flex align-items-center')->name('name'),
Column::make('name'),
Column::make('created_at')->title('Joined Date')->addClass('text-nowrap'),
Column::computed('action')
->addClass('text-end text-nowrap')
->exportable(false)
->printable(false)
->width(60),
];
}
/**
* Get the filename for export.
*/
protected function filename(): string
{
return 'UsersAssingedRole_' . date('YmdHis');
}
}

View File

@ -0,0 +1,91 @@
<?php
namespace App\DataTables;
use App\Models\User;
use Yajra\DataTables\Html\Column;
use Yajra\DataTables\EloquentDataTable;
use Yajra\DataTables\Services\DataTable;
use Yajra\DataTables\Html\Builder as HtmlBuilder;
use Illuminate\Database\Eloquent\Builder as QueryBuilder;
class UsersDataTable extends DataTable
{
/**
* Build the DataTable class.
*
* @param QueryBuilder $query Results from query() method.
*/
public function dataTable(QueryBuilder $query): EloquentDataTable
{
return (new EloquentDataTable($query))
->rawColumns(['user', 'last_login_at'])
->editColumn('user', function (User $user) {
return view('pages.apps.user-management.users.columns._user', compact('user'));
})
->editColumn('role', function (User $user) {
return ucwords($user->roles->first()?->name);
})
->editColumn('last_login_at', function (User $user) {
return sprintf('<div class="badge badge-light fw-bold">%s</div>', $user->last_login_at ? $user->last_login_at->diffForHumans() : $user->updated_at->diffForHumans());
})
->editColumn('created_at', function (User $user) {
return $user->created_at->format('d M Y, h:i a');
})
->addColumn('action', function (User $user) {
return view('pages.apps.user-management.users.columns._actions', compact('user'));
})
->setRowId('id');
}
/**
* Get the query source of dataTable.
*/
public function query(User $model): QueryBuilder
{
return $model->newQuery();
}
/**
* Optional method if you want to use the html builder.
*/
public function html(): HtmlBuilder
{
return $this->builder()
->setTableId('users-table')
->columns($this->getColumns())
->minifiedAjax()
->dom('rt' . "<'row'<'col-sm-12 col-md-5'l><'col-sm-12 col-md-7'p>>",)
->addTableClass('table align-middle table-row-dashed fs-6 gy-5 dataTable no-footer text-gray-600 fw-semibold')
->setTableHeadClass('text-start text-muted fw-bold fs-7 text-uppercase gs-0')
->orderBy(2)
->drawCallback("function() {" . file_get_contents(resource_path('views/pages//apps/user-management/users/columns/_draw-scripts.js')) . "}");
}
/**
* Get the dataTable columns definition.
*/
public function getColumns(): array
{
return [
Column::make('user')->addClass('d-flex align-items-center')->name('name'),
Column::make('role')->searchable(false),
Column::make('last_login_at')->title('Last Login'),
Column::make('created_at')->title('Joined Date')->addClass('text-nowrap'),
Column::computed('action')
->addClass('text-end text-nowrap')
->exportable(false)
->printable(false)
->width(60)
];
}
/**
* Get the filename for export.
*/
protected function filename(): string
{
return 'Users_' . date('YmdHis');
}
}

View File

@ -0,0 +1,66 @@
<?php
namespace App\Http\Controllers\Apps;
use App\DataTables\PermissionsDataTable;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
class PermissionManagementController extends Controller
{
/**
* Display a listing of the resource.
*/
public function index(PermissionsDataTable $dataTable)
{
return $dataTable->render('pages.apps.user-management.permissions.list');
}
/**
* Show the form for creating a new resource.
*/
public function create()
{
//
}
/**
* Store a newly created resource in storage.
*/
public function store(Request $request)
{
//
}
/**
* Display the specified resource.
*/
public function show(string $id)
{
//
}
/**
* Show the form for editing the specified resource.
*/
public function edit(string $id)
{
//
}
/**
* Update the specified resource in storage.
*/
public function update(Request $request, string $id)
{
//
}
/**
* Remove the specified resource from storage.
*/
public function destroy(string $id)
{
//
}
}

View File

@ -0,0 +1,68 @@
<?php
namespace App\Http\Controllers\Apps;
use App\DataTables\UsersAssignedRoleDataTable;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Spatie\Permission\Models\Role;
class RoleManagementController extends Controller
{
/**
* Display a listing of the resource.
*/
public function index()
{
return view('pages.apps.user-management.roles.list');
}
/**
* Show the form for creating a new resource.
*/
public function create()
{
//
}
/**
* Store a newly created resource in storage.
*/
public function store(Request $request)
{
//
}
/**
* Display the specified resource.
*/
public function show(Role $role, UsersAssignedRoleDataTable $dataTable)
{
return $dataTable->with('role', $role)
->render('pages.apps.user-management.roles.show', compact('role'));
}
/**
* Show the form for editing the specified resource.
*/
public function edit(Role $role)
{
//
}
/**
* Update the specified resource in storage.
*/
public function update(Request $request, Role $role)
{
//
}
/**
* Remove the specified resource from storage.
*/
public function destroy(Role $role)
{
//
}
}

View File

@ -0,0 +1,67 @@
<?php
namespace App\Http\Controllers\Apps;
use App\DataTables\UsersDataTable;
use App\Http\Controllers\Controller;
use App\Models\User;
use Illuminate\Http\Request;
class UserManagementController extends Controller
{
/**
* Display a listing of the resource.
*/
public function index(UsersDataTable $dataTable)
{
return $dataTable->render('pages.apps.user-management.users.list');
}
/**
* Show the form for creating a new resource.
*/
public function create()
{
//
}
/**
* Store a newly created resource in storage.
*/
public function store(Request $request)
{
//
}
/**
* Display the specified resource.
*/
public function show(User $user)
{
return view('pages.apps.user-management.users.show', compact('user'));
}
/**
* Show the form for editing the specified resource.
*/
public function edit(User $user)
{
//
}
/**
* Update the specified resource in storage.
*/
public function update(Request $request, User $user)
{
//
}
/**
* Remove the specified resource from storage.
*/
public function destroy(User $user)
{
//
}
}

View File

@ -0,0 +1,64 @@
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Http\Requests\Auth\LoginRequest;
use App\Providers\RouteServiceProvider;
use Illuminate\Http\Request;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Auth;
class AuthenticatedSessionController extends Controller
{
/**
* Display the login view.
*
* @return \Illuminate\View\View
*/
public function create()
{
addJavascriptFile('assets/js/custom/authentication/sign-in/general.js');
return view('pages.auth.login');
}
/**
* Handle an incoming authentication request.
*
* @param \App\Http\Requests\Auth\LoginRequest $request
*
* @return \Illuminate\Http\RedirectResponse
*/
public function store(LoginRequest $request)
{
$request->authenticate();
$request->session()->regenerate();
$request->user()->update([
'last_login_at' => Carbon::now()->toDateTimeString(),
'last_login_ip' => $request->getClientIp()
]);
return redirect()->intended(RouteServiceProvider::HOME);
}
/**
* Destroy an authenticated session.
*
* @param \Illuminate\Http\Request $request
*
* @return \Illuminate\Http\RedirectResponse
*/
public function destroy(Request $request)
{
Auth::guard('web')->logout();
$request->session()->invalidate();
$request->session()->regenerateToken();
return redirect('/');
}
}

View File

@ -0,0 +1,44 @@
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Validation\ValidationException;
class ConfirmablePasswordController extends Controller
{
/**
* Show the confirm password view.
*
* @return \Illuminate\View\View
*/
public function show()
{
return view('pages.auth.confirm-password');
}
/**
* Confirm the user's password.
*
* @param \Illuminate\Http\Request $request
* @return mixed
*/
public function store(Request $request)
{
if (! Auth::guard('web')->validate([
'email' => $request->user()->email,
'password' => $request->password,
])) {
throw ValidationException::withMessages([
'password' => __('auth.password'),
]);
}
$request->session()->put('auth.password_confirmed_at', time());
return redirect()->intended(RouteServiceProvider::HOME);
}
}

View File

@ -0,0 +1,27 @@
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
use Illuminate\Http\Request;
class EmailVerificationNotificationController extends Controller
{
/**
* Send a new email verification notification.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\RedirectResponse
*/
public function store(Request $request)
{
if ($request->user()->hasVerifiedEmail()) {
return redirect()->intended(RouteServiceProvider::HOME);
}
$request->user()->sendEmailVerificationNotification();
return back()->with('status', 'verification-link-sent');
}
}

View File

@ -0,0 +1,23 @@
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
use Illuminate\Http\Request;
class EmailVerificationPromptController extends Controller
{
/**
* Display the email verification prompt.
*
* @param \Illuminate\Http\Request $request
* @return mixed
*/
public function __invoke(Request $request)
{
return $request->user()->hasVerifiedEmail()
? redirect()->intended(RouteServiceProvider::HOME)
: view('pages.auth.verify-email');
}
}

View File

@ -0,0 +1,67 @@
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Auth\Events\PasswordReset;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Password;
use Illuminate\Support\Str;
use Illuminate\Validation\Rules;
class NewPasswordController extends Controller
{
/**
* Display the password reset view.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\View\View
*/
public function create(Request $request)
{
addJavascriptFile('assets/js/custom/authentication/reset-password/new-password.js');
return view('pages.auth.reset-password', ['request' => $request]);
}
/**
* Handle an incoming new password request.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\RedirectResponse
*
* @throws \Illuminate\Validation\ValidationException
*/
public function store(Request $request)
{
$request->validate([
'token' => ['required'],
'email' => ['required', 'email'],
'password' => ['required', 'confirmed', Rules\Password::defaults()],
]);
// Here we will attempt to reset the user's password. If it is successful we
// will update the password on an actual user model and persist it to the
// database. Otherwise we will parse the error and return the response.
$status = Password::reset(
$request->only('email', 'password', 'password_confirmation', 'token'),
function ($user) use ($request) {
$user->forceFill([
'password' => Hash::make($request->password),
'remember_token' => Str::random(60),
])->save();
event(new PasswordReset($user));
}
);
// If the password was successfully reset, we will redirect the user back to
// the application's home authenticated view. If there is an error we can
// redirect them back to where they came from with their error message.
return $status == Password::PASSWORD_RESET
? redirect()->route('login')->with('status', __($status))
: back()->withInput($request->only('email'))
->withErrors(['email' => __($status)]);
}
}

View File

@ -0,0 +1,49 @@
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Password;
class PasswordResetLinkController extends Controller
{
/**
* Display the password reset link request view.
*
* @return \Illuminate\View\View
*/
public function create()
{
addJavascriptFile('assets/js/custom/authentication/reset-password/reset-password.js');
return view('pages.auth.forgot-password');
}
/**
* Handle an incoming password reset link request.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\RedirectResponse
*
* @throws \Illuminate\Validation\ValidationException
*/
public function store(Request $request)
{
$request->validate([
'email' => ['required', 'email'],
]);
// We will send the password reset link to this user. Once we have attempted
// to send the link, we will examine the response then see the message we
// need to show to the user. Finally, we'll send out a proper response.
$status = Password::sendResetLink(
$request->only('email')
);
return $status == Password::RESET_LINK_SENT
? back()->with('status', __($status))
: back()->withInput($request->only('email'))
->withErrors(['email' => __($status)]);
}
}

View File

@ -0,0 +1,59 @@
<?php
namespace App\Http\Controllers\Auth;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Carbon;
use Illuminate\Validation\Rules;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Auth\Events\Registered;
use App\Providers\RouteServiceProvider;
class RegisteredUserController extends Controller
{
/**
* Display the registration view.
*
* @return \Illuminate\View\View
*/
public function create()
{
addJavascriptFile('assets/js/custom/authentication/sign-up/general.js');
return view('pages.auth.register');
}
/**
* Handle an incoming registration request.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\RedirectResponse
*
* @throws \Illuminate\Validation\ValidationException
*/
public function store(Request $request)
{
$request->validate([
'name' => ['required', 'string', 'max:255'],
'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
'password' => ['required', 'confirmed', Rules\Password::defaults()],
]);
$user = User::create([
'name' => $request->name,
'email' => $request->email,
'password' => Hash::make($request->password),
'last_login_at' => \Illuminate\Support\Carbon::now()->toDateTimeString(),
'last_login_ip' => $request->getClientIp()
]);
event(new Registered($user));
Auth::login($user);
return redirect(RouteServiceProvider::HOME);
}
}

View File

@ -0,0 +1,54 @@
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Models\User;
use Illuminate\Auth\Events\Verified;
use Laravel\Socialite\Facades\Socialite;
class SocialiteController extends Controller
{
public function redirect($provider)
{
// redirect from social site
if (request()->input('state')) {
// already logged in
// get user info from social site
$user = Socialite::driver($provider)->stateless()->user();
// check for existing user
$existingUser = User::where('email', $user->getEmail())->first();
if ($existingUser) {
auth()->login($existingUser, true);
return redirect()->to('/');
}
$newUser = $this->createUser($user);
auth()->login($newUser, true);
}
// request login from social site
return Socialite::driver($provider)->redirect();
}
function createUser($user)
{
$user = User::updateOrCreate([
'email' => $user->getEmail(),
], [
'name' => $user->getName(),
'password' => '',
'avatar' => $user->getAvatar(),
]);
if ($user->markEmailAsVerified()) {
event(new Verified($user));
}
return $user;
}
}

View File

@ -0,0 +1,30 @@
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
use Illuminate\Auth\Events\Verified;
use Illuminate\Foundation\Auth\EmailVerificationRequest;
class VerifyEmailController extends Controller
{
/**
* Mark the authenticated user's email address as verified.
*
* @param \Illuminate\Foundation\Auth\EmailVerificationRequest $request
* @return \Illuminate\Http\RedirectResponse
*/
public function __invoke(EmailVerificationRequest $request)
{
if ($request->user()->hasVerifiedEmail()) {
return redirect()->intended(RouteServiceProvider::HOME.'?verified=1');
}
if ($request->user()->markEmailAsVerified()) {
event(new Verified($request->user()));
}
return redirect()->intended(RouteServiceProvider::HOME.'?verified=1');
}
}

View File

@ -0,0 +1,80 @@
<?php
namespace App\Http\Livewire\Permission;
use Livewire\Component;
use Spatie\Permission\Models\Permission;
class PermissionModal extends Component
{
public $name;
public Permission $permission;
protected $rules = [
'name' => 'required|string',
];
// This is the list of listeners that this component listens to.
protected $listeners = [
'modal.show.permission_name' => 'mountPermission',
'delete_permission' => 'delete'
];
public function render()
{
return view('livewire.permission.permission-modal');
}
public function mountPermission($permission_name = '')
{
if (empty($permission_name)) {
// Create new
$this->permission = new Permission;
$this->name = '';
return;
}
// Get the role by name.
$permission = Permission::where('name', $permission_name)->first();
if (is_null($permission)) {
$this->emit('error', 'The selected permission [' . $permission_name . '] is not found');
return;
}
$this->permission = $permission;
// Set the name and checked permissions properties to the role's values.
$this->name = $this->permission->name;
}
public function submit()
{
$this->validate();
$this->permission->name = strtolower($this->name);
if ($this->permission->isDirty()) {
$this->permission->save();
}
// Emit a success event with a message indicating that the permissions have been updated.
$this->emit('success', 'Permission updated');
}
public function delete($name)
{
$permission = Permission::where('name', $name)->first();
if (!is_null($permission)) {
$permission->delete();
}
$this->emit('success', 'Permission deleted');
}
public function hydrate()
{
$this->resetErrorBag();
$this->resetValidation();
}
}

View File

@ -0,0 +1,32 @@
<?php
namespace App\Http\Livewire\Permission;
use Illuminate\Database\Eloquent\Collection;
use Livewire\Component;
use Spatie\Permission\Models\Role;
class RoleList extends Component
{
public array|Collection $roles;
protected $listeners = ['success' => 'updateRoleList'];
public function render()
{
$this->roles = Role::with('permissions')->get();
return view('livewire.permission.role-list');
}
public function updateRoleList()
{
$this->roles = Role::with('permissions')->get();
}
public function hydrate()
{
$this->resetErrorBag();
$this->resetValidation();
}
}

View File

@ -0,0 +1,110 @@
<?php
namespace App\Http\Livewire\Permission;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Str;
use Livewire\Component;
use Spatie\Permission\Models\Permission;
use Spatie\Permission\Models\Role;
class RoleModal extends Component
{
public $name;
public $checked_permissions;
public $check_all;
public Role $role;
public Collection $permissions;
protected $rules = [
'name' => 'required|string',
];
// This is the list of listeners that this component listens to.
protected $listeners = ['modal.show.role_name' => 'mountRole'];
// This function is called when the component receives the `modal.show.role_name` event.
public function mountRole($role_name = '')
{
if (empty($role_name)) {
// Create new
$this->role = new Role;
$this->name = '';
return;
}
// Get the role by name.
$role = Role::where('name', $role_name)->first();
if (is_null($role)) {
$this->emit('error', 'The selected role [' . $role_name . '] is not found');
return;
}
$this->role = $role;
// Set the name and checked permissions properties to the role's values.
$this->name = $this->role->name;
$this->checked_permissions = $this->role->permissions->pluck('name');
}
// This function is called when the component is mounted.
public function mount()
{
// Get all permissions.
$this->permissions = Permission::all();
// Set the checked permissions property to an empty array.
$this->checked_permissions = [];
}
// This function renders the component's view.
public function render()
{
// Create an array of permissions grouped by ability.
$permissions_by_group = [];
foreach ($this->permissions ?? [] as $permission) {
$ability = Str::after($permission->name, ' ');
$permissions_by_group[$ability][] = $permission;
}
// Return the view with the permissions_by_group variable passed in.
return view('livewire.permission.role-modal', compact('permissions_by_group'));
}
// This function submits the form and updates the role's permissions.
public function submit()
{
$this->validate();
$this->role->name = $this->name;
if ($this->role->isDirty()) {
$this->role->save();
}
// Sync the role's permissions with the checked permissions property.
$this->role->syncPermissions($this->checked_permissions);
// Emit a success event with a message indicating that the permissions have been updated.
$this->emit('success', 'Permissions for ' . ucwords($this->role->name) . ' role updated');
}
// This function checks all of the permissions.
public function checkAll()
{
// If the check_all property is true, set the checked permissions property to all of the permissions.
if ($this->check_all) {
$this->checked_permissions = $this->permissions->pluck('name');
} else {
// Otherwise, set the checked permissions property to an empty array.
$this->checked_permissions = [];
}
}
public function hydrate()
{
$this->resetErrorBag();
$this->resetValidation();
}
}

View File

@ -0,0 +1,137 @@
<?php
namespace App\Http\Livewire\User;
use App\Models\User;
use Livewire\Component;
use Livewire\WithFileUploads;
use Illuminate\Support\Facades\DB;
use Spatie\Permission\Models\Role;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Password;
class AddUserModal extends Component
{
use WithFileUploads;
public $name;
public $email;
public $role;
public $avatar;
public $saved_avatar;
public $edit_mode = false;
protected $rules = [
'name' => 'required|string',
'email' => 'required|email',
'role' => 'required|string',
'avatar' => 'nullable|sometimes|image|max:1024',
];
protected $listeners = [
'delete_user' => 'deleteUser',
'update_user' => 'updateUser',
];
public function render()
{
$roles = Role::all();
$roles_description = [
'administrator' => 'Best for business owners and company administrators',
'developer' => 'Best for developers or people primarily using the API',
'analyst' => 'Best for people who need full access to analytics data, but don\'t need to update business settings',
'support' => 'Best for employees who regularly refund payments and respond to disputes',
'trial' => 'Best for people who need to preview content data, but don\'t need to make any updates',
];
foreach ($roles as $i => $role) {
$roles[$i]->description = $roles_description[$role->name] ?? '';
}
return view('livewire.user.add-user-modal', compact('roles'));
}
public function submit()
{
// Validate the form input data
$this->validate();
DB::transaction(function () {
// Prepare the data for creating a new user
$data = [
'name' => $this->name,
];
if ($this->avatar) {
$data['profile_photo_path'] = $this->avatar->store('avatars', 'public');
} else {
$data['profile_photo_path'] = null;
}
if (!$this->edit_mode) {
$data['password'] = Hash::make($this->email);
}
// Create a new user record in the database
$user = User::updateOrCreate([
'email' => $this->email,
], $data);
if ($this->edit_mode) {
// Assign selected role for user
$user->syncRoles($this->role);
// Emit a success event with a message
$this->emit('success', __('User updated'));
} else {
// Assign selected role for user
$user->assignRole($this->role);
// Send a password reset link to the user's email
Password::sendResetLink($user->only('email'));
// Emit a success event with a message
$this->emit('success', __('New user created'));
}
});
// Reset the form fields after successful submission
$this->reset();
}
public function deleteUser($id)
{
// Prevent deletion of current user
if ($id == Auth::id()) {
$this->emit('error', 'User cannot be deleted');
return;
}
// Delete the user record with the specified ID
User::destroy($id);
// Emit a success event with a message
$this->emit('success', 'User successfully deleted');
}
public function updateUser($id)
{
$this->edit_mode = true;
$user = User::find($id);
$this->saved_avatar = $user->profile_photo_url;
$this->name = $user->name;
$this->email = $user->email;
$this->role = $user->roles?->first()->name ?? '';
}
public function hydrate()
{
$this->resetErrorBag();
$this->resetValidation();
}
}

View File

@ -0,0 +1,93 @@
<?php
namespace App\Http\Requests\Auth;
use Illuminate\Auth\Events\Lockout;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Support\Str;
use Illuminate\Validation\ValidationException;
class LoginRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'email' => ['required', 'string', 'email'],
'password' => ['required', 'string'],
];
}
/**
* Attempt to authenticate the request's credentials.
*
* @return void
*
* @throws \Illuminate\Validation\ValidationException
*/
public function authenticate()
{
$this->ensureIsNotRateLimited();
if (! Auth::attempt($this->only('email', 'password'), $this->boolean('remember'))) {
RateLimiter::hit($this->throttleKey());
throw ValidationException::withMessages([
'email' => trans('auth.failed'),
]);
}
RateLimiter::clear($this->throttleKey());
}
/**
* Ensure the login request is not rate limited.
*
* @return void
*
* @throws \Illuminate\Validation\ValidationException
*/
public function ensureIsNotRateLimited()
{
if (! RateLimiter::tooManyAttempts($this->throttleKey(), 5)) {
return;
}
event(new Lockout($this));
$seconds = RateLimiter::availableIn($this->throttleKey());
throw ValidationException::withMessages([
'email' => trans('auth.throttle', [
'seconds' => $seconds,
'minutes' => ceil($seconds / 60),
]),
]);
}
/**
* Get the rate limiting throttle key for the request.
*
* @return string
*/
public function throttleKey()
{
return Str::transliterate(Str::lower($this->input('email')).'|'.$this->ip());
}
}

60
app/Models/User.php Normal file
View File

@ -0,0 +1,60 @@
<?php
namespace App\Models;
// use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Facades\Storage;
use Laravel\Sanctum\HasApiTokens;
use Spatie\Permission\Traits\HasRoles;
class User extends Authenticatable
{
use HasApiTokens, HasFactory, Notifiable;
use HasRoles;
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'name',
'email',
'password',
'last_login_at',
'last_login_ip',
'profile_photo_path',
];
/**
* The attributes that should be hidden for serialization.
*
* @var array<int, string>
*/
protected $hidden = [
'password',
'remember_token',
];
/**
* The attributes that should be cast.
*
* @var array<string, string>
*/
protected $casts = [
'email_verified_at' => 'datetime',
'last_login_at' => 'datetime',
];
public function getProfilePhotoUrlAttribute()
{
if ($this->profile_photo_path) {
return asset('storage/' . $this->profile_photo_path);
}
return $this->profile_photo_path;
}
}

75
config/breadcrumbs.php Normal file
View File

@ -0,0 +1,75 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| View Name
|--------------------------------------------------------------------------
|
| Choose a view to display when Breadcrumbs::render() is called.
| Built in templates are:
|
| - 'breadcrumbs::bootstrap5' - Bootstrap 5
| - 'breadcrumbs::bootstrap4' - Bootstrap 4
| - 'breadcrumbs::bulma' - Bulma
| - 'breadcrumbs::foundation6' - Foundation 6
| - 'breadcrumbs::json-ld' - JSON-LD Structured Data
| - 'breadcrumbs::materialize' - Materialize
| - 'breadcrumbs::tailwind' - Tailwind CSS
| - 'breadcrumbs::uikit' - UIkit
|
| Or a custom view, e.g. '_partials/breadcrumbs'.
|
*/
'view' => 'breadcrumbs::bootstrap5',
/*
|--------------------------------------------------------------------------
| Breadcrumbs File(s)
|--------------------------------------------------------------------------
|
| The file(s) where breadcrumbs are defined. e.g.
|
| - base_path('routes/breadcrumbs.php')
| - glob(base_path('breadcrumbs/*.php'))
|
*/
'files' => base_path('routes/breadcrumbs.php'),
/*
|--------------------------------------------------------------------------
| Exceptions
|--------------------------------------------------------------------------
|
| Determine when to throw an exception.
|
*/
// When route-bound breadcrumbs are used but the current route doesn't have a name (UnnamedRouteException)
'unnamed-route-exception' => true,
// When route-bound breadcrumbs are used and the matching breadcrumb doesn't exist (InvalidBreadcrumbException)
'missing-route-bound-breadcrumb-exception' => true,
// When a named breadcrumb is used but doesn't exist (InvalidBreadcrumbException)
'invalid-named-breadcrumb-exception' => true,
/*
|--------------------------------------------------------------------------
| Classes
|--------------------------------------------------------------------------
|
| Subclass the default classes for more advanced customisations.
|
*/
// Manager
'manager-class' => Diglactic\Breadcrumbs\Manager::class,
// Generator
'generator-class' => Diglactic\Breadcrumbs\Generator::class,
];

158
config/livewire.php Normal file
View File

@ -0,0 +1,158 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Class Namespace
|--------------------------------------------------------------------------
|
| This value sets the root namespace for Livewire component classes in
| your application. This value affects component auto-discovery and
| any Livewire file helper commands, like `artisan make:livewire`.
|
| After changing this item, run: `php artisan livewire:discover`.
|
*/
'class_namespace' => 'App\\Http\\Livewire',
/*
|--------------------------------------------------------------------------
| View Path
|--------------------------------------------------------------------------
|
| This value sets the path for Livewire component views. This affects
| file manipulation helper commands like `artisan make:livewire`.
|
*/
'view_path' => resource_path('views/livewire'),
/*
|--------------------------------------------------------------------------
| Layout
|--------------------------------------------------------------------------
| The default layout view that will be used when rendering a component via
| Route::get('/some-endpoint', SomeComponent::class);. In this case the
| the view returned by SomeComponent will be wrapped in "layouts.app"
|
*/
'layout' => 'layouts.app',
/*
|--------------------------------------------------------------------------
| Livewire Assets URL
|--------------------------------------------------------------------------
|
| This value sets the path to Livewire JavaScript assets, for cases where
| your app's domain root is not the correct path. By default, Livewire
| will load its JavaScript assets from the app's "relative root".
|
| Examples: "/assets", "myurl.com/app".
|
*/
'asset_url' => env('LIVEWIRE_ASSET_URL', null),
/*
|--------------------------------------------------------------------------
| Livewire App URL
|--------------------------------------------------------------------------
|
| This value should be used if livewire assets are served from CDN.
| Livewire will communicate with an app through this url.
|
| Examples: "https://my-app.com", "myurl.com/app".
|
*/
'app_url' => null,
/*
|--------------------------------------------------------------------------
| Livewire Endpoint Middleware Group
|--------------------------------------------------------------------------
|
| This value sets the middleware group that will be applied to the main
| Livewire "message" endpoint (the endpoint that gets hit everytime
| a Livewire component updates). It is set to "web" by default.
|
*/
'middleware_group' => 'web',
/*
|--------------------------------------------------------------------------
| Livewire Temporary File Uploads Endpoint Configuration
|--------------------------------------------------------------------------
|
| Livewire handles file uploads by storing uploads in a temporary directory
| before the file is validated and stored permanently. All file uploads
| are directed to a global endpoint for temporary storage. The config
| items below are used for customizing the way the endpoint works.
|
*/
'temporary_file_upload' => [
'disk' => null, // Example: 'local', 's3' Default: 'default'
'rules' => null, // Example: ['file', 'mimes:png,jpg'] Default: ['required', 'file', 'max:12288'] (12MB)
'directory' => null, // Example: 'tmp' Default 'livewire-tmp'
'middleware' => null, // Example: 'throttle:5,1' Default: 'throttle:60,1'
'preview_mimes' => [ // Supported file types for temporary pre-signed file URLs.
'png', 'gif', 'bmp', 'svg', 'wav', 'mp4',
'mov', 'avi', 'wmv', 'mp3', 'm4a',
'jpg', 'jpeg', 'mpga', 'webp', 'wma',
],
'max_upload_time' => 5, // Max duration (in minutes) before an upload gets invalidated.
],
/*
|--------------------------------------------------------------------------
| Manifest File Path
|--------------------------------------------------------------------------
|
| This value sets the path to the Livewire manifest file.
| The default should work for most cases (which is
| "<app_root>/bootstrap/cache/livewire-components.php"), but for specific
| cases like when hosting on Laravel Vapor, it could be set to a different value.
|
| Example: for Laravel Vapor, it would be "/tmp/storage/bootstrap/cache/livewire-components.php".
|
*/
'manifest_path' => null,
/*
|--------------------------------------------------------------------------
| Back Button Cache
|--------------------------------------------------------------------------
|
| This value determines whether the back button cache will be used on pages
| that contain Livewire. By disabling back button cache, it ensures that
| the back button shows the correct state of components, instead of
| potentially stale, cached data.
|
| Setting it to "false" (default) will disable back button cache.
|
*/
'back_button_cache' => false,
/*
|--------------------------------------------------------------------------
| Render On Redirect
|--------------------------------------------------------------------------
|
| This value determines whether Livewire will render before it's redirected
| or not. Setting it to "false" (default) will mean the render method is
| skipped when redirecting. And "true" will mean the render method is
| run before redirecting. Browsers bfcache can store a potentially
| stale view if render is skipped on redirect.
|
*/
'render_on_redirect' => false,
];

View File

@ -0,0 +1,40 @@
<?php
namespace Database\Factories;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;
/**
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\User>
*/
class UserFactory extends Factory
{
/**
* Define the model's default state.
*
* @return array<string, mixed>
*/
public function definition()
{
return [
'name' => fake()->name(),
'email' => fake()->unique()->safeEmail(),
'email_verified_at' => now(),
'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
'remember_token' => Str::random(10),
];
}
/**
* Indicate that the model's email address should be unverified.
*
* @return static
*/
public function unverified()
{
return $this->state(fn (array $attributes) => [
'email_verified_at' => null,
]);
}
}

View File

@ -0,0 +1,37 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->string('avatar')->nullable();
$table->rememberToken();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('users');
}
};

View File

@ -0,0 +1,32 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('password_resets', function (Blueprint $table) {
$table->string('email')->index();
$table->string('token');
$table->timestamp('created_at')->nullable();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('password_resets');
}
};

View File

@ -0,0 +1,36 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('failed_jobs', function (Blueprint $table) {
$table->id();
$table->string('uuid')->unique();
$table->text('connection');
$table->text('queue');
$table->longText('payload');
$table->longText('exception');
$table->timestamp('failed_at')->useCurrent();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('failed_jobs');
}
};

View File

@ -0,0 +1,37 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('personal_access_tokens', function (Blueprint $table) {
$table->id();
$table->morphs('tokenable');
$table->string('name');
$table->string('token', 64)->unique();
$table->text('abilities')->nullable();
$table->timestamp('last_used_at')->nullable();
$table->timestamp('expires_at')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('personal_access_tokens');
}
};

View File

@ -0,0 +1,29 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration {
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('users', function (Blueprint $table) {
$table->datetime('last_login_at')->nullable();
$table->string('last_login_ip')->nullable();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('users', function (Blueprint $table) {
$table->removeColumn('last_login_at');
$table->removeColumn('last_login_ip');
});
}
};

View File

@ -0,0 +1,141 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
use Spatie\Permission\PermissionRegistrar;
class CreatePermissionTables extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
$tableNames = config('permission.table_names');
$columnNames = config('permission.column_names');
$teams = config('permission.teams');
if (empty($tableNames)) {
throw new \Exception('Error: config/permission.php not loaded. Run [php artisan config:clear] and try again.');
}
if ($teams && empty($columnNames['team_foreign_key'] ?? null)) {
throw new \Exception('Error: team_foreign_key on config/permission.php not loaded. Run [php artisan config:clear] and try again.');
}
Schema::create($tableNames['permissions'], function (Blueprint $table) {
$table->bigIncrements('id'); // permission id
$table->string('name'); // For MySQL 8.0 use string('name', 125);
$table->string('guard_name'); // For MySQL 8.0 use string('guard_name', 125);
$table->timestamps();
$table->unique(['name', 'guard_name']);
});
Schema::create($tableNames['roles'], function (Blueprint $table) use ($teams, $columnNames) {
$table->bigIncrements('id'); // role id
if ($teams || config('permission.testing')) { // permission.testing is a fix for sqlite testing
$table->unsignedBigInteger($columnNames['team_foreign_key'])->nullable();
$table->index($columnNames['team_foreign_key'], 'roles_team_foreign_key_index');
}
$table->string('name'); // For MySQL 8.0 use string('name', 125);
$table->string('guard_name'); // For MySQL 8.0 use string('guard_name', 125);
$table->timestamps();
if ($teams || config('permission.testing')) {
$table->unique([$columnNames['team_foreign_key'], 'name', 'guard_name']);
} else {
$table->unique(['name', 'guard_name']);
}
});
Schema::create($tableNames['model_has_permissions'], function (Blueprint $table) use ($tableNames, $columnNames, $teams) {
$table->unsignedBigInteger(PermissionRegistrar::$pivotPermission);
$table->string('model_type');
$table->unsignedBigInteger($columnNames['model_morph_key']);
$table->index([$columnNames['model_morph_key'], 'model_type'], 'model_has_permissions_model_id_model_type_index');
$table->foreign(PermissionRegistrar::$pivotPermission)
->references('id') // permission id
->on($tableNames['permissions'])
->onDelete('cascade');
if ($teams) {
$table->unsignedBigInteger($columnNames['team_foreign_key']);
$table->index($columnNames['team_foreign_key'], 'model_has_permissions_team_foreign_key_index');
$table->primary([$columnNames['team_foreign_key'], PermissionRegistrar::$pivotPermission, $columnNames['model_morph_key'], 'model_type'],
'model_has_permissions_permission_model_type_primary');
} else {
$table->primary([PermissionRegistrar::$pivotPermission, $columnNames['model_morph_key'], 'model_type'],
'model_has_permissions_permission_model_type_primary');
}
});
Schema::create($tableNames['model_has_roles'], function (Blueprint $table) use ($tableNames, $columnNames, $teams) {
$table->unsignedBigInteger(PermissionRegistrar::$pivotRole);
$table->string('model_type');
$table->unsignedBigInteger($columnNames['model_morph_key']);
$table->index([$columnNames['model_morph_key'], 'model_type'], 'model_has_roles_model_id_model_type_index');
$table->foreign(PermissionRegistrar::$pivotRole)
->references('id') // role id
->on($tableNames['roles'])
->onDelete('cascade');
if ($teams) {
$table->unsignedBigInteger($columnNames['team_foreign_key']);
$table->index($columnNames['team_foreign_key'], 'model_has_roles_team_foreign_key_index');
$table->primary([$columnNames['team_foreign_key'], PermissionRegistrar::$pivotRole, $columnNames['model_morph_key'], 'model_type'],
'model_has_roles_role_model_type_primary');
} else {
$table->primary([PermissionRegistrar::$pivotRole, $columnNames['model_morph_key'], 'model_type'],
'model_has_roles_role_model_type_primary');
}
});
Schema::create($tableNames['role_has_permissions'], function (Blueprint $table) use ($tableNames) {
$table->unsignedBigInteger(PermissionRegistrar::$pivotPermission);
$table->unsignedBigInteger(PermissionRegistrar::$pivotRole);
$table->foreign(PermissionRegistrar::$pivotPermission)
->references('id') // permission id
->on($tableNames['permissions'])
->onDelete('cascade');
$table->foreign(PermissionRegistrar::$pivotRole)
->references('id') // role id
->on($tableNames['roles'])
->onDelete('cascade');
$table->primary([PermissionRegistrar::$pivotPermission, PermissionRegistrar::$pivotRole], 'role_has_permissions_permission_id_role_id_primary');
});
app('cache')
->store(config('permission.cache.store') != 'default' ? config('permission.cache.store') : null)
->forget(config('permission.cache.key'));
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
$tableNames = config('permission.table_names');
if (empty($tableNames)) {
throw new \Exception('Error: config/permission.php not found and defaults could not be merged. Please publish the package configuration before proceeding, or drop the tables manually.');
}
Schema::drop($tableNames['role_has_permissions']);
Schema::drop($tableNames['model_has_roles']);
Schema::drop($tableNames['model_has_permissions']);
Schema::drop($tableNames['roles']);
Schema::drop($tableNames['permissions']);
}
}

View File

@ -0,0 +1,27 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration {
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('users', function (Blueprint $table) {
$table->string('profile_photo_path', 2048)->nullable()->after('email');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('users', function (Blueprint $table) {
$table->dropColumn('profile_photo_path');
});
}
};

View File

@ -0,0 +1,72 @@
<?php
namespace Database\Seeders;
use App\Models\User;
use Illuminate\Database\Seeder;
use Spatie\Permission\Models\Permission;
use Spatie\Permission\Models\Role;
class RolesPermissionsSeeder extends Seeder
{
/**
* Run the database seeds.
*/
public function run(): void
{
$abilities = [
'read',
'write',
'create',
];
$permissions_by_role = [
'administrator' => [
'user management',
'content management',
'financial management',
'reporting',
'payroll',
'disputes management',
'api controls',
'database management',
'repository management',
],
'developer' => [
'api controls',
'database management',
'repository management',
],
'analyst' => [
'content management',
'financial management',
'reporting',
'payroll',
],
'support' => [
'reporting',
],
'trial' => [
],
];
foreach ($permissions_by_role['administrator'] as $permission) {
foreach ($abilities as $ability) {
Permission::create(['name' => $ability . ' ' . $permission]);
}
}
foreach ($permissions_by_role as $role => $permissions) {
$full_permissions_list = [];
foreach ($abilities as $ability) {
foreach ($permissions as $permission) {
$full_permissions_list[] = $ability . ' ' . $permission;
}
}
Role::create(['name' => $role])->syncPermissions($full_permissions_list);
}
User::find(1)->assignRole('administrator');
User::find(2)->assignRole('developer');
}
}

View File

@ -0,0 +1,33 @@
<?php
namespace Database\Seeders;
use App\Models\User;
use Faker\Generator;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\Hash;
class UsersSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run(Generator $faker)
{
$demoUser = User::create([
'name' => $faker->name,
'email' => 'demo@demo.com',
'password' => Hash::make('demo'),
'email_verified_at' => now(),
]);
$demoUser2 = User::create([
'name' => $faker->name,
'email' => 'admin@demo.com',
'password' => Hash::make('demo'),
'email_verified_at' => now(),
]);
}
}

17151
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

14
public/vendor/livewire/livewire.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

1
public/vendor/livewire/manifest.json vendored Normal file
View File

@ -0,0 +1 @@
{"/livewire.js":"/livewire.js?id=90730a3b0e7144480175"}

BIN
resources/_keenthemes/src/.DS_Store vendored Normal file

Binary file not shown.

View File

@ -0,0 +1,137 @@
"use strict";
// Class definition
var KTChartMap = function () {
// Charts widgets
var initChartMap = function() {
var element = document.getElementById("chartdiv");
if ( !element ) {
return;
}
// Create root and chart
var root = am5.Root.new("chartdiv");
// Set themes
root.setThemes([
am5themes_Animated.new(root)
]);
var chart = root.container.children.push(
am5map.MapChart.new(root, {
panX: "rotateX",
projection: am5map.geoNaturalEarth1()
})
);
// Create polygon series
var polygonSeries = chart.series.push(
am5map.MapPolygonSeries.new(root, {
geoJSON: am5geodata_continentsLow,
exclude: ["antarctica"]
})
);
polygonSeries.mapPolygons.template.setAll({
tooltipText: "{name}",
interactive: true,
templateField: "settings"
});
polygonSeries.mapPolygons.template.states.create("hover", {
fill: am5.color(0x677935)
});
var colors = am5.ColorSet.new(root, {});
polygonSeries.data.setAll([{
id: "europe",
settings: {
fill: colors.next(),
fillPattern: am5.LinePattern.new(root, {
color: am5.color(0xffffff),
rotation: 45,
strokeWidth: 1
})
}
}, {
id: "asia",
settings: {
fill: colors.next(),
fillPattern: am5.RectanglePattern.new(root, {
color: am5.color(0xffffff),
checkered: true
})
}
}, {
id: "africa",
settings: {
fill: colors.next(),
fillPattern: am5.CirclePattern.new(root, {
color: am5.color(0xffffff),
checkered: true
})
}
}, {
id: "northAmerica",
settings: {
fill: colors.next(),
fillPattern: am5.CirclePattern.new(root, {
color: am5.color(0xffffff)
})
}
}, {
id: "southAmerica",
settings: {
fill: colors.next(),
fillPattern: am5.LinePattern.new(root, {
color: am5.color(0xffffff),
rotation: 90,
strokeWidth: 2
})
}
}, {
id: "oceania",
settings: {
fill: colors.next(),
fillPattern: am5.LinePattern.new(root, {
color: am5.color(0xffffff),
})
}
}])
// Init chart
initChart();
// Update chart on theme mode change
KTThemeMode.on("kt.thememode.change", function() {
if (chart.rendered) {
chart.self.destroy();
}
initChart();
});
}
// Public methods
return {
init: function () {
// Charts widgets
initChartMap();
}
}
}();
// Webpack support
if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
module.exports = KTChartMap;
}
// On document ready
KTUtil.onDOMContentLoaded(function() {
KTChartMap.init();
});

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 184 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 231 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Some files were not shown because too many files have changed in this diff Show More