├── .env.example
├── .github
└── workflows
│ └── main.yml
├── .gitignore
├── .php_cs
├── .phpstorm.meta.php
├── _ide_helper.php
├── _ide_helper_models.php
├── app
├── Console
│ ├── Commands
│ │ └── ComponentsScaffoldMakeCommand.php
│ └── Kernel.php
├── Events
│ └── ProfileImageUploaded.php
├── Exceptions
│ ├── Handler.php
│ └── MissingModel.php
├── Filters
│ ├── Filter.php
│ ├── RoleFilter.php
│ └── UserFilter.php
├── Http
│ ├── Controllers
│ │ ├── Auth
│ │ │ ├── ForgotPasswordController.php
│ │ │ ├── LoginController.php
│ │ │ ├── ResetPasswordController.php
│ │ │ └── VerificationController.php
│ │ ├── ConfirmedEmailController.php
│ │ ├── Controller.php
│ │ ├── HomeController.php
│ │ └── Profile
│ │ │ └── UserController.php
│ ├── HasAcceptedInvitationAuth.php
│ ├── Kernel.php
│ ├── Livewire
│ │ ├── AcceptedInvitationComponent.php
│ │ ├── CanFlash.php
│ │ ├── CreateRoleComponent.php
│ │ ├── CreateUserComponent.php
│ │ ├── DeleteRoleComponent.php
│ │ ├── DeleteUserComponent.php
│ │ ├── EditRoleComponent.php
│ │ ├── EditUserComponent.php
│ │ ├── HasLivewireAuth.php
│ │ ├── HasTable.php
│ │ ├── IndexRoleComponent.php
│ │ ├── IndexUserComponent.php
│ │ └── Profile
│ │ │ ├── UpdateEmail.php
│ │ │ ├── UpdateImage.php
│ │ │ └── UpdatePassword.php
│ └── Middleware
│ │ ├── Authenticate.php
│ │ ├── Authorization.php
│ │ ├── CheckForMaintenanceMode.php
│ │ ├── EncryptCookies.php
│ │ ├── RedirectIfAuthenticated.php
│ │ ├── TrimStrings.php
│ │ ├── TrustProxies.php
│ │ └── VerifyCsrfToken.php
├── Listeners
│ └── ResizeImage.php
├── Mail
│ ├── InvitationMail.php
│ ├── NewEmailConfirmationMail.php
│ └── PasswordChangedMail.php
├── Models
│ ├── Permission.php
│ ├── PermissionRole.php
│ ├── Role.php
│ └── User.php
├── Providers
│ ├── AppServiceProvider.php
│ ├── AuthServiceProvider.php
│ ├── BroadcastServiceProvider.php
│ ├── EventServiceProvider.php
│ └── RouteServiceProvider.php
├── Rules
│ ├── OwnerRestrictedRule.php
│ ├── PasswordCheckRule.php
│ ├── PasswordRule.php
│ └── PermissionExistsRule.php
├── Scopes
│ └── VisibleToScope.php
├── Services
│ └── ForRouteGate.php
├── ViewModels
│ └── SaveRoleViewModel.php
└── helpers.php
├── artisan
├── bootstrap
├── app.php
└── cache
│ └── .gitignore
├── composer.json
├── composer.lock
├── config
├── app.php
├── auth.php
├── broadcasting.php
├── cache.php
├── database.php
├── filesystems.php
├── hashing.php
├── ide-helper.php
├── insights.php
├── livewire.php
├── logging.php
├── mail.php
├── queue.php
├── services.php
├── session.php
└── view.php
├── database
├── .gitignore
├── factories
│ ├── PermissionFactory.php
│ ├── RoleFactory.php
│ └── UserFactory.php
├── migrations
│ ├── 2013_03_11_165941_create_roles_table.php
│ ├── 2014_10_12_000000_create_users_table.php
│ ├── 2014_10_12_100000_create_password_resets_table.php
│ ├── 2020_02_03_125830_create_sessions_table.php
│ ├── 2020_02_03_132010_create_jobs_table.php
│ ├── 2020_03_26_110221_create_permissions_table.php
│ └── 2023_03_26_110250_create_permission_role_table.php
└── seeders
│ ├── DatabaseSeeder.php
│ ├── PermissionsTableSeeder.php
│ ├── RolesTableSeeder.php
│ └── UsersTableSeeder.php
├── package-lock.json
├── package.json
├── phpunit.xml
├── public
├── .htaccess
├── css
│ └── app.css
├── favicon.ico
├── images
│ └── default-user.png
├── index.php
├── js
│ ├── app.js
│ └── turbolinks.js
├── mix-manifest.json
├── robots.txt
├── web.config
└── webfonts
│ ├── fa-brands-400.eot
│ ├── fa-brands-400.svg
│ ├── fa-brands-400.ttf
│ ├── fa-brands-400.woff
│ ├── fa-brands-400.woff2
│ ├── fa-regular-400.eot
│ ├── fa-regular-400.svg
│ ├── fa-regular-400.ttf
│ ├── fa-regular-400.woff
│ ├── fa-regular-400.woff2
│ ├── fa-solid-900.eot
│ ├── fa-solid-900.svg
│ ├── fa-solid-900.ttf
│ ├── fa-solid-900.woff
│ └── fa-solid-900.woff2
├── readme.md
├── resources
├── css
│ ├── adminlte.css
│ ├── custom.css
│ ├── font-awesome.css
│ ├── google-font.css
│ └── icheck-bootstrap.css
├── images
│ └── default-user.png
├── js
│ └── app.js
├── lang
│ └── en
│ │ ├── auth.php
│ │ ├── pagination.php
│ │ ├── passwords.php
│ │ └── validation.php
├── views
│ ├── accepted-invitations
│ │ └── create.blade.php
│ ├── auth
│ │ ├── login.blade.php
│ │ ├── passwords
│ │ │ ├── confirm.blade.php
│ │ │ ├── email.blade.php
│ │ │ └── reset.blade.php
│ │ └── verify.blade.php
│ ├── components
│ │ ├── content-header.blade.php
│ │ ├── inputs
│ │ │ ├── button.blade.php
│ │ │ ├── dropdown.blade.php
│ │ │ ├── email.blade.php
│ │ │ ├── error.blade.php
│ │ │ ├── fa.blade.php
│ │ │ ├── file.blade.php
│ │ │ ├── password.blade.php
│ │ │ └── text.blade.php
│ │ ├── profile
│ │ │ └── element.blade.php
│ │ ├── savings
│ │ │ └── content.blade.php
│ │ └── tables
│ │ │ ├── entries-data.blade.php
│ │ │ ├── pagination.blade.php
│ │ │ ├── per-page.blade.php
│ │ │ ├── search.blade.php
│ │ │ ├── sort-by.blade.php
│ │ │ └── table.blade.php
│ ├── errors
│ │ ├── 401.blade.php
│ │ ├── 403.blade.php
│ │ ├── 404.blade.php
│ │ ├── 419.blade.php
│ │ ├── 429.blade.php
│ │ ├── 500.blade.php
│ │ ├── 503.blade.php
│ │ └── app.blade.php
│ ├── home.blade.php
│ ├── layouts
│ │ ├── _flash.blade.php
│ │ ├── _head.blade.php
│ │ ├── app.blade.php
│ │ └── guest-app.blade.php
│ ├── livewire
│ │ └── profile
│ │ │ ├── update-email.blade.php
│ │ │ ├── update-image.blade.php
│ │ │ └── update-password.blade.php
│ ├── mails
│ │ ├── invitation-mail.blade.php
│ │ ├── new-email-confirmation-mail.blade.php
│ │ └── password-changed-mail.blade.php
│ ├── profile
│ │ └── users
│ │ │ └── index.blade.php
│ ├── roles
│ │ ├── create.blade.php
│ │ ├── delete.blade.php
│ │ ├── edit.blade.php
│ │ └── index.blade.php
│ └── users
│ │ ├── create.blade.php
│ │ ├── delete.blade.php
│ │ ├── edit.blade.php
│ │ └── index.blade.php
└── webfonts
│ ├── fa-brands-400.eot
│ ├── fa-brands-400.svg
│ ├── fa-brands-400.ttf
│ ├── fa-brands-400.woff
│ ├── fa-brands-400.woff2
│ ├── fa-regular-400.eot
│ ├── fa-regular-400.svg
│ ├── fa-regular-400.ttf
│ ├── fa-regular-400.woff
│ ├── fa-regular-400.woff2
│ ├── fa-solid-900.eot
│ ├── fa-solid-900.svg
│ ├── fa-solid-900.ttf
│ ├── fa-solid-900.woff
│ └── fa-solid-900.woff2
├── routes
├── api.php
├── channels.php
├── console.php
└── web.php
├── server.php
├── storage
├── app
│ ├── .gitignore
│ └── public
│ │ └── .gitignore
├── debugbar
│ └── .gitignore
├── framework
│ ├── .gitignore
│ ├── cache
│ │ ├── .gitignore
│ │ └── data
│ │ │ └── .gitignore
│ ├── sessions
│ │ └── .gitignore
│ ├── testing
│ │ └── .gitignore
│ └── views
│ │ └── .gitignore
└── logs
│ └── .gitignore
├── stubs
├── controller.api.stub
├── controller.invokable.stub
├── controller.model.api.stub
├── controller.model.stub
├── controller.nested.api.stub
├── controller.nested.stub
├── controller.plain.stub
├── controller.stub
├── job.queued.stub
├── job.stub
├── laravellte
│ ├── create.class.stub
│ ├── create.test.stub
│ ├── create.view.stub
│ ├── delete.class.stub
│ ├── delete.test.stub
│ ├── delete.view.stub
│ ├── edit.class.stub
│ ├── edit.test.stub
│ ├── edit.view.stub
│ ├── index.class.stub
│ ├── index.filter.stub
│ ├── index.test.stub
│ ├── index.view.stub
│ ├── show.class.stub
│ ├── show.test.stub
│ └── show.view.stub
├── migration.create.stub
├── migration.stub
├── migration.update.stub
├── model.pivot.stub
├── model.stub
├── test.stub
└── test.unit.stub
├── tests
├── CreatesApplication.php
├── Feature
│ ├── Console
│ │ └── Commands
│ │ │ └── ComponentsScaffoldMakeCommandTest.php
│ └── Http
│ │ ├── Controllers
│ │ ├── Auth
│ │ │ ├── ForgotPasswordControllerTest.php
│ │ │ ├── LoginControllerTest.php
│ │ │ └── ResetPasswordControllerTest.php
│ │ ├── ConfirmedEmailControllerTest.php
│ │ ├── HomeControllerTest.php
│ │ └── Profile
│ │ │ └── UserControllerTest.php
│ │ └── Livewire
│ │ ├── AcceptedInvitationComponentTest.php
│ │ ├── CreateRoleComponentTest.php
│ │ ├── CreateUserComponentTest.php
│ │ ├── DeleteRoleComponentTest.php
│ │ ├── DeleteUserComponentTest.php
│ │ ├── EditRoleComponentTest.php
│ │ ├── EditUserComponentTest.php
│ │ ├── IndexRoleComponentTest.php
│ │ ├── IndexUserComponentTest.php
│ │ ├── Profile
│ │ ├── UpdateEmailTest.php
│ │ ├── UpdateImageTest.php
│ │ └── UpdatePasswordTest.php
│ │ └── TableTest.php
├── TestCase.php
├── Unit
│ ├── Filters
│ │ ├── RoleFilterTest.php
│ │ └── UserFilterTest.php
│ ├── Http
│ │ ├── AcceptedInvitationAuthTest.php
│ │ ├── Livewire
│ │ │ └── HasLivewireAuthTest.php
│ │ └── Middleware
│ │ │ ├── AuthenticateTest.php
│ │ │ └── AuthorizationTest.php
│ ├── Listeners
│ │ └── ResizeImageTest.php
│ ├── Mail
│ │ ├── InvitationMailTest.php
│ │ ├── NewEmailConfirmationMailTest.php
│ │ └── PasswordChangedMailTest.php
│ ├── Models
│ │ ├── PermissionRoleTest.php
│ │ ├── PermissionTest.php
│ │ ├── RoleTest.php
│ │ └── UserTest.php
│ ├── Providers
│ │ ├── AuthServiceProviderTest.php
│ │ └── EventServiceProviderTest.php
│ ├── Rules
│ │ ├── OwnerRestrictedRuleTest.php
│ │ ├── PasswordCheckRuleTest.php
│ │ ├── PasswordRuleTest.php
│ │ └── PermissionExistsRuleTest.php
│ ├── Scopes
│ │ └── VisibleToScopeTest.php
│ ├── Services
│ │ └── ForRouteGateTest.php
│ └── ViewModels
│ │ └── SaveRoleViewModelTest.php
└── helpers.php
└── webpack.mix.js
/.env.example:
--------------------------------------------------------------------------------
1 | APP_NAME="laravellte"
2 | APP_ENV=local
3 | APP_KEY=
4 | APP_DEBUG=true
5 | APP_URL=http://laravellte.test
6 |
7 | BUGSNAG_API_KEY=
8 |
9 | LOG_CHANNEL=stack
10 |
11 | DB_CONNECTION=mysql
12 | DB_HOST=localhost
13 | DB_DATABASE=laravellte
14 | DB_USERNAME=homestead
15 | DB_PASSWORD=secret
16 |
17 | BROADCAST_DRIVER=log
18 | CACHE_DRIVER=file
19 | QUEUE_CONNECTION=redis
20 | SESSION_DRIVER=file
21 | SESSION_LIFETIME=120
22 |
23 | MAIL_DRIVER=smtp
24 | MAIL_HOST=
25 | MAIL_PORT=
26 | MAIL_USERNAME=
27 | MAIL_PASSWORD=
28 | MAIL_ENCRYPTION=tls
29 |
30 | MAIL_FROM_ADDRESS=no-replay@laravellte.com
31 | MAIL_FROM_NAME="laravellte"
--------------------------------------------------------------------------------
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | on: push
2 |
3 | name: Run
4 | jobs:
5 | tests:
6 | name: Run tests
7 | runs-on: ubuntu-latest
8 | strategy:
9 | matrix:
10 | php: ['7.4']
11 | steps:
12 | - uses: actions/checkout@v1
13 | - name: Setup PHP
14 | uses: shivammathur/setup-php@v1
15 | with:
16 | php-version: ${{ matrix.php }}
17 | - name: Run composer install
18 | run: composer install -n --prefer-dist
19 | env:
20 | APP_ENV: testing
21 | - name: Prepare Laravel Application
22 | run: |
23 | cp .env.example .env
24 | php artisan key:generate
25 | - name: Cache composer dependencies
26 | uses: actions/cache@v1
27 | with:
28 | path: vendor
29 | key: composer-${{ hashFiles('composer.lock') }}
30 | - name: Run php cs fixer
31 | run: vendor/bin/php-cs-fixer fix --dry-run
32 | - name: Run insights
33 | run: php artisan insights --no-interaction --min-quality=90 --min-complexity=85 --min-architecture=90 --min-style=95
34 | - name: Run tests
35 | run: php artisan test --parallel
36 | env:
37 | APP_ENV: testing
38 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .php_cs.cache
2 | /node_modules
3 | /public/hot
4 | /public/storage
5 | /storage/*.key
6 | .env
7 | vendor/
8 | .phpunit.result.cache
9 | npm-debug.log
10 | .idea
--------------------------------------------------------------------------------
/.php_cs:
--------------------------------------------------------------------------------
1 | setFinder(
8 | PhpCsFixer\Finder::create()
9 | ->in(app_path())
10 | ->in(config_path())
11 | ->in(database_path())
12 | ->notPath(database_path('migrations'))
13 | ->in(resource_path('lang'))
14 | ->in(base_path('routes'))
15 | ->in(base_path('tests'))
16 | )
17 | ->setRules([
18 | '@Laravel' => true,
19 | ]);
20 |
--------------------------------------------------------------------------------
/app/Console/Kernel.php:
--------------------------------------------------------------------------------
1 | load(__DIR__.'/Commands');
35 |
36 | require base_path('routes/console.php');
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/app/Events/ProfileImageUploaded.php:
--------------------------------------------------------------------------------
1 | user = $user;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/app/Exceptions/Handler.php:
--------------------------------------------------------------------------------
1 | $value) {
18 | if (! method_exists($this, $name)) {
19 | continue;
20 | }
21 |
22 | if (is_array($value)) {
23 | $this->$name($value[0], $value[1]);
24 | } else {
25 | $this->$name($value);
26 | }
27 | }
28 |
29 | return $this;
30 | }
31 |
32 | /**
33 | * Order results by field in specific order.
34 | *
35 | * @param string $field
36 | * @param string $direction
37 | * @return \Illuminate\Database\Eloquent\Builder
38 | */
39 | public function orderByField($field, $direction)
40 | {
41 | $this->orderBy($field, $direction);
42 |
43 | return $this;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/app/Filters/RoleFilter.php:
--------------------------------------------------------------------------------
1 | when($term, function ($query, $term) {
16 | $query->where('name', 'LIKE', "%$term%");
17 | });
18 |
19 | return $this;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/app/Filters/UserFilter.php:
--------------------------------------------------------------------------------
1 | when($term, function ($query, $term) {
16 | $query->where('email', 'LIKE', "%$term%");
17 | });
18 |
19 | return $this;
20 | }
21 |
22 | /**
23 | * Filter by role.
24 | *
25 | * @param mixed $roleId
26 | * @return \Illuminate\Database\Eloquent\Builder
27 | */
28 | public function roleId($roleId = null)
29 | {
30 | $this->when($roleId, function ($query, $roleId) {
31 | $query->where('role_id', $roleId);
32 | });
33 |
34 | return $this;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Auth/ForgotPasswordController.php:
--------------------------------------------------------------------------------
1 | middleware('guest');
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Auth/LoginController.php:
--------------------------------------------------------------------------------
1 | middleware('guest')->except('logout');
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Auth/ResetPasswordController.php:
--------------------------------------------------------------------------------
1 | middleware('guest');
40 | }
41 |
42 | /**
43 | * Get the password reset validation rules.
44 | *
45 | * @return array
46 | */
47 | protected function rules()
48 | {
49 | return [
50 | 'token' => 'required',
51 | 'email' => 'required|email',
52 | 'password' => new PasswordRule(request()->password_confirmation),
53 | ];
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Auth/VerificationController.php:
--------------------------------------------------------------------------------
1 | middleware('auth');
39 | $this->middleware('signed')->only('verify');
40 | $this->middleware('throttle:6,1')->only('verify', 'resend');
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/app/Http/Controllers/ConfirmedEmailController.php:
--------------------------------------------------------------------------------
1 | logout();
21 |
22 | abort_if(! $request->hasValidSignature(), Response::HTTP_FORBIDDEN);
23 |
24 | $user = User::find($request->user);
25 |
26 | abort_if($user === null, Response::HTTP_FORBIDDEN);
27 |
28 | $user->update([
29 | 'email' => $request->new_email,
30 | ]);
31 |
32 | msg_success('Your email has been successfully update.');
33 |
34 | return redirect()->route('login');
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Controller.php:
--------------------------------------------------------------------------------
1 | auth()->user()]);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/app/Http/HasAcceptedInvitationAuth.php:
--------------------------------------------------------------------------------
1 | hasValidSignature()) {
22 | abort(Response::HTTP_FORBIDDEN, 'The link does not have a valid signature or it is expired.');
23 | }
24 |
25 | if ($user === null) {
26 | abort(Response::HTTP_FORBIDDEN, 'User was not found.');
27 | }
28 |
29 | if ($user->password !== null) {
30 | return abort(Response::HTTP_FORBIDDEN, 'The link has already been used.');
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/app/Http/Livewire/AcceptedInvitationComponent.php:
--------------------------------------------------------------------------------
1 | user = User::find($request->user);
35 | $this->authorizeInvitation($request, $this->user);
36 | }
37 |
38 | /**
39 | * Render the component view.
40 | *
41 | * @return \Illuminate\View\View
42 | */
43 | public function render()
44 | {
45 | return view('accepted-invitations.create')
46 | ->extends('layouts.guest-app');
47 | }
48 |
49 | /**
50 | * Submit the form.
51 | *
52 | * @return void
53 | */
54 | public function submit()
55 | {
56 | $this->validate(['newPassword' => [new PasswordRule($this->newPasswordConfirmation)]]);
57 | $this->user->savePassword($this->newPassword);
58 |
59 | auth()->login($this->user);
60 |
61 | return redirect()->to('/home');
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/app/Http/Livewire/CanFlash.php:
--------------------------------------------------------------------------------
1 | dispatchBrowserEvent('flash', [
16 | 'level' => 'alert-danger',
17 | 'message' => $message,
18 | ]);
19 | }
20 |
21 | /**
22 | * Dispatch browser success flash event.
23 | *
24 | * @param string $message
25 | * @return void
26 | */
27 | protected function dispatchFlashSuccessEvent($message)
28 | {
29 | return $this->dispatchBrowserEvent('flash', [
30 | 'level' => 'alert-success',
31 | 'message' => $message,
32 | ]);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/app/Http/Livewire/CreateUserComponent.php:
--------------------------------------------------------------------------------
1 | roles = Role::orderBy('name')->get();
32 |
33 | return view('users.create')
34 | ->extends('layouts.app');
35 | }
36 |
37 | /**
38 | * Store new user.
39 | *
40 | * @return \Illuminate\Http\Response
41 | */
42 | public function store()
43 | {
44 | $this->validate();
45 |
46 | $user = User::create([
47 | 'email' => $this->user['email'],
48 | 'role_id' => $this->user['role_id'],
49 | AppServiceProvider::OWNER_FIELD => auth()->id(),
50 | ]);
51 |
52 | msg_success('User has been successfully created.');
53 |
54 | Mail::to($user)
55 | ->queue(new InvitationMail($user, Carbon::tomorrow()));
56 |
57 | return redirect()->route('users.index');
58 | }
59 |
60 | /**
61 | * Validation rules.
62 | *
63 | * @return array
64 | */
65 | protected function rules()
66 | {
67 | return [
68 | 'user.email' => [
69 | 'required',
70 | 'email',
71 | Rule::unique('users', 'email'),
72 | ],
73 | 'user.role_id' => [
74 | 'required',
75 | Rule::exists('roles', 'id'),
76 | ],
77 | ];
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/app/Http/Livewire/DeleteRoleComponent.php:
--------------------------------------------------------------------------------
1 | role->isAdmin()) {
28 | $this->dispatchFlashDangerEvent('Admin role cannot be deleted.');
29 |
30 | return;
31 | }
32 |
33 | User::where('role_id', $this->role)->delete();
34 |
35 | $this->role->delete();
36 |
37 | $this->emit('entity-deleted');
38 |
39 | $this->dispatchFlashSuccessEvent('Role has been successfully deleted.');
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/app/Http/Livewire/DeleteUserComponent.php:
--------------------------------------------------------------------------------
1 | user()->isHimself($this->user)) {
28 | throw new AuthorizationException();
29 | }
30 |
31 | $this->dispatchFlashSuccessEvent('User has been successfully deleted.');
32 |
33 | $this->user->delete();
34 |
35 | $this->emit('entity-deleted');
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/app/Http/Livewire/EditUserComponent.php:
--------------------------------------------------------------------------------
1 | user->isHimself(auth()->user())) {
29 | throw new AuthorizationException();
30 | }
31 | }
32 |
33 | /**
34 | * Render the component view.
35 | *
36 | * @return \Illuminate\View\View
37 | */
38 | public function render()
39 | {
40 | $this->roles = Role::orderBy('name')->get();
41 |
42 | return view('users.edit')
43 | ->extends('layouts.app');
44 | }
45 |
46 | /**
47 | * Update existing user.
48 | *
49 | * @return \Illuminate\Http\Response
50 | */
51 | public function update()
52 | {
53 | $this->validate($this->rules());
54 |
55 | $this->user->save();
56 |
57 | msg_success('User has been successfully updated.');
58 |
59 | return redirect()->route('users.index');
60 | }
61 |
62 | /**
63 | * Validation rules.
64 | *
65 | * @return array
66 | */
67 | protected function rules()
68 | {
69 | return [
70 | 'user.email' => [
71 | 'required',
72 | 'email',
73 | Rule::unique('users', 'email')->ignore($this->user->id),
74 | ],
75 | 'user.role_id' => [
76 | 'required',
77 | 'exists:roles,id',
78 | ],
79 | ];
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/app/Http/Livewire/HasLivewireAuth.php:
--------------------------------------------------------------------------------
1 | guest()) {
29 | throw new AuthenticationException();
30 | }
31 |
32 | $this->getPermissionName();
33 |
34 | $this->authorize('for-route', [$this->permissionName, $this->getModel()]);
35 | }
36 |
37 | /**
38 | * Get bind model.
39 | *
40 | * @return mixed
41 | */
42 | public function getModel()
43 | {
44 | if (method_exists($this, 'setModel')) {
45 | return $this->setModel();
46 | }
47 |
48 | return collect(get_object_vars($this))
49 | ->filter(function ($variable) {
50 | return $variable instanceof Model;
51 | })->first();
52 | }
53 |
54 | /**
55 | * Get permission name.
56 | *
57 | * @return void
58 | */
59 | public function getPermissionName()
60 | {
61 | if (isset($this->permissionName)) {
62 | return;
63 | }
64 |
65 | $splitted = explode('-', self::getName());
66 | $this->permissionName = Str::plural($splitted[1]).'.'.$splitted[0];
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/app/Http/Livewire/HasTable.php:
--------------------------------------------------------------------------------
1 | sortField === $field && $this->sortDirection === 'asc') {
31 | $this->sortDirection = 'desc';
32 | } elseif ($this->sortField === $field && $this->sortDirection === 'asc') {
33 | $this->sortDirection = 'asc';
34 | } else {
35 | $this->sortDirection = 'asc';
36 | }
37 |
38 | $this->sortField = $field;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/app/Http/Livewire/IndexRoleComponent.php:
--------------------------------------------------------------------------------
1 | 'render'];
20 |
21 | /**
22 | * Render the component view.
23 | *
24 | * @return \Illuminate\View\View
25 | */
26 | public function render()
27 | {
28 | $roles = Role::filter([
29 | 'search' => $this->search,
30 | 'orderByField' => [$this->sortField, $this->sortDirection],
31 | ])->paginate($this->perPage);
32 |
33 | return view('roles.index', ['roles' => $roles])
34 | ->extends('layouts.app');
35 | }
36 |
37 | /**
38 | * Reset pagination back to page one if search query is changed.
39 | *
40 | * @return void
41 | */
42 | public function updatedSearch()
43 | {
44 | $this->resetPage();
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/app/Http/Livewire/IndexUserComponent.php:
--------------------------------------------------------------------------------
1 | 'render'];
30 |
31 | /**
32 | * Render the component view.
33 | *
34 | * @return \Illuminate\View\View
35 | */
36 | public function render()
37 | {
38 | $users = User::with('role')
39 | ->filter([
40 | 'orderByField' => [$this->sortField, $this->sortDirection],
41 | 'search' => $this->search,
42 | 'roleId' => $this->roleId,
43 | ])->paginate($this->perPage);
44 |
45 | $roles = Role::orderBy('name')->get();
46 |
47 | return view('users.index', ['users' => $users, 'roles' => $roles])
48 | ->extends('layouts.app');
49 | }
50 |
51 | /**
52 | * Reset pagination back to page one if search query is changed.
53 | *
54 | * @return void
55 | */
56 | public function updatedSearch()
57 | {
58 | $this->resetPage();
59 | }
60 |
61 | /**
62 | * Reset pagination back to page one if roleId query is changed.
63 | *
64 | * @return void
65 | */
66 | public function updatedRoleId()
67 | {
68 | $this->resetPage();
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/app/Http/Livewire/Profile/UpdateEmail.php:
--------------------------------------------------------------------------------
1 | guest()) {
35 | throw new AuthenticationException();
36 | }
37 | }
38 |
39 | /**
40 | * Component mount.
41 | *
42 | * @return void
43 | */
44 | public function mount()
45 | {
46 | $this->user = auth()->user();
47 | }
48 |
49 | /**
50 | * Submit the form.
51 | *
52 | * @return void
53 | */
54 | public function submit()
55 | {
56 | $this->validate($this->validationRules());
57 |
58 | Mail::to($this->email)
59 | ->send(new NewEmailConfirmationMail($this->user, Carbon::tomorrow(), $this->email));
60 |
61 | $this->dispatchFlashSuccessEvent(
62 | "Confirmation email was sent to {$this->email}. Please verify your new email address."
63 | );
64 |
65 | $this->dispatchBrowserEvent('close');
66 |
67 | $this->clearInput();
68 | }
69 |
70 | /**
71 | * Render the component view.
72 | *
73 | * @return \Illuminate\View\View
74 | */
75 | public function render()
76 | {
77 | return view('livewire.profile.update-email');
78 | }
79 |
80 | /**
81 | * Get the validation rules.
82 | *
83 | * @return array
84 | */
85 | private function validationRules()
86 | {
87 | return [
88 | 'email' => [
89 | 'required',
90 | 'email',
91 | 'unique:users,email',
92 | ],
93 | 'currentPassword' => [
94 | 'required',
95 | new PasswordCheckRule($this->user),
96 | ],
97 | ];
98 | }
99 |
100 | /**
101 | * Reset public properties back to empty string.
102 | *
103 | * @return void
104 | */
105 | private function clearInput()
106 | {
107 | $this->email = '';
108 | $this->currentPassword = '';
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/app/Http/Livewire/Profile/UpdateImage.php:
--------------------------------------------------------------------------------
1 | guest()) {
30 | throw new AuthenticationException();
31 | }
32 | }
33 |
34 | /**
35 | * Component mount.
36 | *
37 | * @return void
38 | */
39 | public function mount()
40 | {
41 | $this->user = auth()->user();
42 | }
43 |
44 | /**
45 | * Submit the form.
46 | *
47 | * @return void
48 | */
49 | public function submit()
50 | {
51 | $this->validate($this->validationRules());
52 |
53 | if ($this->user->image !== null) {
54 | Storage::disk('avatar')->delete("{$this->user->image}");
55 | }
56 |
57 | $imageName = $this->image->store('/', 'avatar');
58 |
59 | $this->user->saveImage($imageName);
60 |
61 | ProfileImageUploaded::dispatch($this->user);
62 |
63 | msg_success('Your profile\'s image has been successfully updated');
64 |
65 | return redirect()->route('profile.users.index');
66 | }
67 |
68 | /**
69 | * Render the component view.
70 | *
71 | * @return \Illuminate\View\View
72 | */
73 | public function render()
74 | {
75 | return view('livewire.profile.update-image');
76 | }
77 |
78 | /**
79 | * Get the validation rules.
80 | *
81 | * @return array
82 | */
83 | private function validationRules()
84 | {
85 | return [
86 | 'image' => [
87 | 'required',
88 | 'image',
89 | 'dimensions:min_width=100,min_height=100',
90 | ],
91 | ];
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/app/Http/Livewire/Profile/UpdatePassword.php:
--------------------------------------------------------------------------------
1 | guest()) {
38 | throw new AuthenticationException();
39 | }
40 | }
41 |
42 | /**
43 | * Component mount.
44 | *
45 | * @return void
46 | */
47 | public function mount()
48 | {
49 | $this->user = auth()->user();
50 | }
51 |
52 | /**
53 | * Submit the form.
54 | *
55 | * @return void
56 | */
57 | public function submit()
58 | {
59 | $this->validate($this->validationRules());
60 |
61 | $this->user->savePassword($this->newPassword);
62 |
63 | Mail::to($this->user->email)
64 | ->send(new PasswordChangedMail());
65 |
66 | $this->dispatchBrowserEvent('close');
67 |
68 | $this->dispatchFlashSuccessEvent('You password has been successfully updated.');
69 |
70 | $this->clearInput();
71 | }
72 |
73 | /**
74 | * Render the component view.
75 | *
76 | * @return \Illuminate\View\View
77 | */
78 | public function render()
79 | {
80 | return view('livewire.profile.update-password');
81 | }
82 |
83 | /**
84 | * Get the validation rules.
85 | *
86 | * @return array
87 | */
88 | private function validationRules()
89 | {
90 | return [
91 | 'newPassword' => [
92 | new PasswordRule($this->newPasswordConfirmation),
93 | ],
94 | 'currentPassword' => [
95 | 'required',
96 | new PasswordCheckRule($this->user),
97 | ],
98 | ];
99 | }
100 |
101 | /**
102 | * Reset public properties back to empty string.
103 | *
104 | * @return void
105 | */
106 | private function clearInput()
107 | {
108 | $this->newPassword = '';
109 | $this->newPasswordConfirmation = '';
110 | $this->currentPassword = '';
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/app/Http/Middleware/Authenticate.php:
--------------------------------------------------------------------------------
1 | expectsJson()) {
18 | return route('login');
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/app/Http/Middleware/Authorization.php:
--------------------------------------------------------------------------------
1 | route()->action['controller'];
21 |
22 | $model = (new ImplicitRouteBinding(new Container()))->resolveComponentProps(
23 | $request->route(), new $component()
24 | );
25 |
26 | Gate::authorize('for-route', [$request->route()->getName(), $model->first() ?? null]);
27 |
28 | return $next($request);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/app/Http/Middleware/CheckForMaintenanceMode.php:
--------------------------------------------------------------------------------
1 | check()) {
22 | return redirect(RouteServiceProvider::HOME);
23 | }
24 |
25 | return $next($request);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/app/Http/Middleware/TrimStrings.php:
--------------------------------------------------------------------------------
1 | get("{$event->user->image}");
23 |
24 | Image::make($file)
25 | ->resize(100, 100)
26 | ->save(config('filesystems.disks.avatar.root')."/{$event->user->image}");
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/app/Mail/InvitationMail.php:
--------------------------------------------------------------------------------
1 | user = $user;
36 | $this->validUntil = $validUntil;
37 | }
38 |
39 | /**
40 | * Build the message.
41 | *
42 | * @return $this
43 | */
44 | public function build()
45 | {
46 | return $this->from(config('mail.from.address'), config('mail.from.name'))
47 | ->subject('Welcome')
48 | ->markdown('mails.invitation-mail', ['signedUrl' => $this->createTemporarySignedRoute()]);
49 | }
50 |
51 | private function createTemporarySignedRoute()
52 | {
53 | return URL::temporarySignedRoute(
54 | 'accepted-invitations.create',
55 | $this->validUntil,
56 | ['user' => $this->user->id]
57 | );
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/app/Mail/NewEmailConfirmationMail.php:
--------------------------------------------------------------------------------
1 | user = $user;
40 | $this->validUntil = $validUntil;
41 | $this->newEmail = $newEmail;
42 | }
43 |
44 | /**
45 | * Build the message.
46 | *
47 | * @return $this
48 | */
49 | public function build()
50 | {
51 | return $this->from(config('mail.from.address'), config('mail.from.name'))
52 | ->subject('Please confirm your new email address.')
53 | ->markdown('mails.new-email-confirmation-mail', [
54 | 'signedUrl' => $this->createTemporarySignedRoute(),
55 | 'newEmail' => $this->newEmail,
56 | ]);
57 | }
58 |
59 | private function createTemporarySignedRoute()
60 | {
61 | return URL::temporarySignedRoute(
62 | 'confirmed-emails.store',
63 | $this->validUntil,
64 | ['user' => $this->user->id, 'new_email' => $this->newEmail]
65 | );
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/app/Mail/PasswordChangedMail.php:
--------------------------------------------------------------------------------
1 | from(config('mail.from.address'), config('mail.from.name'))
22 | ->subject('Security notification regarding your password')
23 | ->markdown('mails.password-changed-mail');
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/app/Models/Permission.php:
--------------------------------------------------------------------------------
1 | 'integer',
23 | ];
24 |
25 | /**
26 | * The roles that belong to the permissions.
27 | *
28 | * @return \Illuminate\Database\Eloquent\Relations\belongsToMany
29 | */
30 | public function roles()
31 | {
32 | return $this->belongsToMany(Role::class)
33 | ->withPivot('owner_restricted')
34 | ->using(PermissionRole::class);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/app/Models/PermissionRole.php:
--------------------------------------------------------------------------------
1 | 'integer',
16 | 'owner_restricted' => 'boolean',
17 | 'role_id' => 'integer',
18 | 'permission_id' => 'integer',
19 | ];
20 | }
21 |
--------------------------------------------------------------------------------
/app/Providers/AppServiceProvider.php:
--------------------------------------------------------------------------------
1 | app->isLocal()) {
26 | $this->app->register(\Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider::class);
27 | }
28 |
29 | Blade::directive('errorClass', function ($field) {
30 | $ifStatement = "if(session()->has('errors') && session('errors')->has(${field}))";
31 |
32 | return "";
33 | });
34 | }
35 |
36 | /**
37 | * Bootstrap any application services.
38 | *
39 | * @return void
40 | */
41 | public function boot()
42 | {
43 | Schema::defaultStringLength(191);
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/app/Providers/AuthServiceProvider.php:
--------------------------------------------------------------------------------
1 | registerPolicies();
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/app/Providers/BroadcastServiceProvider.php:
--------------------------------------------------------------------------------
1 | [
20 | SendEmailVerificationNotification::class,
21 | ],
22 | ProfileImageUploaded::class => [
23 | ResizeImage::class,
24 | ],
25 | ];
26 |
27 | /**
28 | * Register any events for your application.
29 | *
30 | * @return void
31 | */
32 | public function boot()
33 | {
34 | parent::boot();
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/app/Providers/RouteServiceProvider.php:
--------------------------------------------------------------------------------
1 | mapApiRoutes();
33 |
34 | $this->mapWebRoutes();
35 | }
36 |
37 | /**
38 | * Define the "web" routes for the application.
39 | *
40 | * These routes all receive session state, CSRF protection, etc.
41 | *
42 | * @return void
43 | */
44 | protected function mapWebRoutes()
45 | {
46 | Route::middleware('web')
47 | ->group(base_path('routes/web.php'));
48 | }
49 |
50 | /**
51 | * Define the "api" routes for the application.
52 | *
53 | * These routes are typically stateless.
54 | *
55 | * @return void
56 | */
57 | protected function mapApiRoutes()
58 | {
59 | Route::prefix('api')
60 | ->middleware('api')
61 | ->group(base_path('routes/api.php'));
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/app/Rules/OwnerRestrictedRule.php:
--------------------------------------------------------------------------------
1 | permissions = $permissions;
21 | }
22 |
23 | /**
24 | * Determine if the validation rule passes.
25 | *
26 | * @param string $attribute
27 | * @param mixed $value
28 | * @return bool
29 | */
30 | public function passes($attribute, $value)
31 | {
32 | $splitted = preg_split('/\./', $attribute);
33 | $index = $splitted[1];
34 |
35 | return $value !== true || $this->permissions[$index]['allowed'] !== false;
36 | }
37 |
38 | /**
39 | * Get the validation error message.
40 | *
41 | * @return string
42 | */
43 | public function message()
44 | {
45 | return 'The :attribute is allowed only when corresponding permission is selected.';
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/app/Rules/PasswordCheckRule.php:
--------------------------------------------------------------------------------
1 | user = $user;
23 | }
24 |
25 | /**
26 | * Determine if the validation rule passes.
27 | *
28 | * @param string $attribute
29 | * @param mixed $password
30 | * @return bool
31 | */
32 | public function passes($attribute, $password)
33 | {
34 | return Hash::check($password, $this->user->password);
35 | }
36 |
37 | /**
38 | * Get the validation error message.
39 | *
40 | * @return string
41 | */
42 | public function message()
43 | {
44 | return trans('validation.password_check');
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/app/Rules/PasswordRule.php:
--------------------------------------------------------------------------------
1 | confirmationValue = $confirmationValue;
28 | }
29 |
30 | /**
31 | * Determine if the validation rule passes.
32 | *
33 | * @param string $attribute
34 | * @param mixed $value
35 | * @return bool
36 | * @throws \Illuminate\Validation\ValidationException
37 | */
38 | public function passes($attribute, $value)
39 | {
40 | $validator = Validator::make([
41 | $attribute => $value,
42 | $attribute.'_confirmation' => $this->confirmationValue,
43 | ], [
44 | $attribute => ['required', 'confirmed', Password::min(AppServiceProvider::MIN_PASSWORD_LENGTH)->uncompromised()],
45 | ]);
46 |
47 | try {
48 | $validator->validate();
49 | } catch (ValidationException $exception) {
50 | $this->message = $validator->getMessageBag()->first();
51 |
52 | return false;
53 | }
54 |
55 | return true;
56 | }
57 |
58 | /**
59 | * Get the validation error message.
60 | *
61 | * @return string
62 | */
63 | public function message()
64 | {
65 | return $this->message;
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/app/Rules/PermissionExistsRule.php:
--------------------------------------------------------------------------------
1 | hasUser()) {
23 | return $builder;
24 | }
25 |
26 | $user = auth()->user();
27 |
28 | if ($this->returnEarly($user)) {
29 | return $builder;
30 | }
31 |
32 | if ($this->returnEarlyPermission($user, $model)) {
33 | return $builder;
34 | }
35 |
36 | return $builder->where(AppServiceProvider::OWNER_FIELD, $user->id);
37 | }
38 |
39 | /**
40 | * Should we return early form global scope base on permission and owner field.
41 | *
42 | * @param \App\Models\User $user
43 | * @param \Illuminate\Database\Eloquent\Model $model
44 | * @return bool
45 | */
46 | public function returnEarlyPermission($user, $model)
47 | {
48 | $permission = $user->getPermission($model->getTable().'.index');
49 |
50 | if (! $permission->pivot->owner_restricted === true) {
51 | return true;
52 | }
53 |
54 | if (! Schema::hasColumn($model->getTable(), AppServiceProvider::OWNER_FIELD)) {
55 | return true;
56 | }
57 |
58 | return false;
59 | }
60 |
61 | /**
62 | * Should we return early form global scope.
63 | *
64 | * @param \App\Models\User $user
65 | * @return bool
66 | */
67 | private function returnEarly($user)
68 | {
69 | if ($user === null) {
70 | return true;
71 | }
72 |
73 | if ($user->isAdmin()) {
74 | return true;
75 | }
76 |
77 | return false;
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/app/Services/ForRouteGate.php:
--------------------------------------------------------------------------------
1 | isAdmin()) {
23 | return true;
24 | }
25 |
26 | if ($permissionName === '' || $permissionName === null) {
27 | return false;
28 | }
29 |
30 | if (! Str::contains($permissionName, ['show', 'edit', 'delete'])) {
31 | return $user->hasPermission($permissionName);
32 | }
33 |
34 | return $this->forOwner($user, $permissionName, $model);
35 | }
36 |
37 | /**
38 | * Get permission for non-admin role where value of owner restricted fields is important.
39 | *
40 | * @param \App\Models\User $user
41 | * @param string $permissionName
42 | * @param mixed $model
43 | * @return bool
44 | */
45 | public function forOwner($user, $permissionName, $model)
46 | {
47 | if ($model === null) {
48 | throw new MissingModel();
49 | }
50 |
51 | $ownerField = AppServiceProvider::OWNER_FIELD;
52 |
53 | if ($model->$ownerField === null) {
54 | return $user->hasPermission($permissionName);
55 | }
56 |
57 | return $user->isModelOwner($permissionName, $model);
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/app/ViewModels/SaveRoleViewModel.php:
--------------------------------------------------------------------------------
1 | get();
19 |
20 | $assignedPermissions = [];
21 | $rolePermissions = self::getRolePermissions($roleId);
22 |
23 | foreach ($permissions as $permission) {
24 | $assignedPermissions[$permission->id]['group'] = $permission->group;
25 | $assignedPermissions[$permission->id]['description'] = $permission->description;
26 | $assignedPermissions[$permission->id]['allowed'] = key_exists($permission->id, $rolePermissions);
27 | $assignedPermissions[$permission->id]['owner_restricted'] = $rolePermissions[$permission->id] ?? false;
28 | }
29 |
30 | return $assignedPermissions;
31 | }
32 |
33 | /**
34 | * Group permissions by group name.
35 | *
36 | * @param array $permissions
37 | * @return array
38 | */
39 | public static function groupPermissions($permissions)
40 | {
41 | return collect($permissions)
42 | ->groupBy('group', true)
43 | ->sortKeys()
44 | ->toArray();
45 | }
46 |
47 | /**
48 | * Get current role permissions.
49 | *
50 | * @param int $roleId
51 | * @return array
52 | */
53 | private static function getRolePermissions($roleId)
54 | {
55 | if ($roleId === null) {
56 | return [];
57 | }
58 |
59 | return PermissionRole::where('role_id', $roleId)
60 | ->get()
61 | ->pluck('owner_restricted', 'permission_id')
62 | ->toArray();
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/app/helpers.php:
--------------------------------------------------------------------------------
1 | flash('flash', ['message' => $message, 'level' => 'success']);
13 | }
14 | }
15 |
16 | if (! function_exists('msg_error')) {
17 | /**
18 | * Flash error message.
19 | *
20 | * @param string $message
21 | * @return void
22 | */
23 | function msg_error($message)
24 | {
25 | session()->flash('flash', ['message' => $message, 'level' => 'danger']);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/artisan:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env php
2 | make(Illuminate\Contracts\Console\Kernel::class);
34 |
35 | $status = $kernel->handle(
36 | $input = new Symfony\Component\Console\Input\ArgvInput,
37 | new Symfony\Component\Console\Output\ConsoleOutput
38 | );
39 |
40 | /*
41 | |--------------------------------------------------------------------------
42 | | Shutdown The Application
43 | |--------------------------------------------------------------------------
44 | |
45 | | Once Artisan has finished running, we will fire off the shutdown events
46 | | so that any final work may be done by the application before we shut
47 | | down the process. This is the last thing to happen to the request.
48 | |
49 | */
50 |
51 | $kernel->terminate($input, $status);
52 |
53 | exit($status);
54 |
--------------------------------------------------------------------------------
/bootstrap/app.php:
--------------------------------------------------------------------------------
1 | singleton(
30 | Illuminate\Contracts\Http\Kernel::class,
31 | App\Http\Kernel::class
32 | );
33 |
34 | $app->singleton(
35 | Illuminate\Contracts\Console\Kernel::class,
36 | App\Console\Kernel::class
37 | );
38 |
39 | $app->singleton(
40 | Illuminate\Contracts\Debug\ExceptionHandler::class,
41 | App\Exceptions\Handler::class
42 | );
43 |
44 | /*
45 | |--------------------------------------------------------------------------
46 | | Return The Application
47 | |--------------------------------------------------------------------------
48 | |
49 | | This script returns the application instance. The instance is given to
50 | | the calling script so we can separate the building of the instances
51 | | from the actual running of the application and sending responses.
52 | |
53 | */
54 |
55 | return $app;
56 |
--------------------------------------------------------------------------------
/bootstrap/cache/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/config/broadcasting.php:
--------------------------------------------------------------------------------
1 | env('BROADCAST_DRIVER', 'null'),
19 |
20 | /*
21 | |--------------------------------------------------------------------------
22 | | Broadcast Connections
23 | |--------------------------------------------------------------------------
24 | |
25 | | Here you may define all of the broadcast connections that will be used
26 | | to broadcast events to other systems or over websockets. Samples of
27 | | each available type of connection are provided inside this array.
28 | |
29 | */
30 |
31 | 'connections' => [
32 |
33 | 'pusher' => [
34 | 'driver' => 'pusher',
35 | 'key' => env('PUSHER_APP_KEY'),
36 | 'secret' => env('PUSHER_APP_SECRET'),
37 | 'app_id' => env('PUSHER_APP_ID'),
38 | 'options' => [
39 | 'cluster' => env('PUSHER_APP_CLUSTER'),
40 | 'encrypted' => true,
41 | ],
42 | ],
43 |
44 | 'redis' => [
45 | 'driver' => 'redis',
46 | 'connection' => 'default',
47 | ],
48 |
49 | 'log' => [
50 | 'driver' => 'log',
51 | ],
52 |
53 | 'null' => [
54 | 'driver' => 'null',
55 | ],
56 |
57 | ],
58 |
59 | ];
60 |
--------------------------------------------------------------------------------
/config/filesystems.php:
--------------------------------------------------------------------------------
1 | env('FILESYSTEM_DRIVER', 'local'),
17 |
18 | /*
19 | |--------------------------------------------------------------------------
20 | | Default Cloud Filesystem Disk
21 | |--------------------------------------------------------------------------
22 | |
23 | | Many applications store files both locally and in the cloud. For this
24 | | reason, you may specify a default "cloud" driver here. This driver
25 | | will be bound as the Cloud disk implementation in the container.
26 | |
27 | */
28 |
29 | 'cloud' => env('FILESYSTEM_CLOUD', 's3'),
30 |
31 | /*
32 | |--------------------------------------------------------------------------
33 | | Filesystem Disks
34 | |--------------------------------------------------------------------------
35 | |
36 | | Here you may configure as many filesystem "disks" as you wish, and you
37 | | may even configure multiple disks of the same driver. Defaults have
38 | | been setup for each driver as an example of the required options.
39 | |
40 | | Supported Drivers: "local", "ftp", "sftp", "s3", "rackspace"
41 | |
42 | */
43 |
44 | 'disks' => [
45 |
46 | 'local' => [
47 | 'driver' => 'local',
48 | 'root' => storage_path('app'),
49 | ],
50 |
51 | 'public' => [
52 | 'driver' => 'local',
53 | 'root' => storage_path('app/public'),
54 | 'url' => env('APP_URL').'/storage',
55 | 'visibility' => 'public',
56 | ],
57 |
58 | 'avatar' => [
59 | 'driver' => 'local',
60 | 'root' => storage_path('app/public/avatars'),
61 | 'url' => env('APP_URL').'/storage/avatars',
62 | 'visibility' => 'public',
63 | ],
64 |
65 | 's3' => [
66 | 'driver' => 's3',
67 | 'key' => env('AWS_ACCESS_KEY_ID'),
68 | 'secret' => env('AWS_SECRET_ACCESS_KEY'),
69 | 'region' => env('AWS_DEFAULT_REGION'),
70 | 'bucket' => env('AWS_BUCKET'),
71 | 'url' => env('AWS_URL'),
72 | ],
73 |
74 | ],
75 |
76 | ];
77 |
--------------------------------------------------------------------------------
/config/hashing.php:
--------------------------------------------------------------------------------
1 | 'bcrypt',
19 |
20 | /*
21 | |--------------------------------------------------------------------------
22 | | Bcrypt Options
23 | |--------------------------------------------------------------------------
24 | |
25 | | Here you may specify the configuration options that should be used when
26 | | passwords are hashed using the Bcrypt algorithm. This will allow you
27 | | to control the amount of time it takes to hash the given password.
28 | |
29 | */
30 |
31 | 'bcrypt' => [
32 | 'rounds' => env('BCRYPT_ROUNDS', 10),
33 | ],
34 |
35 | /*
36 | |--------------------------------------------------------------------------
37 | | Argon Options
38 | |--------------------------------------------------------------------------
39 | |
40 | | Here you may specify the configuration options that should be used when
41 | | passwords are hashed using the Argon algorithm. These will allow you
42 | | to control the amount of time it takes to hash the given password.
43 | |
44 | */
45 |
46 | 'argon' => [
47 | 'memory' => 1024,
48 | 'threads' => 2,
49 | 'time' => 2,
50 | ],
51 |
52 | ];
53 |
--------------------------------------------------------------------------------
/config/services.php:
--------------------------------------------------------------------------------
1 | [
18 | 'domain' => env('MAILGUN_DOMAIN'),
19 | 'secret' => env('MAILGUN_SECRET'),
20 | 'endpoint' => env('MAILGUN_ENDPOINT', 'api.mailgun.net'),
21 | ],
22 |
23 | 'postmark' => [
24 | 'token' => env('POSTMARK_TOKEN'),
25 | ],
26 |
27 | 'ses' => [
28 | 'key' => env('AWS_ACCESS_KEY_ID'),
29 | 'secret' => env('AWS_SECRET_ACCESS_KEY'),
30 | 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
31 | ],
32 |
33 | 'sparkpost' => [
34 | 'secret' => env('SPARKPOST_SECRET'),
35 | ],
36 |
37 | 'stripe' => [
38 | 'model' => App\Models\User::class,
39 | 'key' => env('STRIPE_KEY'),
40 | 'secret' => env('STRIPE_SECRET'),
41 | 'webhook' => [
42 | 'secret' => env('STRIPE_WEBHOOK_SECRET'),
43 | 'tolerance' => env('STRIPE_WEBHOOK_TOLERANCE', 300),
44 | ],
45 | ],
46 |
47 | ];
48 |
--------------------------------------------------------------------------------
/config/view.php:
--------------------------------------------------------------------------------
1 | [
17 | resource_path('views'),
18 | ],
19 |
20 | /*
21 | |--------------------------------------------------------------------------
22 | | Compiled View Path
23 | |--------------------------------------------------------------------------
24 | |
25 | | This option determines where all the compiled Blade templates will be
26 | | stored for your application. Typically, this is within the storage
27 | | directory. However, as usual, you are free to change this value.
28 | |
29 | */
30 |
31 | 'compiled' => env(
32 | 'VIEW_COMPILED_PATH',
33 | realpath(storage_path('framework/views'))
34 | ),
35 |
36 | ];
37 |
--------------------------------------------------------------------------------
/database/.gitignore:
--------------------------------------------------------------------------------
1 | *.sqlite
2 | *.sqlite-journal
3 |
--------------------------------------------------------------------------------
/database/factories/PermissionFactory.php:
--------------------------------------------------------------------------------
1 | strtoupper($this->faker->word),
26 | 'name' => $this->faker->word,
27 | 'description' => $this->faker->sentence,
28 | ];
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/database/factories/RoleFactory.php:
--------------------------------------------------------------------------------
1 | strtoupper($this->faker->word),
26 | 'label' => $this->faker->word,
27 | ];
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/database/factories/UserFactory.php:
--------------------------------------------------------------------------------
1 | RoleFactory::new(),
28 | AppServiceProvider::OWNER_FIELD => 1,
29 | 'email' => $this->faker->unique()->safeEmail,
30 | 'email_verified_at' => now(),
31 | 'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
32 | 'remember_token' => Str::random(10),
33 | 'image' => null,
34 | ];
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/database/migrations/2013_03_11_165941_create_roles_table.php:
--------------------------------------------------------------------------------
1 | bigIncrements('id');
18 | $table->string('name', 255);
19 | $table->string('label', 255);
20 | $table->timestamps();
21 | $table->softDeletes();
22 | });
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/database/migrations/2014_10_12_000000_create_users_table.php:
--------------------------------------------------------------------------------
1 | bigIncrements('id');
19 | $table->unsignedBigInteger(AppServiceProvider::OWNER_FIELD);
20 | $table->foreign(AppServiceProvider::OWNER_FIELD)->references('id')->on('users');
21 | $table->unsignedBigInteger('role_id');
22 | $table->foreign('role_id')->references('id')->on('roles');
23 | $table->string('email')->unique();
24 | $table->timestamp('email_verified_at')->nullable();
25 | $table->string('password')->nullable();
26 | $table->rememberToken();
27 | $table->string('image')->nullable();
28 | $table->timestamps();
29 | $table->softDeletes();
30 | });
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/database/migrations/2014_10_12_100000_create_password_resets_table.php:
--------------------------------------------------------------------------------
1 | string('email')->index();
18 | $table->string('token');
19 | $table->timestamp('created_at')->nullable();
20 | });
21 | }
22 |
23 | /**
24 | * Reverse the migrations.
25 | *
26 | * @return void
27 | */
28 | public function down()
29 | {
30 | Schema::dropIfExists('password_resets');
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/database/migrations/2020_02_03_125830_create_sessions_table.php:
--------------------------------------------------------------------------------
1 | string('id')->unique();
18 | $table->unsignedBigInteger('user_id')->nullable();
19 | $table->string('ip_address', 45)->nullable();
20 | $table->text('user_agent')->nullable();
21 | $table->text('payload');
22 | $table->integer('last_activity');
23 | });
24 | }
25 |
26 | /**
27 | * Reverse the migrations.
28 | *
29 | * @return void
30 | */
31 | public function down()
32 | {
33 | Schema::dropIfExists('sessions');
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/database/migrations/2020_02_03_132010_create_jobs_table.php:
--------------------------------------------------------------------------------
1 | bigIncrements('id');
18 | $table->string('queue')->index();
19 | $table->longText('payload');
20 | $table->unsignedTinyInteger('attempts');
21 | $table->unsignedInteger('reserved_at')->nullable();
22 | $table->unsignedInteger('available_at');
23 | $table->unsignedInteger('created_at');
24 | });
25 | }
26 |
27 | /**
28 | * Reverse the migrations.
29 | *
30 | * @return void
31 | */
32 | public function down()
33 | {
34 | Schema::dropIfExists('jobs');
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/database/migrations/2020_03_26_110221_create_permissions_table.php:
--------------------------------------------------------------------------------
1 | bigIncrements('id');
18 | $table->string('group');
19 | $table->string('name');
20 | $table->text('description');
21 | $table->timestamps();
22 | });
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/database/migrations/2023_03_26_110250_create_permission_role_table.php:
--------------------------------------------------------------------------------
1 | bigIncrements('id');
18 | $table->unsignedBigInteger('permission_id');
19 | $table->foreign('permission_id')->references('id')->on('permissions');
20 | $table->unsignedBigInteger('role_id');
21 | $table->foreign('role_id')->references('id')->on('roles');
22 | $table->boolean('owner_restricted')->nullable();
23 | });
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/database/seeders/DatabaseSeeder.php:
--------------------------------------------------------------------------------
1 | environment('production')) {
17 | return;
18 | }
19 |
20 | $this->call([
21 | RolesTableSeeder::class,
22 | PermissionsTableSeeder::class,
23 | UsersTableSeeder::class,
24 | ]);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/database/seeders/PermissionsTableSeeder.php:
--------------------------------------------------------------------------------
1 | create([
18 | 'group' => 'users',
19 | 'name' => 'users.index',
20 | 'description' => 'View Users',
21 | ]);
22 |
23 | PermissionFactory::new()->create([
24 | 'group' => 'users',
25 | 'name' => 'users.create',
26 | 'description' => 'Create New User',
27 | ]);
28 |
29 | PermissionFactory::new()->create([
30 | 'group' => 'users',
31 | 'name' => 'users.edit',
32 | 'description' => 'Edit Existing User',
33 | ]);
34 |
35 | PermissionFactory::new()->create([
36 | 'group' => 'users',
37 | 'name' => 'users.delete',
38 | 'description' => 'Delete Existing User',
39 | ]);
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/database/seeders/RolesTableSeeder.php:
--------------------------------------------------------------------------------
1 | create([
18 | 'name' => 'admin',
19 | 'label' => 'admin',
20 | ]);
21 |
22 | RoleFactory::new()->create([
23 | 'name' => 'manager',
24 | 'label' => 'manager',
25 | ]);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/database/seeders/UsersTableSeeder.php:
--------------------------------------------------------------------------------
1 | create([
19 | 'email' => 'admin@lte.com',
20 | 'role_id' => Role::whereName('admin')->first(),
21 | ]);
22 |
23 | UserFactory::new()->create([
24 | 'email' => 'manager@lte.com',
25 | 'role_id' => Role::whereName('manager')->first(),
26 | ]);
27 |
28 | for ($i = 1; $i < 10; $i++) {
29 | UserFactory::new()->create([
30 | 'role_id' => Role::whereName('manager')->first(),
31 | ]);
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "scripts": {
4 | "dev": "npm run development",
5 | "development": "mix",
6 | "watch": "mix watch",
7 | "watch-poll": "mix watch -- --watch-options-poll=1000",
8 | "hot": "mix watch --hot",
9 | "prod": "npm run production",
10 | "production": "mix --production"
11 | },
12 | "devDependencies": {
13 | "cross-env": "^7.0.3",
14 | "laravel-mix": "^6.0.41",
15 | "vue-template-compiler": "^2.6.14"
16 | },
17 | "dependencies": {
18 | "alpinejs": "^3.8.1",
19 | "axios": "^0.25.0",
20 | "websocket-driver": "^0.7.4"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/phpunit.xml:
--------------------------------------------------------------------------------
1 |
2 |
Create New Account
8 | 9 | 22 |Sign in to start your session
11 | 12 | 32 | 33 |34 | I forgot my password 35 |
36 |{{ __('Please confirm your password before continuing.') }}
11 | 12 | 29 |{{ __('Reset Password') }}
11 | 12 | @include('layouts._flash') 13 | 14 | 25 |26 | {{ __('Sing In') }} 27 |
28 |{{ __('Reset Password') }}
12 | 13 | 30 |{{ __('Verify Your Email Address') }}
11 | 12 | @if (session('resent')) 13 |12 | {{ $exception->getMessage() ?: 'You are not authorized.' }} 13 |
14 |12 | {{ $exception->getMessage() ?: 'You are not allowed to see this page.' }} 13 |
14 |12 | We could not find the page you were looking for. 13 | Would you like to go to return to dashboard? 14 |
15 |12 | {{ $exception->getMessage() ?: 'Please refresh the page.' }} 13 |
14 |12 | {{ $exception->getMessage() ?: 'Too many requests.' }} 13 |
14 |12 | {{ $exception->getMessage() ?: 'Something went wrong on our end.' }} 13 |
14 |12 | {{ $exception->getMessage() ?: 'Service is not available. Please try again later.' }} 13 |
14 |