├── .env-example ├── .gitignore ├── LICENSE ├── README.md ├── app ├── App │ ├── App.php │ ├── Auth │ │ └── Auth.php │ ├── Console │ │ ├── Command.php │ │ ├── Commands │ │ │ └── Generator │ │ │ │ ├── ControllerGeneratorCommand.php │ │ │ │ └── MiddlewareGeneratorCommand.php │ │ ├── Console.php │ │ ├── Kernel.php │ │ ├── Traits │ │ │ └── Generatable.php │ │ └── stubs │ │ │ ├── controller.stub │ │ │ └── middleware.stub │ ├── Database │ │ ├── Permission.php │ │ ├── Role.php │ │ ├── User.php │ │ └── UserRole.php │ ├── Http │ │ ├── Controllers │ │ │ ├── Admin │ │ │ │ ├── AdminController.php │ │ │ │ ├── AdminPermissionController.php │ │ │ │ ├── AdminRoleController.php │ │ │ │ └── AdminUserController.php │ │ │ ├── Auth │ │ │ │ ├── ActivationController.php │ │ │ │ ├── LoginController.php │ │ │ │ ├── PasswordResetController.php │ │ │ │ ├── RegisterController.php │ │ │ │ └── SettingsController.php │ │ │ ├── Controller.php │ │ │ └── HomeController.php │ │ └── Middleware │ │ │ ├── AdminMiddleware.php │ │ │ ├── AuthMiddleware.php │ │ │ ├── CsrfMiddleware.php │ │ │ ├── GuestMiddleware.php │ │ │ ├── Middleware.php │ │ │ ├── OldInputMiddleware.php │ │ │ ├── Pagination.php │ │ │ ├── RememberMiddleware.php │ │ │ └── RequiresSecureRequestMiddleware.php │ ├── Lib │ │ ├── Cookie.php │ │ ├── Flash.php │ │ ├── Hash.php │ │ └── Session.php │ ├── Mail │ │ ├── Mailer.php │ │ └── Mailtrap │ │ │ └── Message.php │ ├── Traits │ │ └── HasPermissionsTrait.php │ ├── Twig │ │ └── TwigExtension.php │ └── Validation │ │ ├── Validator.php │ │ └── Violin │ │ ├── Contracts │ │ ├── MessageBagContract.php │ │ ├── RuleContract.php │ │ └── ValidatorContract.php │ │ ├── Rules │ │ ├── AlnumDashRule.php │ │ ├── AlnumRule.php │ │ ├── AlphaRule.php │ │ ├── ArrayRule.php │ │ ├── BetweenRule.php │ │ ├── BoolRule.php │ │ ├── CheckedRule.php │ │ ├── DateRule.php │ │ ├── EmailRule.php │ │ ├── IntRule.php │ │ ├── IpRule.php │ │ ├── MatchesRule.php │ │ ├── MaxRule.php │ │ ├── MinRule.php │ │ ├── NumberRule.php │ │ ├── RegexRule.php │ │ ├── RequiredRule.php │ │ └── UrlRule.php │ │ ├── Support │ │ └── MessageBag.php │ │ └── Violin.php ├── Migration │ └── Migration.php └── helpers.php ├── auth.sql ├── bootstrap ├── app.php └── container.php ├── composer.json ├── config ├── app.php ├── database.php ├── lang.php ├── mail.php └── plugins.php ├── database ├── migrations │ ├── 20190527142257_permissions.php │ ├── 20190527142308_roles.php │ ├── 20190527142321_roles_permissions.php │ ├── 20190527142334_users.php │ ├── 20190527142340_users_permissions.php │ └── 20190527142344_users_roles.php └── seeds │ ├── PermissionSeeder.php │ ├── RolePermissionSeeder.php │ └── RoleSeeder.php ├── forge ├── gulpfile.js ├── package.json ├── phinx ├── phinx.php ├── public ├── .htaccess ├── css │ └── app.css ├── index.php └── js │ ├── app.min.js │ └── jquery.min.js ├── resources ├── assets │ ├── js │ │ ├── app.js │ │ └── bootstrap.js │ └── sass │ │ ├── app.scss │ │ └── components │ │ ├── _base.scss │ │ └── bootstrap │ │ └── _custom.scss ├── phinx │ └── Migration.template.php.dist └── views │ ├── admin │ ├── home.twig │ ├── permission │ │ ├── create.twig │ │ ├── delete.twig │ │ ├── edit.twig │ │ └── list.twig │ ├── role │ │ ├── create.twig │ │ ├── delete.twig │ │ ├── edit.twig │ │ └── list.twig │ ├── templates │ │ ├── admin.twig │ │ └── partials │ │ │ └── _menu.twig │ └── user │ │ ├── adminlist.twig │ │ ├── delete.twig │ │ ├── edit.twig │ │ └── list.twig │ ├── auth │ ├── account │ │ └── settings.twig │ ├── login.twig │ ├── password │ │ ├── forgot.twig │ │ └── reset.twig │ └── register.twig │ ├── errors │ ├── 404.twig │ ├── 405.twig │ └── 500.twig │ ├── home.twig │ ├── mail │ ├── auth │ │ └── activate.twig │ └── password │ │ └── forgot.twig │ ├── pagination.twig │ └── templates │ ├── app.twig │ └── partials │ ├── alerts.twig │ └── nav.twig └── routes ├── admin.php └── web.php /.env-example: -------------------------------------------------------------------------------- 1 | APP_ENV=development 2 | APP_NAME="My App" 3 | APP_URL=http://127.0.0.1 4 | APP_AUTH_ID=user_id 5 | APP_ACTIVATION_METHOD=mail 6 | 7 | DB_CONNECTION=mysql 8 | DB_HOST=127.0.0.1 9 | DB_PORT=3306 10 | DB_DATABASE=auth 11 | DB_USERNAME=root 12 | DB_PASSWORD= 13 | 14 | MAIL_HOST=smtp.mailtrap.io 15 | MAIL_PORT=2525 16 | MAIL_USERNAME= 17 | MAIL_PASSWORD= 18 | MAIL_FROM= 19 | 20 | RECAPTCHA_PUBLIC= 21 | RECAPTCHA_SECRET= 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.lock 2 | /vendor 3 | .env 4 | /node_modules 5 | .phpintel 6 | /.idea 7 | 1.IDEIAS.txt -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Savage 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Slim 3 Authentication 2 | A very easy to use Slim 3 authentication system. 3 | 4 | [![Latest Unstable Version](https://poser.pugx.org/devsavage/slim-3-authentication/v/unstable?format=flat-square)](https://packagist.org/packages/devsavage/slim-3-authentication) 5 | [![License](https://poser.pugx.org/devsavage/slim-3-authentication/license?format=flat-square)](https://packagist.org/packages/devsavage/slim-3-authentication) 6 | 7 | If you stumble upon any vulnerabilities within this package, more importantly with the role/permission system, please send your findings to: **savage@savagedev.io**. 8 | 9 | ## Getting Started 10 | 11 | ### Prerequisites 12 | 13 | You will need the following to get started: 14 | 15 | * A web server with URL rewriting 16 | - PHP 5.5 or newer 17 | - A SSL certificate will be required in production environments! Check out [HTTPS Is Easy](https://httpsiseasy.com/) for help setting this up! 18 | * [Composer](https://getcomposer.org/) 19 | * [Yarn](https://yarnpkg.com/) or [npm](https://www.npmjs.com/) 20 | 21 | ### Installing 22 | #### Clone the project: 23 | ``` 24 | git clone https://github.com/devsavage/slim-3-authentication.git your-project-name 25 | ``` 26 | 27 | #### Install the composer dependencies: 28 | ```bash 29 | $ cd your-project-name && composer install 30 | ``` 31 | 32 | #### Inside your project folder, install the node dependencies using yarn or npm: 33 | ```bash 34 | $ yarn install 35 | ``` 36 | 37 | #### Rename *_.env-example_* to *_.env_* 38 | 39 | #### Update *_.env_* to your project's configuration 40 | ```bash 41 | APP_ENV=development 42 | ``` 43 | You will need to update the **APP_ENV** variable to "production" when serving your application outside of a local environment! 44 | 45 | #### Build assets (prodution or development) 46 | ```bash 47 | $ yarn prod 48 | ``` 49 | 50 | ```bash 51 | $ yarn dev 52 | ``` 53 | #### Database and Admin 54 | 1. Import auth.sql file to your database. 55 | 2. Open your site, register a new user and click on activation link sent to your email 56 | 3. Go to **phpMyAdmin**, select **user_roles** table and insert a new record. Select your user on **user_id** field, select "superadmin" on **role_id** field and confirm. 57 | 4. Login on site to see "Admin Dashboard" on header menu 58 | 59 | #### Migrations and Seeds 60 | Create migration file 61 | ```bash 62 | php phinx create MigrationName 63 | ``` 64 | Create seed file 65 | ```bash 66 | php phinx seed:create SeedName 67 | ``` 68 | Run migrations 69 | ```bash 70 | php phinx migrate 71 | ``` 72 | Run seeds 73 | ```bash 74 | php phinx seed:run 75 | ``` 76 | Use `php phinx` on terminal to see all available command list. 77 | 78 | #### You will also need Google reCAPTCHA API keys. Get them [here](https://www.google.com/recaptcha). 79 | 80 | *If you would like to completely disable reCAPTCHA, see this [page](https://github.com/devsavage/slim-3-authentication/wiki/Completely-remove-reCAPTCHA)* 81 | 82 | ### Check out the [wiki](https://github.com/devsavage/slim-3-authentication/wiki/) for more information and details on how to add new controllers, routes and more. 83 | 84 | ## License 85 | 86 | This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details 87 | -------------------------------------------------------------------------------- /app/App/App.php: -------------------------------------------------------------------------------- 1 | map($methods, $uri, function($request, $response, $args) use ($methods, $uri, $controller, $func) { 16 | $callable = new $controller($request, $response, $args, $this); 17 | return call_user_func_array([$callable, $request->getMethod() . ucfirst($func)], $args); 18 | }); 19 | } 20 | 21 | return $this->map($methods, $uri, function($request, $response, $args) use ($controller, $uri) { 22 | $callable = new $controller($request, $response, $args, $this); 23 | return call_user_func_array([$callable, $request->getMethod()], $args); 24 | }); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/App/Auth/Auth.php: -------------------------------------------------------------------------------- 1 | ci = $ci; 22 | } 23 | 24 | protected function configure() 25 | { 26 | $this->setName($this->command)->setDescription($this->description); 27 | 28 | $this->addArguments(); 29 | $this->addOptions(); 30 | } 31 | 32 | protected function execute(InputInterface $input, OutputInterface $output) 33 | { 34 | $this->input = $input; 35 | $this->output = $output; 36 | 37 | return $this->handle($input, $output); 38 | } 39 | 40 | protected function argument($name) 41 | { 42 | return $this->input->getArgument($name); 43 | } 44 | 45 | protected function option($name) 46 | { 47 | return $this->input->getOption($name); 48 | } 49 | 50 | protected function addArguments() 51 | { 52 | foreach ($this->arguments() as $argument) { 53 | $this->addArgument($argument[0], $argument[1], $argument[2]); 54 | } 55 | } 56 | 57 | protected function addOptions() 58 | { 59 | foreach ($this->options() as $option) { 60 | $this->addOption($option[0], $option[1], $option[2], $option[3], $option[4]); 61 | } 62 | } 63 | 64 | protected function info($value) 65 | { 66 | return $this->output->writeln('' . $value . ''); 67 | } 68 | 69 | protected function error($value) 70 | { 71 | return $this->output->writeln('' . $value . ''); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /app/App/Console/Commands/Generator/ControllerGeneratorCommand.php: -------------------------------------------------------------------------------- 1 | argument('name'))); 27 | 28 | $fileName = array_pop($fileParts); 29 | 30 | $cleanPath = implode('/', $fileParts); 31 | 32 | if (count($fileParts) >= 1) { 33 | $path = $path . $cleanPath; 34 | 35 | $namespace = $namespace . '\\' . str_replace('/', '\\', $cleanPath); 36 | 37 | if (!is_dir($path)) { 38 | mkdir($path, 0777, true); 39 | } 40 | } 41 | 42 | $target = $path . '/' . $fileName . '.php'; 43 | 44 | if (file_exists($target)) { 45 | return $this->error('Controller already exists!'); 46 | } 47 | 48 | $stub = $this->generateStub('controller', [ 49 | 'DummyClass' => $fileName, 50 | 'DummyNamespace' => $namespace, 51 | ]); 52 | 53 | file_put_contents($target, $stub); 54 | 55 | return $this->info('Controller generated!'); 56 | } 57 | 58 | protected function arguments() 59 | { 60 | return [ 61 | ['name', InputArgument::REQUIRED, 'The name of the controller to generate.'] 62 | ]; 63 | } 64 | 65 | protected function options() 66 | { 67 | return [ 68 | 69 | ]; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /app/App/Console/Commands/Generator/MiddlewareGeneratorCommand.php: -------------------------------------------------------------------------------- 1 | argument('name'))); 27 | 28 | $fileName = array_pop($fileParts); 29 | 30 | $cleanPath = implode('/', $fileParts); 31 | 32 | if (count($fileParts) >= 1) { 33 | $path = $path . $cleanPath; 34 | 35 | $namespace = $namespace . '\\' . str_replace('/', '\\', $cleanPath); 36 | 37 | if (!is_dir($path)) { 38 | mkdir($path, 0777, true); 39 | } 40 | } 41 | 42 | $target = $path . '/' . $fileName . '.php'; 43 | 44 | if (file_exists($target)) { 45 | return $this->error('Middleware already exists!'); 46 | } 47 | 48 | $stub = $this->generateStub('middleware', [ 49 | 'DummyClass' => $fileName, 50 | 'DummyNamespace' => $namespace, 51 | ]); 52 | 53 | file_put_contents($target, $stub); 54 | 55 | return $this->info('Middleware generated!'); 56 | } 57 | 58 | protected function arguments() 59 | { 60 | return [ 61 | ['name', InputArgument::REQUIRED, 'The name of the middleware to generate.'] 62 | ]; 63 | } 64 | 65 | protected function options() 66 | { 67 | return [ 68 | 69 | ]; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /app/App/Console/Console.php: -------------------------------------------------------------------------------- 1 | slim = $slim; 16 | } 17 | 18 | public function boot(Kernel $kernel) 19 | { 20 | foreach ($kernel->getCommands() as $command) { 21 | $this->add(new $command($this->getSlim()->getContainer())); 22 | } 23 | } 24 | 25 | protected function getSlim() 26 | { 27 | return $this->slim; 28 | } 29 | } -------------------------------------------------------------------------------- /app/App/Console/Kernel.php: -------------------------------------------------------------------------------- 1 | commands, $this->defaultCommands); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/App/Console/Traits/Generatable.php: -------------------------------------------------------------------------------- 1 | stubDirectory . '/' . $name . '.stub') 15 | ); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/App/Console/stubs/controller.stub: -------------------------------------------------------------------------------- 1 | belongsToMany(Role::class, 'roles_permissions'); 16 | } 17 | } -------------------------------------------------------------------------------- /app/App/Database/Role.php: -------------------------------------------------------------------------------- 1 | belongsToMany(Permission::class,'roles_permissions'); 18 | } 19 | 20 | public function givePermissionTo(Permission $permission) 21 | { 22 | return $this->permissions()->save($permission); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/App/Database/User.php: -------------------------------------------------------------------------------- 1 | update([ 19 | 'remember_identifier' => $identifier, 20 | 'remember_token' => $token, 21 | ]); 22 | } 23 | 24 | public function removeRememberCredentials() 25 | { 26 | $this->updateRememberCredentials(null, null); 27 | } 28 | 29 | public function revokeRecoveryHash() 30 | { 31 | $this->update([ 32 | 'recover_hash' => null, 33 | ]); 34 | } 35 | 36 | public function activate($value = true, $hash = null) 37 | { 38 | $this->update([ 39 | 'active' => $value, 40 | 'active_hash' => $hash 41 | ]); 42 | } 43 | 44 | public function deactivate($hash = null) 45 | { 46 | $this->activate(false, $hash); 47 | } 48 | 49 | public function userRoles() 50 | { 51 | return $this->hasMany(UserRole::class, 'user_id'); 52 | } 53 | 54 | public function isAdmin() 55 | { 56 | return $this->hasRole('admin'); 57 | } 58 | 59 | public function isSuperAdmin() 60 | { 61 | return $this->hasRole('superadmin'); 62 | } 63 | 64 | /** 65 | * Make this functionality better. 66 | */ 67 | 68 | public function giveRole($title) 69 | { 70 | $role = Role::where('title', $title)->first(); 71 | 72 | if(!$role) { 73 | return false; 74 | } 75 | 76 | $userRoles = $this->userRoles(); 77 | 78 | if($userRoles->where('role_id', $role->id)->first()) { 79 | return true; 80 | } 81 | 82 | return $this->userRoles()->create([ 83 | 'role_id' => $role->id, 84 | ]); 85 | } 86 | 87 | /** 88 | * Make this functionality better. 89 | */ 90 | 91 | public function removeRole($title) 92 | { 93 | $role = Role::where('title', $title)->first(); 94 | 95 | if(!$role) { 96 | return false; 97 | } 98 | 99 | $userRole = $this->userRoles()->where('role_id', $role->id)->first(); 100 | 101 | if($userRole) { 102 | return $userRole->delete(); 103 | } 104 | 105 | return true; 106 | } 107 | 108 | public function can($action) 109 | { 110 | $permission = Permission::where('name', $action)->first(); 111 | 112 | if(!$permission) { 113 | return false; 114 | } 115 | 116 | return $this->hasPermissionTo($permission); 117 | } 118 | 119 | public function canEdit(User $user) 120 | { 121 | if($this->isSuperAdmin() && $user->isSuperAdmin()) { 122 | return false; 123 | } 124 | 125 | if($user->isAdmin() && $this->can('edit admins') || !$user->isAdmin() && $this->can('edit users') && !$user->isSuperAdmin()) { 126 | return true; 127 | } 128 | 129 | return false; 130 | } 131 | } -------------------------------------------------------------------------------- /app/App/Database/UserRole.php: -------------------------------------------------------------------------------- 1 | belongsTo(User::class, 'user_id','id'); 16 | } 17 | } -------------------------------------------------------------------------------- /app/App/Http/Controllers/Admin/AdminController.php: -------------------------------------------------------------------------------- 1 | render('admin/home'); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /app/App/Http/Controllers/Admin/AdminPermissionController.php: -------------------------------------------------------------------------------- 1 | render('admin/permission/list', [ 13 | 'permissions' => Permission::paginate(), 14 | ]); 15 | } 16 | 17 | public function getEdit($permissionId) 18 | { 19 | $permission = Permission::where('id', $permissionId)->first(); 20 | 21 | if(!$this->auth()->user()->can('edit permission') && !$this->auth()->user()->isSuperAdmin()) { 22 | $this->flash('error', $this->lang('admin.permission.general.cant_edit')); 23 | return $this->redirect('admin.permissions.list'); 24 | } 25 | 26 | return $this->render('admin/permission/edit', [ 27 | 'permission' => $permission, 28 | ]); 29 | } 30 | 31 | public function postEdit($permissionId) 32 | { 33 | $name = $this->param('name'); 34 | 35 | $permission = Permission::where('id', $permissionId)->first(); 36 | 37 | if(!$this->user()->can('edit permission') && !$this->auth()->user()->isSuperAdmin()) { 38 | $this->flash("error", $this->lang('admin.permission.general.not_authorized')); 39 | return $this->redirect('admin.permissions.list'); 40 | } 41 | 42 | $validator = $this->validator()->validate([ 43 | 'name|Name' => [$name, "required|adminUniqueName({$name},{$permission->id})"], 44 | ]); 45 | 46 | if(!$validator->passes()) { 47 | $this->flashNow('error', $this->lang('admin.general.fail')); 48 | return $this->render('admin/permission/edit', [ 49 | 'permission' => $permission, 50 | 'errors' => $validator->errors(), 51 | ]); 52 | } 53 | 54 | $permission->update([ 55 | 'name' => $name 56 | ]); 57 | 58 | $this->flash('success', $this->lang('admin.general.success')); 59 | return $this->redirect('admin.permissions.edit', [ 60 | 'permissionId' => $permissionId, 61 | ]); 62 | } 63 | 64 | public function getCreate() 65 | { 66 | 67 | if(!$this->auth()->user()->can('create permission') && !$this->auth()->user()->isSuperAdmin()) { 68 | $this->flash('error', $this->lang('admin.permission.general.cant_create')); 69 | return $this->redirect('admin.permissions.list'); 70 | } 71 | 72 | return $this->render('admin/permission/create'); 73 | } 74 | 75 | public function postCreate() 76 | { 77 | $name = $this->param('name'); 78 | 79 | if(!$this->user()->can('edit permission') && !$this->auth()->user()->isSuperAdmin()) { 80 | $this->flash("error", $this->lang('admin.permission.general.not_authorized')); 81 | return $this->redirect('admin.permissions.list'); 82 | } 83 | 84 | $validator = $this->validator()->validate([ 85 | 'name|Title' => [$name, "required|adminUniqueTitle()"], 86 | ]); 87 | 88 | if(!$validator->passes()) { 89 | $this->flashNow('error', $this->lang('admin.general.fail')); 90 | return $this->render('admin/permission/create', [ 91 | 'errors' => $validator->errors(), 92 | ]); 93 | } 94 | 95 | Permission::create([ 96 | 'name' => $name 97 | ]); 98 | 99 | $this->flash('success', $this->lang('admin.general.created')); 100 | return $this->redirect('admin.permissions.list'); 101 | } 102 | 103 | public function getDelete($permissionId) 104 | { 105 | $permission = Permission::where('id', $permissionId)->first(); 106 | 107 | if(!$this->user()->can('edit permission') && !$this->auth()->user()->isSuperAdmin()) { 108 | $this->flash("error", $this->lang('admin.user.general.not_authorized')); 109 | return $this->redirect('admin.permissions.list'); 110 | } 111 | 112 | return $this->render('admin/permission/delete', [ 113 | 'permission' => $permission, 114 | ]); 115 | } 116 | 117 | public function postDelete($permissionId) 118 | { 119 | $permission = Permission::where('id', $permissionId)->first(); 120 | 121 | if(!$this->user()->can('delete permission') && !$this->auth()->user()->isSuperAdmin()) { 122 | $this->flash("error", $this->lang('admin.user.general.not_authorized')); 123 | return $this->redirect('admin.permissions.list'); 124 | } 125 | 126 | $delete = $this->param('delete'); 127 | 128 | if(!$delete) { 129 | return $this->redirect('admin.home'); 130 | } 131 | 132 | if($delete === "true") { 133 | $permission->delete(); 134 | $this->flash('success', $this->lang('admin.general.deleted')); 135 | return $this->redirect('admin.permissions.list'); 136 | } 137 | 138 | $this->flash('info', $this->lang('admin.general.not_deleted')); 139 | return $this->redirect('admin.permissions.edit', [ 140 | 'permissionId' => $permissionId 141 | ]); 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /app/App/Http/Controllers/Admin/AdminRoleController.php: -------------------------------------------------------------------------------- 1 | render('admin/role/list', [ 14 | 'roles' => Role::where("hidden", false)->paginate(), 15 | ]); 16 | } 17 | 18 | public function getEdit($roleId) 19 | { 20 | $role = Role::with('permissions')->where('id', $roleId)->first(); 21 | 22 | if((bool)$role->hidden) { 23 | $this->flash('error', $this->lang('admin.role.general.cant_edit')); 24 | return $this->redirect('admin.roles.list'); 25 | } 26 | 27 | $permissions = Permission::all(); 28 | 29 | if(!$this->auth()->user()->can('edit role') && !$this->auth()->user()->isSuperAdmin()) { 30 | $this->flash('error', $this->lang('admin.role.general.cant_edit')); 31 | return $this->redirect('admin.roles.list'); 32 | } 33 | 34 | return $this->render('admin/role/edit', [ 35 | 'role' => $role, 36 | 'permissions' => $permissions, 37 | ]); 38 | } 39 | 40 | public function postEdit($roleId) 41 | { 42 | $title = $this->param('title'); 43 | $permissions = $this->param('permissions'); 44 | 45 | $role = Role::where('id', $roleId)->where("hidden", false)->first(); 46 | 47 | if(!$this->user()->can('edit role') && !$this->auth()->user()->isSuperAdmin()) { 48 | $this->flash("error", $this->lang('admin.role.general.not_authorized')); 49 | return $this->redirect('admin.roles.list'); 50 | } 51 | 52 | $validator = $this->validator()->validate([ 53 | 'title|Title' => [$title, "required|adminUniqueTitle({$title},{$role->id})"], 54 | 'permissions|Permissions' => [$permissions, "array"] 55 | ]); 56 | 57 | if(!$validator->passes()) { 58 | $this->flashNow('error', $this->lang('admin.general.fail')); 59 | return $this->render('admin/role/edit', [ 60 | 'role' => $role, 61 | 'errors' => $validator->errors(), 62 | ]); 63 | } 64 | 65 | $role->update([ 66 | 'title' => $title 67 | ]); 68 | 69 | $role->permissions()->detach(); 70 | 71 | if($permissions){ 72 | foreach ($permissions as $permission_name) { 73 | $permission = Permission::where('id',$permission_name)->first(); 74 | $role->givePermissionTo($permission); 75 | } 76 | } 77 | 78 | $this->flash('success', $this->lang('admin.general.success')); 79 | return $this->redirect('admin.roles.edit', [ 80 | 'roleId' => $roleId, 81 | ]); 82 | } 83 | 84 | public function getCreate() 85 | { 86 | $permissions = Permission::all(); 87 | 88 | if(!$this->auth()->user()->can('create role') && !$this->auth()->user()->isSuperAdmin()) { 89 | $this->flash('error', $this->lang('admin.role.general.cant_create')); 90 | return $this->redirect('admin.roles.list'); 91 | } 92 | 93 | return $this->render('admin/role/create',[ 94 | 'permissions' => $permissions, 95 | ]); 96 | } 97 | 98 | public function postCreate() 99 | { 100 | $title = $this->param('title'); 101 | $permissions = $this->param('permissions'); 102 | 103 | if(!$this->user()->can('edit role') && !$this->auth()->user()->isSuperAdmin()) { 104 | $this->flash("error", $this->lang('admin.role.general.not_authorized')); 105 | return $this->redirect('admin.roles.list'); 106 | } 107 | 108 | $validator = $this->validator()->validate([ 109 | 'title|Title' => [$title, "required|adminUniqueTitle()"], 110 | ]); 111 | 112 | if(!$validator->passes()) { 113 | $this->flashNow('error', $this->lang('admin.general.fail')); 114 | return $this->render('admin/role/create', [ 115 | 'errors' => $validator->errors(), 116 | ]); 117 | } 118 | 119 | $role = Role::create([ 120 | 'title' => $title 121 | ]); 122 | 123 | $role->permissions()->detach(); 124 | if($permissions){ 125 | foreach ($permissions as $permission_name) { 126 | $permission = Permission::where('id',$permission_name)->first(); 127 | $role->givePermissionTo($permission); 128 | } 129 | } 130 | 131 | $this->flash('success', $this->lang('admin.general.created')); 132 | return $this->redirect('admin.roles.list'); 133 | } 134 | 135 | public function getDelete($roleId) 136 | { 137 | $role = Role::where('id', $roleId)->where("hidden", false)->first(); 138 | 139 | if(!$this->user()->can('edit role') && !$this->auth()->user()->isSuperAdmin()) { 140 | $this->flash("error", $this->lang('admin.user.general.not_authorized')); 141 | return $this->redirect('admin.roles.list'); 142 | } 143 | 144 | return $this->render('admin/role/delete', [ 145 | 'role' => $role, 146 | ]); 147 | } 148 | 149 | public function postDelete($roleId) 150 | { 151 | $role = Role::where('id', $roleId)->where("hidden", false)->first(); 152 | 153 | if(!$this->user()->can('delete role') && !$this->auth()->user()->isSuperAdmin()) { 154 | $this->flash("error", $this->lang('admin.user.general.not_authorized')); 155 | return $this->redirect('admin.roles.list'); 156 | } 157 | 158 | $delete = $this->param('delete'); 159 | 160 | if(!$delete) { 161 | return $this->redirect('admin.home'); 162 | } 163 | 164 | if($delete === "true") { 165 | $role->delete(); 166 | $this->flash('success', $this->lang('admin.general.deleted')); 167 | return $this->redirect('admin.roles.list'); 168 | } 169 | 170 | $this->flash('info', $this->lang('admin.general.not_deleted')); 171 | return $this->redirect('admin.roles.edit', [ 172 | 'roleId' => $roleId 173 | ]); 174 | } 175 | } 176 | -------------------------------------------------------------------------------- /app/App/Http/Controllers/Admin/AdminUserController.php: -------------------------------------------------------------------------------- 1 | render('admin/user/list', [ 16 | 'users' => User::whereNotIn('id',$user_roles)->paginate(), 17 | ]); 18 | } 19 | public function getAdmins() 20 | { 21 | $user_roles = UserRole::get('user_id')->except($this->user()->id); 22 | 23 | return $this->render('admin/user/adminlist', [ 24 | 'users' => User::whereIn('id',$user_roles)->paginate(), 25 | ]); 26 | } 27 | 28 | public function getEdit($userId) 29 | { 30 | $user = User::where('id', $userId)->first(); 31 | 32 | if(!$this->authorize($user)) { 33 | return $this->redirect('admin.users.list'); 34 | } 35 | 36 | if(!$this->user()->can('edit users')) { 37 | $this->flash("error", $this->lang('admin.user.general.not_authorized')); 38 | return $this->redirect('admin.users.list'); 39 | } 40 | 41 | if($this->param('revoke')) { 42 | $revoke = $this->param('revoke'); 43 | switch ($revoke) { 44 | case 'remember': 45 | $user->removeRememberCredentials(); 46 | $this->flash('success', $this->lang('admin.user.revoke.remember')); 47 | return $this->redirect('admin.users.edit', [ 48 | 'userId' => $user->id, 49 | ]); 50 | break; 51 | case 'recovery': 52 | $user->revokeRecoveryHash(); 53 | $this->flash('success', $this->lang('admin.user.revoke.recovery')); 54 | return $this->redirect('admin.users.edit', [ 55 | 'userId' => $user->id, 56 | ]); 57 | break; 58 | default: 59 | break; 60 | } 61 | } 62 | 63 | return $this->render('admin/user/edit', [ 64 | 'user' => $user, 65 | ]); 66 | } 67 | 68 | public function getEditProfile($userId) 69 | { 70 | return $this->getEdit($userId); 71 | } 72 | 73 | public function postEditProfile($userId) 74 | { 75 | $username = $this->param('username'); 76 | $email = $this->param('email'); 77 | 78 | $user = User::where('id', $userId)->first(); 79 | 80 | if(!$this->authorize($user)) { 81 | return $this->redirect('admin.users.list'); 82 | } 83 | 84 | if(!$this->user()->can('edit users')) { 85 | $this->flash("error", $this->lang('admin.user.general.not_authorized')); 86 | return $this->redirect('admin.users.list'); 87 | } 88 | 89 | $validator = $this->validator()->validate([ 90 | 'username|Username' => [$username, "required|adminUniqueUsername({$user->username})"], 91 | 'email|E-Mail' => [$email, "required|email|adminUniqueEmail({$user->email})"], 92 | ]); 93 | 94 | if(!$validator->passes()) { 95 | $this->flashNow('error', $this->lang('admin.user.update.profile.fail')); 96 | return $this->render('admin/user/edit', [ 97 | 'user' => $user, 98 | 'errors' => $validator->errors(), 99 | ]); 100 | } 101 | 102 | $user->update([ 103 | 'username' => $username, 104 | 'email' => $email 105 | ]); 106 | 107 | $this->flash('success', $this->lang('admin.user.update.profile.success')); 108 | return $this->redirect('admin.users.edit', [ 109 | 'userId' => $userId, 110 | ]); 111 | } 112 | 113 | public function getEditSettings() 114 | { 115 | return $this->getEdit($userId); 116 | } 117 | 118 | public function postEditSettings($userId) 119 | { 120 | $user = User::where('id', $userId)->first(); 121 | 122 | if(!$this->authorize($user)) { 123 | return $this->redirect('admin.users.list'); 124 | } 125 | 126 | if(!$this->user()->can('edit users')) { 127 | $this->flash("error", $this->lang('admin.user.general.not_authorized')); 128 | return $this->redirect('admin.users.list'); 129 | } 130 | 131 | $active = $this->param('active'); 132 | 133 | switch ($active) { 134 | case 'yes': 135 | $user->activate(); 136 | $this->flash('success', $this->lang('admin.user.update.settings.active.yes')); 137 | return $this->redirect('admin.users.edit', [ 138 | 'userId' => $user->id, 139 | ]); 140 | break; 141 | case 'resend': 142 | $activeHash = $this->hash->generate(128); 143 | $user->deactivate($activeHash); 144 | $this->mail->send('/mail/auth/activate.twig', ['hash' => $activeHash, 'user' => $user], function($message) use ($user) { 145 | $message->to($user->email); 146 | $message->subject($this->lang('mail.activation.subject')); 147 | }); 148 | $this->flash('success', $this->lang('admin.user.update.settings.active.resend')); 149 | return $this->redirect('admin.users.edit', [ 150 | 'userId' => $user->id, 151 | ]); 152 | break; 153 | case 'no': 154 | $user->deactivate(); 155 | $this->flash('success', $this->lang('admin.user.update.settings.active.no')); 156 | return $this->redirect('admin.users.edit', [ 157 | 'userId' => $user->id, 158 | ]); 159 | break; 160 | default: 161 | break; 162 | } 163 | } 164 | 165 | public function getDelete($userId) 166 | { 167 | $user = User::where('id', $userId)->first(); 168 | 169 | if(!$this->authorize($user)) { 170 | return $this->redirect('admin.users.list'); 171 | } 172 | 173 | if(!$this->user()->can('edit users')) { 174 | $this->flash("error", $this->lang('admin.user.general.not_authorized')); 175 | return $this->redirect('admin.users.list'); 176 | } 177 | 178 | return $this->render('admin/user/delete', [ 179 | 'user' => $user, 180 | ]); 181 | } 182 | 183 | public function postDelete($userId) 184 | { 185 | $user = User::where('id', $userId)->first(); 186 | 187 | if(!$this->authorize($user)) { 188 | return $this->redirect('admin.users.list'); 189 | } 190 | 191 | if(!$this->user()->can('delete users')) { 192 | $this->flash("error", $this->lang('admin.user.general.not_authorized')); 193 | return $this->redirect('admin.users.list'); 194 | } 195 | 196 | $delete = $this->param('delete'); 197 | 198 | if(!$delete) { 199 | return $this->redirect('admin.home'); 200 | } 201 | 202 | if($delete === "true") { 203 | $user->delete(); 204 | $this->flash('success', $this->lang('admin.user.general.user_deleted')); 205 | return $this->redirect('admin.users.list'); 206 | } 207 | 208 | $this->flash('info', $this->lang('admin.user.general.user_not_deleted')); 209 | return $this->redirect('admin.users.edit', [ 210 | 'userId' => $userId 211 | ]); 212 | } 213 | 214 | public function postUpdateRole($userId, $role, $action) 215 | { 216 | $user = User::where('id', $userId)->first(); 217 | 218 | if(!$this->authorize($user)) { 219 | return $this->redirect('admin.users.list'); 220 | } 221 | 222 | if(!$this->user()->can('manage roles') || $role == "admin" && !$this->user()->can('make admin')) { 223 | $this->flash("error", $this->lang('admin.user.general.not_authorized')); 224 | return $this->redirect('admin.users.list'); 225 | } 226 | 227 | switch ($action) { 228 | case 'set': 229 | $user->giveRole($role); 230 | $this->flash("raw_success", "You have set the role to {$role} for {$user->username}."); 231 | break; 232 | case 'remove': 233 | $user->removeRole($role); 234 | $this->flash("raw_success", "You have removed the role {$role} from {$user->username}."); 235 | break; 236 | default: 237 | break; 238 | } 239 | 240 | return $this->redirect('admin.users.edit', [ 241 | 'userId' => $userId 242 | ]); 243 | } 244 | 245 | protected function authorize($user) 246 | { 247 | if(!$user) { 248 | $this->flash('error', $this->lang('admin.user.general.user_not_found')); 249 | return false; 250 | } 251 | 252 | if($user->id === $this->user()->id) { 253 | $this->flash('error', $this->lang('admin.user.general.user_edit_from_settings')); 254 | return false; 255 | } 256 | 257 | if(!$this->user()->canEdit($user)) { 258 | $this->flash('error', $this->lang('admin.user.general.cant_edit_user')); 259 | return false; 260 | } 261 | 262 | return true; 263 | } 264 | } 265 | -------------------------------------------------------------------------------- /app/App/Http/Controllers/Auth/ActivationController.php: -------------------------------------------------------------------------------- 1 | param('identifier'); 14 | 15 | // Make sure we check for an identifier first. 16 | if(!$identifier) { 17 | return $this->redirect('home'); 18 | } 19 | 20 | $user = User::where('active_hash', $identifier)->first(); 21 | 22 | if(!$user) { 23 | $this->flash('error', $this->lang('alerts.account.invalid_active_hash')); 24 | return $this->redirect('auth.login'); 25 | } 26 | 27 | if($user->active) { 28 | $this->flash("info", $this->lang('alerts.account.already_activated')); 29 | 30 | $user->update([ 31 | 'active_hash' => null 32 | ]); 33 | 34 | return $this->redirect('auth.login'); 35 | } 36 | 37 | if(!$user->active) { 38 | $user->update([ 39 | 'active' => true, 40 | 'active_hash' => null, 41 | ]); 42 | 43 | $this->flash("success", $this->lang('alerts.account.activated')); 44 | 45 | return $this->redirect('auth.login'); 46 | } 47 | } 48 | 49 | public function getResend() 50 | { 51 | if(Session::exists('temp_user_id')) { 52 | $user = User::where('id', Session::get('temp_user_id'))->first(); 53 | 54 | if(!$user) { 55 | return $this->redirect('home'); 56 | } 57 | 58 | $activeHash = $this->hash->generate(128); 59 | 60 | $user->update([ 61 | 'active_hash' => $activeHash 62 | ]); 63 | 64 | $this->mail->send('/mail/auth/activate.twig', ['hash' => $activeHash, 'user' => $user], function($message) use ($user) { 65 | $message->to($user->email); 66 | $message->subject($this->lang('mail.activation.subject')); 67 | }); 68 | 69 | Session::destroy('temp_user_id'); 70 | 71 | $this->flash('info', $this->lang('alerts.login.resend_activation')); 72 | return $this->redirect('auth.login'); 73 | } 74 | 75 | return $this->redirect('auth.login'); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /app/App/Http/Controllers/Auth/LoginController.php: -------------------------------------------------------------------------------- 1 | render('auth/login'); 17 | } 18 | 19 | public function post() 20 | { 21 | $username = $this->param('username'); 22 | $password = $this->param('password'); 23 | $remember = $this->param('remember'); 24 | 25 | $validator = $this->validator()->validate([ 26 | 'username|Username' => [$username, 'required'], 27 | 'password|Password' => [$password, 'required'], 28 | ]); 29 | 30 | if($validator->passes()) { 31 | $user = User::where('username', $username)->orWhere('email', $username)->first(); 32 | 33 | if(!$user || !$this->hash->verifyPassword($password, $user->password)) { 34 | $this->flash("error", $this->lang('alerts.login.invalid')); 35 | return $this->redirect('auth.login'); 36 | } else if($user && !(bool)$user->active) { 37 | Session::set('temp_user_id', $user->id); 38 | $this->flash("raw_warning", "The account you are trying to access has not been activated. Resend activation link"); 39 | return $this->redirect('auth.login'); 40 | } else if($user && $this->hash->verifyPassword($password, $user->password)) { 41 | Session::set($this->config('app.auth_id'), $user->id); 42 | 43 | if(Session::exists('temp_user_id')) { 44 | Session::destroy('temp_user_id'); 45 | } 46 | 47 | if($remember === "on") { 48 | $rememberIdentifier = $this->hash->generate(128); 49 | $rememberToken = $this->hash->generate(128); 50 | 51 | $user->updateRememberCredentials($rememberIdentifier, $this->hash->hash($rememberToken)); 52 | 53 | Cookie::set($this->config('app.remember_id'), 54 | "{$rememberIdentifier}.{$rememberToken}", 55 | Carbon::now()->addWeek(2)->timestamp 56 | ); 57 | } 58 | 59 | return $this->redirect('home'); 60 | } 61 | } 62 | 63 | $this->flashNow("error", $this->lang('alerts.login.error')); 64 | return $this->render('auth/login', [ 65 | 'errors' => $validator->errors(), 66 | ]); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /app/App/Http/Controllers/Auth/PasswordResetController.php: -------------------------------------------------------------------------------- 1 | render('auth/password/forgot'); 12 | } 13 | 14 | public function postForgot() 15 | { 16 | $email = $this->param('email'); 17 | $response = $this->recaptcha->verify($this->param('g-recaptcha-response')); 18 | 19 | if(!$response->isSuccess()) { 20 | $this->flash('warning', $this->lang('alerts.recaptcha_failed')); 21 | return $this->redirect('auth.password.forgot'); 22 | } 23 | 24 | $validator = $this->validator()->validate([ 25 | 'email|E-Mail' => [$email, 'required|email'], 26 | ]); 27 | 28 | if($validator->passes()) { 29 | $user = $this->auth->where('email', $email)->first(); 30 | 31 | if($user) { 32 | $identifier = $this->hash->generate(); 33 | 34 | $user->update([ 35 | 'recover_hash' => $this->hash->hash($identifier), 36 | ]); 37 | 38 | $this->mail->send('/mail/password/forgot.twig', ['identifier' => $identifier, 'date' => \Carbon\Carbon::now()->toFormattedDateString(), 'user' => $user], function($message) use ($user) { 39 | $message->to($user->email); 40 | $message->subject($this->lang('mail.password.forgot.subject')); 41 | }); 42 | } 43 | 44 | $this->flash("info", $this->lang('alerts.forgot_password_success')); 45 | return $this->redirect('auth.login'); 46 | } 47 | 48 | $this->flash('error', $this->lang('alerts.forgot_password_failed')); 49 | return $this->redirect('auth.password.forgot'); 50 | } 51 | 52 | public function getReset() 53 | { 54 | $identifier = $this->param('identifier'); 55 | 56 | if(!$identifier) { 57 | return $this->redirect('auth.login'); 58 | } 59 | 60 | return $this->render('auth/password/reset', [ 61 | 'identifier' => $identifier, 62 | ]); 63 | } 64 | 65 | public function postReset() 66 | { 67 | $email = $this->param('email'); 68 | $identifier = $this->param('identifier'); 69 | $newPassword = $this->param('new_password'); 70 | $confirmNewPassword = $this->param('confirm_new_password'); 71 | 72 | if(!$email) { 73 | $this->flash('error', $this->lang('alerts.reset_password_no_email')); 74 | return $this->redirect('auth.password.reset', [], [ 75 | 'identifier' => $identifier, 76 | ]); 77 | } 78 | 79 | $user = $this->auth->where('email', $email)->first(); 80 | 81 | if(!$user) { 82 | return $this->redirect('auth.login'); 83 | } 84 | 85 | $knownIdentifier = $user->recover_hash; 86 | $userHash = $this->hash->hash($identifier); 87 | 88 | if(!$knownIdentifier || !$this->hash->verifyHash($knownIdentifier, $userHash)) { 89 | $user->update([ 90 | 'recover_hash' => null, 91 | ]); 92 | 93 | $this->flash('error', $this->lang('alerts.reset_password_invalid')); 94 | return $this->redirect('auth.password.forgot'); 95 | } 96 | 97 | $validator = $this->validator()->validate([ 98 | 'new_password|New Password' => [$newPassword, 'required|min(6)'], 99 | 'confirm_new_password|Confirm New Password' => [$confirmNewPassword, 'required|matches(new_password)'] 100 | ]); 101 | 102 | if($validator->passes()) { 103 | $user->update([ 104 | 'recover_hash' => null, 105 | 'password' => $this->hash->password($newPassword), 106 | ]); 107 | 108 | $this->flash('success', $this->lang('alerts.reset_password_success')); 109 | return $this->redirect('auth.login'); 110 | } 111 | 112 | $this->flashNow('error', $this->lang('alerts.reset_password_failed')); 113 | return $this->render('auth/password/reset', [ 114 | 'identifier' => $identifier, 115 | 'errors' => $validator->errors(), 116 | ]); 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /app/App/Http/Controllers/Auth/RegisterController.php: -------------------------------------------------------------------------------- 1 | render('auth/register'); 14 | } 15 | 16 | public function post() 17 | { 18 | $username = $this->param('username'); 19 | $email = $this->param('email'); 20 | $password = $this->param('password'); 21 | $confirm_password = $this->param('confirm_password'); 22 | 23 | if($this->config('app.activation.method') === 'recaptcha') { 24 | $recaptcha = $this->param('g-recaptcha-response'); 25 | 26 | if(!$this->recaptcha->verify($recaptcha)->isSuccess()) { 27 | $this->flash('warning', $this->lang('alerts.recaptcha_failed')); 28 | return $this->redirect('auth.register'); 29 | } 30 | } 31 | 32 | $validator = $this->validator()->validate([ 33 | 'username|Username' => [$username, 'required|min(3)|alnumDash|uniqueUsername'], 34 | 'email|E-Mail' => [$email, 'required|email|uniqueEmail'], 35 | 'password|Password' => [$password, 'required|min(6)'], 36 | 'confirm_password|Confirm Password' => [$confirm_password, 'required|matches(password)'], 37 | ]); 38 | 39 | if($validator->passes()) { 40 | $activeHash = $this->hash->generate(128); 41 | 42 | $user = User::create([ 43 | 'username' => $username, 44 | 'email' => $email, 45 | 'password' => $this->hash->password($password), 46 | 'active_hash' => $activeHash, 47 | 'active' => false, 48 | ]); 49 | 50 | if($this->config('app.activation.method') === 'mail') { 51 | $this->flash('info', $this->lang('alerts.registration.requires_mail_activation')); 52 | $this->mail->send('/mail/auth/activate.twig', ['hash' => $activeHash, 'user' => $user], function($message) use ($user) { 53 | $message->to($user->email); 54 | $message->subject($this->lang('mail.activation.subject')); 55 | }); 56 | } else { 57 | $user->update([ 58 | 'active' => true, 59 | 'active_hash' => null, 60 | ]); 61 | 62 | $this->flash('success', $this->lang('alerts.registration.successful')); 63 | } 64 | 65 | return $this->redirect('auth.login'); 66 | } 67 | 68 | $this->flashNow('error', $this->lang('alerts.registration.error')); 69 | return $this->render('auth/register', [ 70 | 'errors' => $validator->errors(), 71 | ]); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /app/App/Http/Controllers/Auth/SettingsController.php: -------------------------------------------------------------------------------- 1 | render('auth/account/settings'); 12 | } 13 | 14 | public function getProfile() 15 | { 16 | return $this->redirect('auth.settings'); 17 | } 18 | 19 | 20 | public function getPassword() 21 | { 22 | return $this->redirect('auth.settings'); 23 | } 24 | 25 | public function postProfile() 26 | { 27 | $email = $this->param('email'); 28 | 29 | $validator = $this->validator()->validate([ 30 | 'email|E-Mail' => [$email, 'required|email|uniqueEmail'], 31 | ]); 32 | 33 | if($validator->passes()) { 34 | $user = $this->user()->update([ 35 | 'email' => $email, 36 | ]); 37 | 38 | $this->flash('success', $this->lang('alerts.account.profile.updated')); 39 | return $this->redirect('auth.settings'); 40 | } 41 | 42 | $this->flashNow("error", $this->lang('alerts.account.profile.failed')); 43 | return $this->render('auth/account/settings', [ 44 | 'errors' => $validator->errors(), 45 | ]); 46 | } 47 | 48 | public function postPassword() 49 | { 50 | $currentPassword = $this->param('current_password'); 51 | $newPassword = $this->param('new_password'); 52 | $confirmNewPassword = $this->param('confirm_new_password'); 53 | 54 | $validator = $this->validator()->validate([ 55 | 'current_password|Current Password' => [$currentPassword, 'required|matchesCurrentPassword'], 56 | 'new_password|New Password' => [$newPassword, 'required|min(6)'], 57 | 'confirm_new_password|Confirm New Password' => [$confirmNewPassword, 'required|matches(new_password)'], 58 | ]); 59 | 60 | if($validator->passes()) { 61 | $this->user()->update([ 62 | 'password' => $this->hash->password($newPassword), 63 | ]); 64 | 65 | $this->flash('success', $this->lang('alerts.account.password.updated')); 66 | return $this->redirect('auth.settings'); 67 | } 68 | 69 | $this->flashNow("error", $this->lang('alerts.account.password.failed')); 70 | return $this->render('auth/account/settings', [ 71 | 'errors' => $validator->errors(), 72 | ]); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /app/App/Http/Controllers/Controller.php: -------------------------------------------------------------------------------- 1 | request = $request; 19 | $this->response = $response; 20 | $this->args = $args; 21 | $this->container = $container; 22 | } 23 | 24 | public function __get($property) 25 | { 26 | if ($this->container->{$property}) { 27 | return $this->container->{$property}; 28 | } 29 | } 30 | 31 | public function config($key) 32 | { 33 | return $this->config->get($key); 34 | } 35 | 36 | public function lang($key) 37 | { 38 | return $this->config("lang." . $key); 39 | } 40 | 41 | public function param($name) 42 | { 43 | return $this->request->getParam($name); 44 | } 45 | 46 | public function flash($type, $message) 47 | { 48 | return $this->flash->addMessage($type, $message); 49 | } 50 | 51 | public function flashNow($type, $message) 52 | { 53 | return $this->flash->addMessageNow($type, $message); 54 | } 55 | 56 | public function render($name, array $args = []) 57 | { 58 | return $this->container->view->render($this->response, $name . '.twig', $args); 59 | } 60 | 61 | public function redirect($path = null, $args = [], $params = []) 62 | { 63 | $path = $path != null ? $path : 'home'; 64 | 65 | return $this->response->withRedirect($this->router()->pathFor($path, $args, $params)); 66 | } 67 | 68 | public function notFound() 69 | { 70 | throw new NotFoundException($this->request, $this->response); 71 | } 72 | 73 | public function validator() 74 | { 75 | return new Validator($this->container); 76 | } 77 | 78 | public function auth() 79 | { 80 | return $this->auth; 81 | } 82 | 83 | public function user() 84 | { 85 | return $this->auth()->user(); 86 | } 87 | 88 | protected function router() 89 | { 90 | return $this->container['router']; 91 | } 92 | } -------------------------------------------------------------------------------- /app/App/Http/Controllers/HomeController.php: -------------------------------------------------------------------------------- 1 | render('home'); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /app/App/Http/Middleware/AdminMiddleware.php: -------------------------------------------------------------------------------- 1 | auth()->check()) { 12 | if($this->user()->isAdmin() || $this->user()->isSuperAdmin() || $this->user()->can('view admin pages')) { 13 | $response = $next($request, $response); 14 | return $response; 15 | } 16 | } 17 | 18 | return $this->notFound($request, $response); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/App/Http/Middleware/AuthMiddleware.php: -------------------------------------------------------------------------------- 1 | auth()->check()) { 12 | $this->flash('warning', $this->lang('alerts.requires_auth')); 13 | return $this->redirect($response, 'auth.login'); 14 | } 15 | 16 | $response = $next($request, $response); 17 | return $response; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /app/App/Http/Middleware/CsrfMiddleware.php: -------------------------------------------------------------------------------- 1 | container->view->getEnvironment()->addGlobal('csrf', [ 12 | 'field' => ' 13 | 14 | 15 | ' 16 | ]); 17 | 18 | $response = $next($request, $response); 19 | return $response; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/App/Http/Middleware/GuestMiddleware.php: -------------------------------------------------------------------------------- 1 | auth()->check()) { 12 | return $this->redirect($response, 'home'); 13 | } 14 | 15 | $response = $next($request, $response); 16 | return $response; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /app/App/Http/Middleware/Middleware.php: -------------------------------------------------------------------------------- 1 | container = $container; 15 | } 16 | 17 | public function auth() 18 | { 19 | return $this->container->auth; 20 | } 21 | 22 | public function user() 23 | { 24 | return $this->auth()->user(); 25 | } 26 | 27 | public function flash($type, $message) 28 | { 29 | $this->container->flash->addMessage($type, $message); 30 | } 31 | 32 | public function config($key) 33 | { 34 | return $this->container->config->get($key); 35 | } 36 | 37 | public function lang($key) 38 | { 39 | return $this->config("lang." . $key); 40 | } 41 | 42 | public function redirect($response, $path) 43 | { 44 | return $response->withRedirect($this->router()->pathFor($path)); 45 | } 46 | 47 | public function notFound($request, $response) 48 | { 49 | throw new NotFoundException($request, $response); 50 | } 51 | 52 | protected function router() 53 | { 54 | return $this->container['router']; 55 | } 56 | 57 | protected function isSecure() 58 | { 59 | if(!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on' || !empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') { 60 | return true; 61 | } 62 | 63 | return false; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /app/App/Http/Middleware/OldInputMiddleware.php: -------------------------------------------------------------------------------- 1 | getParams()); 13 | $this->container->view->getEnvironment()->addGlobal('old', Session::get('old')); 14 | 15 | $response = $next($request, $response); 16 | return $response; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /app/App/Http/Middleware/Pagination.php: -------------------------------------------------------------------------------- 1 | container->view; 12 | \Illuminate\Pagination\Paginator::viewFactoryResolver( function() use ( $view ) { 13 | return new class( $view ) { 14 | private $view; 15 | private $template; 16 | private $data; 17 | public function __construct( \Slim\Views\Twig $view ) 18 | { 19 | $this->view = $view; 20 | } 21 | public function make( string $template, $data = null ) 22 | { 23 | $this->template = 'pagination.twig'; 24 | $this->data = $data; 25 | return $this; 26 | } 27 | public function render() 28 | { 29 | return $this->view->fetch($this->template, $this->data); 30 | } 31 | }; 32 | }); 33 | \Illuminate\Pagination\Paginator::currentPageResolver(function() use ($request) { 34 | return $request->getParam('page'); 35 | }); 36 | 37 | return $next( $request, $response ) ; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /app/App/Http/Middleware/RememberMiddleware.php: -------------------------------------------------------------------------------- 1 | config('app.remember_id')) && !$this->container->auth->check()) { 14 | $data = Cookie::get($this->config('app.remember_id')); 15 | $credentials = explode('.', $data); 16 | 17 | if(empty(trim($data)) || count($credentials) !== 2) { 18 | Cookie::destroy($this->config('app.remember_id')); 19 | return $this->redirect($response, 'home'); 20 | } else { 21 | $identifier = $credentials[0]; 22 | $token = $this->container->hash->hash($credentials[1]); 23 | 24 | $user = $this->container->auth->where('remember_identifier', $identifier)->first(); 25 | 26 | if($user) { 27 | if($this->container->hash->verifyHash($token, $user->remember_token)) { 28 | if($user->active) { 29 | Session::set($this->config('app.auth_id'), $user->id); 30 | // We must define a reponse with a redirect to detect a session when we first hit the page, REQUEST_URI is optional. 31 | $response = $response->withRedirect($this->container->config->get('site.url') . $_SERVER['REQUEST_URI']); 32 | return $next($request, $response); 33 | } else { 34 | Cookie::destroy($this->config('app.remember_id')); 35 | 36 | $user->removeRememberCredentials(); 37 | 38 | $this->flash("warning", "Your account has not been activated."); 39 | return $this->redirect($response, 'auth.login'); 40 | } 41 | } else { 42 | $user->removeRememberCredentials(); 43 | } 44 | } 45 | } 46 | } 47 | 48 | $response = $next($request, $response); 49 | return $response; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /app/App/Http/Middleware/RequiresSecureRequestMiddleware.php: -------------------------------------------------------------------------------- 1 | isSecure()) { 12 | throw new \RuntimeException(sprintf("Insecure requests are not allowed for %s!", $request->getRequestTarget())); 13 | } 14 | 15 | $response = $next($request, $response); 16 | return $response; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /app/App/Lib/Cookie.php: -------------------------------------------------------------------------------- 1 | forNow[$key])) { 14 | $this->forNow[$key] = []; 15 | } 16 | 17 | $this->forNow[$key][] = $message; 18 | } 19 | 20 | public function getMessages() 21 | { 22 | $messages = $this->fromPrevious; 23 | 24 | foreach($this->forNow as $key => $values) { 25 | if(!isset($messages[$key])){ 26 | $messages[$key] = []; 27 | } 28 | 29 | foreach($values as $value){ 30 | array_push($messages[$key], $value); 31 | } 32 | } 33 | 34 | return $messages; 35 | } 36 | 37 | public function getMessage($key) 38 | { 39 | $messages = $this->getMessages(); 40 | return (isset($messages[$key])) ? $messages[$key] : null; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /app/App/Lib/Hash.php: -------------------------------------------------------------------------------- 1 | _random = new RandomLib; 14 | } 15 | 16 | public function password($password) 17 | { 18 | return password_hash($password, PASSWORD_DEFAULT); 19 | } 20 | 21 | public function verifyPassword($givenPassword, $knownPassword) 22 | { 23 | return password_verify($givenPassword, $knownPassword); 24 | } 25 | 26 | public function generate($length = 64, $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ') 27 | { 28 | return $this->generator()->generateString($length, $characters); 29 | } 30 | 31 | public function hash($input) 32 | { 33 | return hash('sha256', $input); 34 | } 35 | 36 | public function verifyHash($knownHash, $givenHash) 37 | { 38 | return $this->hash_verify($knownHash, $givenHash); 39 | } 40 | 41 | protected function generator() 42 | { 43 | return $this->_random->getMediumStrengthGenerator(); 44 | } 45 | 46 | protected function hash_verify($known_string, $user_string) 47 | { 48 | if (func_num_args() !== 2) { 49 | // handle wrong parameter count as the native implentation 50 | trigger_error('hash_verify() expects exactly 2 parameters, ' . func_num_args() . ' given', E_USER_WARNING); 51 | return null; 52 | } 53 | 54 | if (is_string($known_string) !== true) { 55 | trigger_error('hash_verify(): Expected known_string to be a string, ' . gettype($known_string) . ' given', E_USER_WARNING); 56 | return false; 57 | } 58 | 59 | $known_string_len = strlen($known_string); 60 | $user_string_type_error = 'hash_verify(): Expected user_string to be a string, ' . gettype($user_string) . ' given'; // prepare wrong type error message now to reduce the impact of string concatenation and the gettype call 61 | if (is_string($user_string) !== true) { 62 | trigger_error($user_string_type_error, E_USER_WARNING); 63 | // prevention of timing attacks might be still possible if we handle $user_string as a string of diffent length (the trigger_error() call increases the execution time a bit) 64 | $user_string_len = strlen($user_string); 65 | $user_string_len = $known_string_len + 1; 66 | } else { 67 | $user_string_len = $known_string_len + 1; 68 | $user_string_len = strlen($user_string); 69 | } 70 | 71 | if ($known_string_len !== $user_string_len) { 72 | $res = $known_string ^ $known_string; // use $known_string instead of $user_string to handle strings of diffrent length. 73 | $ret = 1; // set $ret to 1 to make sure false is returned 74 | } else { 75 | $res = $known_string ^ $user_string; 76 | $ret = 0; 77 | } 78 | 79 | for ($i = strlen($res) - 1; $i >= 0; $i--) { 80 | $ret |= ord($res[$i]); 81 | } 82 | 83 | return $ret === 0; 84 | } 85 | } -------------------------------------------------------------------------------- /app/App/Lib/Session.php: -------------------------------------------------------------------------------- 1 | mailer = $mailer; 15 | $this->container = $container; 16 | } 17 | 18 | public function send($template, $data, $callback) 19 | { 20 | $message = new Message($this->mailer); 21 | 22 | $message->body($this->container->twig->render($template, [ 23 | 'data' => $data 24 | ])); 25 | 26 | call_user_func($callback, $message); 27 | 28 | $this->mailer->send(); 29 | } 30 | } -------------------------------------------------------------------------------- /app/App/Mail/Mailtrap/Message.php: -------------------------------------------------------------------------------- 1 | mailer = $mailer; 12 | } 13 | 14 | public function to($address) 15 | { 16 | $this->mailer->addAddress($address); 17 | } 18 | 19 | public function subject($subject) 20 | { 21 | $this->mailer->Subject = $subject; 22 | } 23 | 24 | public function body($body) 25 | { 26 | $this->mailer->Body = $body; 27 | } 28 | } -------------------------------------------------------------------------------- /app/App/Traits/HasPermissionsTrait.php: -------------------------------------------------------------------------------- 1 | getAllPermissions(Arr::flatten($permissions)); 16 | 17 | if ($permissions === null) { 18 | return $this; 19 | } 20 | 21 | if($this->permissions()->exists($permissions)) { 22 | return $this; 23 | } 24 | 25 | $this->permissions()->saveMany($permissions); 26 | 27 | return $this; 28 | } 29 | 30 | public function withdrawPermissionTo(...$permissions) 31 | { 32 | $permissions = $this->getAllPermissions(Arr::flatten($permissions)); 33 | 34 | $this->permissions()->detach($permissions); 35 | 36 | return $this; 37 | } 38 | 39 | public function updatePermissions(...$permissions) 40 | { 41 | $this->permissions()->detach(); 42 | 43 | return $this->givePermissionTo($permissions); 44 | } 45 | 46 | public function hasRole(...$roles) 47 | { 48 | foreach ($roles as $role) { 49 | if ($this->roles->contains('title', $role)) { 50 | return true; 51 | } 52 | } 53 | 54 | return false; 55 | } 56 | 57 | public function hasPermissionTo($permission) 58 | { 59 | return $this->hasPermissionThroughRole($permission) || $this->hasPermission($permission); 60 | } 61 | 62 | protected function hasPermissionThroughRole($permission) 63 | { 64 | foreach ($permission->roles as $role) { 65 | if ($this->roles->contains($role)) { 66 | return true; 67 | } 68 | } 69 | 70 | return false; 71 | } 72 | 73 | protected function hasPermission($permission) 74 | { 75 | return (bool) $this->permissions->where('name', $permission->name)->count(); 76 | } 77 | 78 | protected function getAllPermissions(array $permissions) 79 | { 80 | return Permission::whereIn('name', $permissions)->get(); 81 | } 82 | 83 | public function roles() 84 | { 85 | return $this->belongsToMany(Role::class, 'users_roles', 'user_id'); 86 | } 87 | 88 | public function permissions() 89 | { 90 | return $this->belongsToMany(Permission::class, 'users_permissions', 'user_id'); 91 | } 92 | 93 | 94 | protected function flatten($array, $depth = INF) 95 | { 96 | return array_reduce($array, function ($result, $item) use ($depth) { 97 | $item = $item instanceof Collection ? $item->all() : $item; 98 | 99 | if (! is_array($item)) { 100 | return array_merge($result, [$item]); 101 | } elseif ($depth === 1) { 102 | return array_merge($result, array_values($item)); 103 | } else { 104 | return array_merge($result, $this->flatten($item, $depth - 1)); 105 | } 106 | }, []); 107 | } 108 | } -------------------------------------------------------------------------------- /app/App/Twig/TwigExtension.php: -------------------------------------------------------------------------------- 1 | container = $container; 12 | } 13 | 14 | public function getName() 15 | { 16 | return 'app'; 17 | } 18 | 19 | public function getFunctions() 20 | { 21 | return [ 22 | new \Twig\TwigFunction('asset', [$this, 'asset']), 23 | new \Twig\TwigFunction('getenv', [$this, 'getenv']), 24 | new \Twig\TwigFunction('config', [$this, 'config']), 25 | new \Twig\TwigFunction('pagination_url', [$this, 'pagination_url']), 26 | ]; 27 | } 28 | 29 | public function asset($name) 30 | { 31 | return env('APP_URL') . '/' . $name; 32 | } 33 | 34 | public function getenv($key, $default = null) 35 | { 36 | return env($key, $default); 37 | } 38 | 39 | public function config($key) 40 | { 41 | return $this->container->config->get($key); 42 | } 43 | 44 | public function pagination_url($path,$url) 45 | { 46 | 47 | return $path.ltrim($url, '/'); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /app/App/Validation/Validator.php: -------------------------------------------------------------------------------- 1 | container = $container; 18 | $this->auth = $container->auth; 19 | 20 | $this->addFieldMessages([ 21 | 'username' => [ 22 | 'min' => 'Your username must be a minimum of {$0} characters.', 23 | 'uniqueUsername' => 'This username has already been taken.', 24 | ], 25 | 26 | 'email' => [ 27 | 'uniqueEmail' => 'This e-mail is already in use.', 28 | ], 29 | 30 | 'password' => [ 31 | 'min' => 'Your password must be a minimum of {$0} characters.', 32 | ], 33 | 34 | 'new_password' => [ 35 | 'min' => 'Your new password must be a minimum of {$0} characters.', 36 | ], 37 | 38 | 'confirm_password' => [ 39 | 'matches' => 'Confirm Password must match Password.' 40 | ], 41 | 42 | 'confirm_new_password' => [ 43 | 'matches' => 'Confirm New Password must match New Password.' 44 | ], 45 | ]); 46 | 47 | $this->addRuleMessages([ 48 | 'matchesCurrentPassword' => 'Your current password is incorrect.', 49 | 'adminUniqueEmail' => "This e-mail is tied to another account.", 50 | 'adminUniqueUsername' => "This username is taken by another account.", 51 | 'adminUniqueTitle' => "This title is taken by another role.", 52 | 'adminUniqueName' => "This name is taken by another permission.", 53 | ]); 54 | } 55 | 56 | public function validate_uniqueUsername($value, $input, $args) 57 | { 58 | return !(bool) $this->auth->where('username', $value)->count(); 59 | } 60 | 61 | public function validate_uniqueEmail($value, $input, $args) 62 | { 63 | $user = $this->auth->where('email', $value); 64 | 65 | if($this->auth->check() && $this->auth->user()->email === $value) { 66 | return true; 67 | } 68 | 69 | return !(bool) $user->count(); 70 | } 71 | 72 | public function validate_matchesCurrentPassword($value, $input, $args) 73 | { 74 | if($this->auth->check() && $this->container->hash->verifyPassword($value, $this->auth->user()->password)) { 75 | return true; 76 | } 77 | 78 | return false; 79 | } 80 | 81 | public function validate_adminUniqueEmail($value, $input, $args) 82 | { 83 | $user = $this->container->user->where('email', $args[0])->first(); 84 | 85 | if(!$user) { 86 | return false; 87 | } 88 | 89 | if($user->email === $value) { 90 | return true; 91 | } 92 | 93 | return !(bool) $this->container->user->where('email', $value)->count(); 94 | } 95 | 96 | public function validate_adminUniqueUsername($value, $input, $args) 97 | { 98 | $user = $this->container->user->where('username', $args[0])->first(); 99 | 100 | if(!$user) { 101 | return false; 102 | } 103 | 104 | if($user->username === $value) { 105 | return true; 106 | } 107 | 108 | return !(bool) $this->container->user->where('username', $value)->count(); 109 | } 110 | 111 | public function validate_adminUniqueTitle($value, $input, $args) 112 | { 113 | $role = Role::where('id', $args[1])->first(); 114 | 115 | if(!$role && ($args[1] !== NULL)) { 116 | return false; 117 | } 118 | 119 | if($role->title === $args[0]) { 120 | return true; 121 | } 122 | 123 | return !(bool) Role::where('title', $value)->count(); 124 | } 125 | 126 | public function validate_adminUniqueName($value, $input, $args) 127 | { 128 | $role = Permission::where('id', $args[1])->first(); 129 | 130 | if(!$role && ($args[1]!==NULL)) { 131 | return false; 132 | } 133 | 134 | if($role->name === $args[0]) { 135 | return true; 136 | } 137 | 138 | return !(bool) Permission::where('name', $value)->count(); 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /app/App/Validation/Violin/Contracts/MessageBagContract.php: -------------------------------------------------------------------------------- 1 | = $args[0] && $value <= $args[1]) ? true : false; 12 | } 13 | 14 | public function error() 15 | { 16 | return '{field} must be between {$0} and {$1}.'; 17 | } 18 | 19 | public function canSkip() 20 | { 21 | return true; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /app/App/Validation/Violin/Rules/BoolRule.php: -------------------------------------------------------------------------------- 1 | = (float) $args[0]; 15 | } 16 | 17 | return mb_strlen($value) >= (int) $args[0]; 18 | } 19 | 20 | public function error() 21 | { 22 | return '{field} must be a minimum of {$0}.'; 23 | } 24 | 25 | public function canSkip() 26 | { 27 | return true; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /app/App/Validation/Violin/Rules/NumberRule.php: -------------------------------------------------------------------------------- 1 | $value) { 28 | $this->messages[$key] = (array) $value; 29 | } 30 | } 31 | 32 | /** 33 | * Checks if the bag has messages for a given key. 34 | * 35 | * @param string $key 36 | * @return boolean 37 | */ 38 | public function has($key) 39 | { 40 | return ! is_null($this->first($key)); 41 | } 42 | 43 | /** 44 | * Get the first message with a given key. 45 | * If the given key doesn't exist, it returns the first 46 | * message of the bag. 47 | * Returns null if the bag is empty. 48 | * 49 | * @param string $key 50 | * @return string|null 51 | */ 52 | public function first($key = null) 53 | { 54 | $messages = is_null($key) ? $this->all() : $this->get($key); 55 | return ($messages && count($messages) > 0) ? $messages[0] : null; 56 | } 57 | 58 | /** 59 | * Get all of the messages from a given key. 60 | * Returns null if the given key is empty, or 61 | * if it doesn't exist. 62 | * 63 | * @param string $key 64 | * @return array|null 65 | */ 66 | public function get($key) 67 | { 68 | if (array_key_exists($key, $this->messages)) { 69 | return !empty($this->messages[$key]) ? $this->messages[$key] : null; 70 | } 71 | 72 | return null; 73 | } 74 | 75 | /** 76 | * Get all of the messages in the bag. 77 | * 78 | * @return array 79 | */ 80 | public function all() 81 | { 82 | return iterator_to_array(new RecursiveIteratorIterator( 83 | new RecursiveArrayIterator($this->messages) 84 | ), false); 85 | } 86 | 87 | /** 88 | * Return all of the keys in the bag. 89 | * 90 | * @return array 91 | */ 92 | public function keys() 93 | { 94 | return array_keys($this->messages); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /app/Migration/Migration.php: -------------------------------------------------------------------------------- 1 | capsule = new Capsule; 17 | $this->capsule->addConnection([ 18 | 'driver' => env('DB_CONNECTION'), 19 | 'host' => env('DB_HOST'), 20 | 'port' => env('DB_PORT'), 21 | 'database' => env('DB_DATABASE'), 22 | 'username' => env('DB_USERNAME'), 23 | 'password' => env('DB_PASSWORD'), 24 | 'charset' => 'utf8', 25 | 'collation' => 'utf8_unicode_ci', 26 | ]); 27 | 28 | $this->capsule->bootEloquent(); 29 | $this->capsule->setAsGlobal(); 30 | $this->schema = $this->capsule->schema(); 31 | } 32 | } -------------------------------------------------------------------------------- /app/helpers.php: -------------------------------------------------------------------------------- 1 | load(); 20 | } 21 | 22 | $app = new App(new Container( 23 | include INC_ROOT . '/container.php' 24 | )); 25 | 26 | $container = $app->getContainer(); 27 | 28 | $container['config'] = function($c) { 29 | return new Config(INC_ROOT . '/../config'); 30 | }; 31 | 32 | $app->add(RememberMiddleware::class); 33 | $app->add(CsrfMiddleware::class); 34 | $app->add(OldInputMiddleware::class); 35 | $app->add(Pagination::class) ; 36 | 37 | $app->add($container->csrf); 38 | 39 | $container['db']->bootEloquent(); 40 | 41 | require INC_ROOT . '/../routes/web.php'; 42 | require INC_ROOT . '/../routes/admin.php'; 43 | -------------------------------------------------------------------------------- /bootstrap/container.php: -------------------------------------------------------------------------------- 1 | [ 4 | 'displayErrorDetails' => getenv('APP_ENV') === "production" ? false : true, 5 | 'determineRouteBeforeAppMiddleware' => true, 6 | 'viewTemplatesDirectory' => INC_ROOT . '/../resources/views', 7 | ], 8 | 9 | 'user' => function($c) { 10 | return new \App\Database\User; 11 | }, 12 | 13 | 'auth' => function($c) { 14 | return new \App\Auth\Auth; 15 | }, 16 | 17 | 'hash' => function($c) { 18 | return new \App\Lib\Hash; 19 | }, 20 | 21 | 'flash' => function($c) { 22 | return new \App\Lib\Flash; 23 | }, 24 | 25 | 'recaptcha' => function($c) { 26 | return new \ReCaptcha\ReCaptcha($c->config->get('plugins.recaptcha.secret')); 27 | }, 28 | 29 | 'twig' => function($c) { 30 | $twig = new \Twig\Environment(new \Twig\Loader\FilesystemLoader($c['settings']['viewTemplatesDirectory'])); 31 | 32 | // We need to load this again to use our functions with our mailing system. 33 | $twig->addExtension(new \App\Twig\TwigExtension($c)); 34 | 35 | return $twig; 36 | }, 37 | 38 | 'view' => function($c) { 39 | $view = new \Slim\Views\Twig($c['settings']['viewTemplatesDirectory'], [ 40 | 'debug' => env('APP_ENV', 'development') === "production" ? false : true 41 | ]); 42 | 43 | $view->getEnvironment()->addGlobal('auth', [ 44 | 'check' => $c->auth->check(), 45 | 'user' => $c->auth->user(), 46 | ]); 47 | 48 | $view->addExtension(new \Slim\Views\TwigExtension($c['router'], $c['request']->getUri())); 49 | $view->addExtension(new \Twig\Extension\DebugExtension); 50 | $view->addExtension(new \App\Twig\TwigExtension($c)); 51 | 52 | $view->getEnvironment()->addGlobal('flash', $c['flash']); 53 | 54 | return $view; 55 | }, 56 | 57 | 'notFoundHandler' => function($c) { 58 | return function($request, $response) use ($c) { 59 | $response = $response->withStatus(404); 60 | return $c->view->render($response, 'errors/404.twig', [ 61 | 'request_uri' => urldecode($_SERVER['REQUEST_URI']) 62 | ]); 63 | }; 64 | }, 65 | 66 | 'notAllowedHandler' => function($c) { 67 | return function ($request, $response, $methods) use ($c) { 68 | $response = $response->withStatus(405); 69 | return $c->view->render($response, 'errors/405.twig', [ 70 | 'request_uri' => $_SERVER['REQUEST_URI'], 71 | 'method' => $_SERVER['REQUEST_METHOD'], 72 | 'methods' => implode(', ', $methods) 73 | ]); 74 | }; 75 | }, 76 | 77 | 'errorHandler' => function($c) { 78 | return function($request, $response, $exception) use ($c) { 79 | $response = $response->withStatus(500); 80 | 81 | $data = [ 82 | 'exception' => null 83 | ]; 84 | 85 | if(env('APP_ENV') === "development") { 86 | $data['exception'] = $exception->getMessage(); 87 | } 88 | 89 | return $c->view->render($response, 'errors/500.twig', $data); 90 | }; 91 | }, 92 | 93 | 'csrf' => function($c) { 94 | $guard = new \Slim\Csrf\Guard; 95 | 96 | $guard->setFailureCallable(function($request, $response, $next) use ($c) { 97 | $request = $request->withAttribute("csrf_status", false); 98 | if($request->getAttribute('csrf_status') === false) { 99 | $c['flash']->addMessage('error', "CSRF verification failed, terminating your request."); 100 | 101 | return $response->withStatus(400)->withRedirect($c['router']->pathFor('home')); 102 | } else { 103 | return $next($request, $response); 104 | } 105 | }); 106 | 107 | return $guard; 108 | }, 109 | 110 | 'db' => function($c) { 111 | $capsule = new \Illuminate\Database\Capsule\Manager; 112 | 113 | $capsule->addConnection($c['config']->get('database'), 'default'); 114 | 115 | return $capsule; 116 | }, 117 | 118 | 'mail' => function($c) { 119 | $mailer = new \PHPMailer; 120 | 121 | $mailer->isSMTP(); 122 | $mailer->Host = $c['config']->get('mail.host'); 123 | $mailer->Port = $c['config']->get('mail.port'); 124 | $mailer->Username = $c['config']->get('mail.username'); 125 | $mailer->Password = $c['config']->get('mail.password'); 126 | $mailer->SMTPAuth = true; 127 | $mailer->SMTPSecure = false; 128 | $mailer->FromName = $c['config']->get('mail.from.name'); 129 | $mailer->From = $c['config']->get('mail.from'); 130 | 131 | $mailer->isHTML(true); 132 | 133 | return new \App\Mail\Mailer($mailer, $c); 134 | }, 135 | ]; 136 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "devsavage/slim-3-authentication", 3 | "description": "An authentication system using the Slim Framework.", 4 | "type": "project", 5 | "version": "2.0.0", 6 | "keywords": ["authentication","slim-3", "slim3", "slimframework", "slim-framework"], 7 | "homepage": "https://github.com/devsavage/slim-3-authentication", 8 | "license": "MIT", 9 | "authors": [ 10 | { 11 | "name": "Savage", 12 | "email": "savage@savagedev.io", 13 | "homepage": "https://savagedev.io", 14 | "role": "Developer" 15 | } 16 | ], 17 | "autoload": { 18 | "psr-4": { 19 | "App\\": "app/App", 20 | "Migration\\": "app/Migration" 21 | }, 22 | "files": [ 23 | "app/helpers.php", 24 | "phinx.php" 25 | ] 26 | }, 27 | 28 | "require": { 29 | "php": ">=5.6.0 ^7.2", 30 | "slim/slim": "^3.0", 31 | "illuminate/database": "^5.2", 32 | "illuminate/pagination": "^5.2", 33 | "slim/twig-view": "^2.0", 34 | "slim/flash": "^0.1.0", 35 | "slim/csrf": "^0.6.0", 36 | "ircmaxell/random-lib": "^1.1", 37 | "phpmailer/phpmailer": "^5.2", 38 | "vlucas/phpdotenv": "^3", 39 | "hassankhan/config": "^0.10.0", 40 | "symfony/console": "^3.1", 41 | "google/recaptcha": "~1.1", 42 | "robmorgan/phinx": "^0.10.7" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /config/app.php: -------------------------------------------------------------------------------- 1 | [ 4 | 'environment' => env('APP_ENV', 'development'), 5 | 'url' => env('APP_URL', 'http://127.0.0.1'), 6 | 'activation' => [ 7 | 'method' => env('APP_ACTIVATION_METHOD', 'mail'), 8 | ], 9 | 'auth_id' => env('APP_AUTH_ID', 'user_id'), 10 | 'remember_id' => env('APP_REMEMBER_ID', 'APP_REMEMBER_TOKEN'), 11 | ] 12 | ]; -------------------------------------------------------------------------------- /config/database.php: -------------------------------------------------------------------------------- 1 | [ 4 | 'driver' => env('DB_CONNECTION', 'mysql'), 5 | 'host' => env('DB_HOST', '127.0.0.1'), 6 | 'port' => env('DB_PORT', '3306'), 7 | 'username' => env('DB_USERNAME', 'root'), 8 | 'password' => env('DB_PASSWORD'), 9 | 'database' => env('DB_DATABASE', 'auth'), 10 | 'charset' => 'utf8', 11 | 'collation' => 'utf8_unicode_ci', 12 | ] 13 | ]; -------------------------------------------------------------------------------- /config/lang.php: -------------------------------------------------------------------------------- 1 | [ 4 | 'mail' => [ 5 | 'activation' => [ 6 | 'subject' => env("APP_NAME", "My App") . " Account Activation", 7 | ], 8 | 9 | 'password' => [ 10 | 'forgot' => [ 11 | 'subject' => env("APP_NAME", "My App") . " Password Reset Request", 12 | ] 13 | ], 14 | ], 15 | 16 | 'alerts' => [ 17 | 'requires_auth' => "You must be signed in to access that page.", 18 | 'recaptcha_failed' => "Please verify you are not a robot by completing the reCAPTCHA.", 19 | 'forgot_password_success' => "If your email is valid, you'll receive an email with instructions on how to reset your password.", 20 | 'forgot_password_failed' => "Please enter the e-mail address associated with your account.", 21 | 'reset_password_invalid' => "Your password reset token was invalid. Please submit another password reset request.", 22 | 'reset_password_failed' => "Your password could not be reset at this time.", 23 | 'reset_password_success' => "You have successfully reset your password. You can now login with your new password.", 24 | 'reset_password_no_email' => "Please verify your e-mail.", 25 | 'registration' => [ 26 | 'successful' => "Your account has been created!", 27 | 'error' => "Please fix any errors with your registration and try again.", 28 | 'requires_mail_activation' => "Your account has been created but you will need to activate it. Please check your e-mail for instructions.", 29 | ], 30 | 31 | 'login' => [ 32 | 'invalid' => "You have supplied invalid credentials.", 33 | 'error' => "Please enter your credentials to continue.", 34 | 'resend_activation' => "Another activation e-mail has been sent. Please check your e-mail for instructions.", 35 | ], 36 | 37 | 'account' => [ 38 | 'already_activated' => "Your account has already been activated.", 39 | 'activatied' => "Your account has been activated! You can now login.", 40 | 'invalid_active_hash' => "The active hash you are trying to use has already expired or never existed.", 41 | 42 | 'password' => [ 43 | 'updated' => "Your password has been changed.", 44 | 'failed' => "Your password couldn't be changed at this time.", 45 | ], 46 | 47 | 'profile' => [ 48 | 'updated' => "Your profile has been updated!", 49 | 'failed' => "Your profile couldn't be updated at this time.", 50 | ] 51 | ] 52 | ], 53 | 54 | 'admin' => [ 55 | 'user' => [ 56 | 'general' => [ 57 | 'user_not_found' => "User not found.", 58 | 'user_edit_from_settings' => "You cannot edit your profile from the Admin Dashboard!", 59 | 'cant_edit_user' => "You do not have permission to edit that user!", 60 | 'user_deleted' => "User has been deleted.", 61 | 'user_not_deleted' => "User was not deleted.", 62 | 'not_authorized' => "You are not authorized to complete that action!", 63 | ], 64 | 'revoke' => [ 65 | 'remember' => "User's remember credentials have been removed.", 66 | 'recovery' => "User's recover hash has been revoked.", 67 | ], 68 | 'update' => [ 69 | 'profile' => [ 70 | 'success' => "User profile updated!", 71 | 'fail' => "User profile cannot be updated!", 72 | ], 73 | 'settings' => [ 74 | 'active' => [ 75 | 'yes' => "User's account has been activated!", 76 | 'resend' => "User's account has been deactivated and another activation email has been sent.", 77 | 'no' => "User's account has been deactivated!", 78 | ] 79 | ], 80 | ] 81 | ], 82 | 'general' => [ 83 | 'created' => "Created successfully!", 84 | 'success' => "Updated successfully!", 85 | 'fail' => "There was an error while trying to process your request!", 86 | 'deleted' => "Item has been deleted.", 87 | 'not_deleted' => "Item was not deleted.", 88 | ], 89 | 'role' => [ 90 | 'general' => [ 91 | 'cant_edit' => "You do not have permission to edit that role!", 92 | 'cant_create' => "You do not have permission to create new roles!", 93 | 'deleted' => "Role has been deleted.", 94 | 'not_deleted' => "Role was not deleted.", 95 | 'not_authorized' => "You are not authorized to complete that action!", 96 | ], 97 | ] 98 | ], 99 | ] 100 | ]; 101 | -------------------------------------------------------------------------------- /config/mail.php: -------------------------------------------------------------------------------- 1 | [ 4 | 'host' => env('MAIL_HOST'), 5 | 'port' => env('MAIL_PORT'), 6 | 'username' => env('MAIL_USERNAME'), 7 | 'password' => env('MAIL_PASSWORD'), 8 | 'from.name' => env('MAIL_FROM_NAME', 'noreply'), 9 | 'from' => env('MAIL_FROM', 'noreply@example.com'), 10 | ] 11 | ]; -------------------------------------------------------------------------------- /config/plugins.php: -------------------------------------------------------------------------------- 1 | [ 4 | 'recaptcha' => [ 5 | 'public' => env('RECAPTCHA_PUBLIC'), 6 | 'secret' => env('RECAPTCHA_SECRET'), 7 | ] 8 | ] 9 | ]; -------------------------------------------------------------------------------- /database/migrations/20190527142257_permissions.php: -------------------------------------------------------------------------------- 1 | schema->create('permissions', function(Illuminate\Database\Schema\Blueprint $table){ 9 | // Auto-increment id 10 | $table->increments('id'); 11 | $table->string('name'); 12 | // Required for Eloquent's created_at and updated_at columns 13 | $table->timestamps(); 14 | }); 15 | } 16 | public function down() { 17 | $this->schema->drop('permissions'); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /database/migrations/20190527142308_roles.php: -------------------------------------------------------------------------------- 1 | schema->create('roles', function(Illuminate\Database\Schema\Blueprint $table){ 9 | // Auto-increment id 10 | $table->increments('id'); 11 | $table->string('title'); 12 | // Required for Eloquent's created_at and updated_at columns 13 | $table->timestamps(); 14 | }); 15 | } 16 | public function down() { 17 | $this->schema->drop('roles'); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /database/migrations/20190527142321_roles_permissions.php: -------------------------------------------------------------------------------- 1 | schema->create('roles_permissions', function(Illuminate\Database\Schema\Blueprint $table){ 9 | // Auto-increment id 10 | $table->increments('id'); 11 | $table->unsignedInteger('role_id'); 12 | $table->foreign('role_id')->references('id')->on('roles')->onDelete('cascade'); 13 | $table->unsignedInteger('permission_id'); 14 | $table->foreign('permission_id')->references('id')->on('permissions')->onDelete('cascade'); 15 | //$table->primary(['role_id','permission_id']); 16 | // Required for Eloquent's created_at and updated_at columns 17 | $table->timestamp('created_at')->useCurrent(); 18 | $table->timestamp('updated_at')->useCurrent(); 19 | }); 20 | } 21 | public function down() { 22 | $this->schema->drop('roles_permissions'); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /database/migrations/20190527142334_users.php: -------------------------------------------------------------------------------- 1 | schema->create('users', function(Illuminate\Database\Schema\Blueprint $table){ 9 | // Auto-increment id 10 | $table->increments('id'); 11 | $table->string('username')->unique()->nullable(); 12 | $table->string('email')->unique()->nullable(); 13 | $table->string('password')->nullable(); 14 | $table->boolean('active')->default(0); 15 | $table->string('active_hash')->nullable(); 16 | $table->string('remember_token')->nullable(); 17 | $table->string('remember_identifier')->nullable(); 18 | $table->string('recover_hash')->nullable(); 19 | // Required for Eloquent's created_at and updated_at columns 20 | $table->timestamps(); 21 | }); 22 | } 23 | public function down() { 24 | $this->schema->drop('users'); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /database/migrations/20190527142340_users_permissions.php: -------------------------------------------------------------------------------- 1 | schema->create('users_permissions', function(Illuminate\Database\Schema\Blueprint $table){ 9 | // Auto-increment id 10 | $table->unsignedInteger('user_id'); 11 | $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); 12 | $table->unsignedInteger('permission_id'); 13 | $table->foreign('permission_id')->references('id')->on('permissions')->onDelete('cascade'); 14 | // Required for Eloquent's created_at and updated_at columns 15 | $table->timestamps(); 16 | }); 17 | } 18 | public function down() { 19 | $this->schema->drop('users_permissions'); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /database/migrations/20190527142344_users_roles.php: -------------------------------------------------------------------------------- 1 | schema->create('users_roles', function(Illuminate\Database\Schema\Blueprint $table){ 9 | // Auto-increment id 10 | $table->increments('id'); 11 | $table->unsignedInteger('user_id'); 12 | $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); 13 | $table->unsignedInteger('role_id'); 14 | $table->foreign('role_id')->references('id')->on('roles')->onDelete('cascade'); 15 | // Required for Eloquent's created_at and updated_at columns 16 | $table->timestamps(); 17 | }); 18 | } 19 | public function down() { 20 | $this->schema->drop('users_roles'); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /database/seeds/PermissionSeeder.php: -------------------------------------------------------------------------------- 1 | 'delete users', 20 | 'created_at' => date('Y-m-d H:i:s'), 21 | 'updated_at' => date('Y-m-d H:i:s'), 22 | ], 23 | [ 24 | 'name' => 'manage roles', 25 | 'created_at' => date('Y-m-d H:i:s'), 26 | 'updated_at' => date('Y-m-d H:i:s'), 27 | ], 28 | [ 29 | 'name' => 'edit users', 30 | 'created_at' => date('Y-m-d H:i:s'), 31 | 'updated_at' => date('Y-m-d H:i:s'), 32 | ], 33 | [ 34 | 'name' => 'edit admins', 35 | 'created_at' => date('Y-m-d H:i:s'), 36 | 'updated_at' => date('Y-m-d H:i:s'), 37 | ], 38 | [ 39 | 'name' => 'view admin pages', 40 | 'created_at' => date('Y-m-d H:i:s'), 41 | 'updated_at' => date('Y-m-d H:i:s'), 42 | ], 43 | [ 44 | 'name' => 'make admin', 45 | 'created_at' => date('Y-m-d H:i:s'), 46 | 'updated_at' => date('Y-m-d H:i:s'), 47 | ] 48 | ]; 49 | 50 | $posts = $this->table('permissions'); 51 | $posts->insert($data) 52 | ->save(); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /database/seeds/RolePermissionSeeder.php: -------------------------------------------------------------------------------- 1 | '1', 28 | 'permission_id' => '1', 29 | 'created_at' => date('Y-m-d H:i:s'), 30 | 'updated_at' => date('Y-m-d H:i:s'), 31 | ], 32 | [ 33 | 'role_id' => '1', 34 | 'permission_id' => '3', 35 | 'created_at' => date('Y-m-d H:i:s'), 36 | 'updated_at' => date('Y-m-d H:i:s'), 37 | ], 38 | [ 39 | 'role_id' => '1', 40 | 'permission_id' => '5', 41 | 'created_at' => date('Y-m-d H:i:s'), 42 | 'updated_at' => date('Y-m-d H:i:s'), 43 | ], 44 | [ 45 | 'role_id' => '2', 46 | 'permission_id' => '1', 47 | 'created_at' => date('Y-m-d H:i:s'), 48 | 'updated_at' => date('Y-m-d H:i:s'), 49 | ], 50 | [ 51 | 'role_id' => '2', 52 | 'permission_id' => '2', 53 | 'created_at' => date('Y-m-d H:i:s'), 54 | 'updated_at' => date('Y-m-d H:i:s'), 55 | ], 56 | [ 57 | 'role_id' => '2', 58 | 'permission_id' => '3', 59 | 'created_at' => date('Y-m-d H:i:s'), 60 | 'updated_at' => date('Y-m-d H:i:s'), 61 | ], 62 | [ 63 | 'role_id' => '2', 64 | 'permission_id' => '4', 65 | 'created_at' => date('Y-m-d H:i:s'), 66 | 'updated_at' => date('Y-m-d H:i:s'), 67 | ], 68 | [ 69 | 'role_id' => '2', 70 | 'permission_id' => '5', 71 | 'created_at' => date('Y-m-d H:i:s'), 72 | 'updated_at' => date('Y-m-d H:i:s'), 73 | ], 74 | [ 75 | 'role_id' => '2', 76 | 'permission_id' => '6', 77 | 'created_at' => date('Y-m-d H:i:s'), 78 | 'updated_at' => date('Y-m-d H:i:s'), 79 | ] 80 | ]; 81 | 82 | $posts = $this->table('roles_permissions'); 83 | $posts->insert($data) 84 | ->save(); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /database/seeds/RoleSeeder.php: -------------------------------------------------------------------------------- 1 | 'admin', 20 | 'created_at' => date('Y-m-d H:i:s'), 21 | 'updated_at' => date('Y-m-d H:i:s'), 22 | ], 23 | [ 24 | 'title' => 'superadmin', 25 | 'created_at' => date('Y-m-d H:i:s'), 26 | 'updated_at' => date('Y-m-d H:i:s'), 27 | ] 28 | ]; 29 | 30 | $posts = $this->table('roles'); 31 | $posts->insert($data) 32 | ->save(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /forge: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | boot($kernel); 9 | 10 | $console->run(); 11 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | var elixir = require('laravel-elixir'); 2 | require('laravel-elixir-sass-compass'); 3 | require('laravel-elixir-webpack-official'); 4 | 5 | elixir.config.sourcemaps = false; 6 | 7 | elixir((mix) => { 8 | mix.copy('node_modules/jquery/dist/jquery.min.js','public/js/jquery.min.js'); 9 | 10 | mix.sass(['app.scss'], 'public/css/') 11 | .webpack('app.js', 'public/js/app.min.js'); 12 | }); 13 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "prod": "gulp --production", 5 | "dev": "gulp watch" 6 | }, 7 | "devDependencies": { 8 | "gulp": "^3.9.1", 9 | "jquery": "^3.1.0", 10 | "laravel-elixir": "^6.0.0-10", 11 | "laravel-elixir-sass-compass": "^0.5.0", 12 | "laravel-elixir-webpack-official": "^1.0.4", 13 | "lodash": "^4.16.2", 14 | "normalize.css": "^4.1.1", 15 | "bootstrap": "^4.0.0-alpha.6" 16 | }, 17 | "dependencies": { 18 | "font-awesome": "^4.7.0", 19 | "tether": "^1.3.7", 20 | "popper.js": "^1.14.0" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /phinx: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | run(); 29 | -------------------------------------------------------------------------------- /phinx.php: -------------------------------------------------------------------------------- 1 | [ 7 | 'migrations' => 'database/migrations', 8 | 'seeds' => 'database/seeds' 9 | ], 10 | 'templates' => [ 11 | 'file' => 'resources/phinx/Migration.template.php.dist' 12 | ], 13 | 'migration_base_class' => '\Migration\Migration', 14 | 'environments' => [ 15 | 'default_migration_table' => 'phinxlog', 16 | 'default_database' => 'development', 17 | 'development' => [ 18 | 'adapter' => env('DB_CONNECTION'), 19 | 'host' => env('DB_HOST'), 20 | 'name' => env('DB_DATABASE'), 21 | 'user' => env('DB_USERNAME'), 22 | 'pass' => env('DB_PASSWORD'), 23 | 'port' => env('DB_PORT') 24 | ], 25 | 'production' => [ 26 | 'adapter' => env('DB_CONNECTION'), 27 | 'host' => env('DB_HOST'), 28 | 'name' => env('DB_DATABASE'), 29 | 'user' => env('DB_USERNAME'), 30 | 'pass' => env('DB_PASSWORD'), 31 | 'port' => env('DB_PORT') 32 | ] 33 | ] 34 | ]; -------------------------------------------------------------------------------- /public/.htaccess: -------------------------------------------------------------------------------- 1 | RewriteEngine On 2 | RewriteCond %{REQUEST_FILENAME} !-f 3 | RewriteRule ^ index.php [QSA,L] 4 | -------------------------------------------------------------------------------- /public/index.php: -------------------------------------------------------------------------------- 1 | run(); 6 | -------------------------------------------------------------------------------- /resources/assets/js/app.js: -------------------------------------------------------------------------------- 1 | require('./bootstrap'); -------------------------------------------------------------------------------- /resources/assets/js/bootstrap.js: -------------------------------------------------------------------------------- 1 | window._ = require('lodash'); 2 | window.$ = window.jQuery = require('jquery'); 3 | window.Tether = require('tether'); 4 | 5 | require('bootstrap'); -------------------------------------------------------------------------------- /resources/assets/sass/app.scss: -------------------------------------------------------------------------------- 1 | @import url(https://fonts.googleapis.com/css?family=Lato:300,400,700); 2 | @import url(https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css); 3 | 4 | @import "../../../node_modules/normalize.css/normalize.css"; 5 | 6 | // Override bootstrap styling 7 | @import "components/bootstrap/custom"; 8 | @import "../../../node_modules/bootstrap/scss/bootstrap.scss"; 9 | 10 | @import "../../../node_modules/font-awesome/scss/font-awesome.scss"; 11 | 12 | @import "components/base"; -------------------------------------------------------------------------------- /resources/assets/sass/components/_base.scss: -------------------------------------------------------------------------------- 1 | html { 2 | position: relative; 3 | min-height: 100%; 4 | } 5 | 6 | body { 7 | padding-top: 75px; 8 | margin-bottom: 40px; 9 | } -------------------------------------------------------------------------------- /resources/assets/sass/components/bootstrap/_custom.scss: -------------------------------------------------------------------------------- 1 | $brand-primary: #4285F4 !default; 2 | $brand-success: #34A853 !default; 3 | $brand-info: #00A1F1 !default; 4 | $brand-warning: #FBBC05 !default; 5 | $brand-danger: #EA4335 !default; 6 | 7 | $state-success-bg: $brand-success; 8 | $state-success-text: #FFF; 9 | $state-info-bg: $brand-info; 10 | $state-info-text: #FFF; 11 | $state-warning-bg: $brand-warning; 12 | $state-warning-text: #FFF; 13 | $state-danger-bg: $brand-danger; 14 | $state-danger-text: #FFF; 15 | 16 | .btn { 17 | cursor: pointer !important; 18 | } -------------------------------------------------------------------------------- /resources/phinx/Migration.template.php.dist: -------------------------------------------------------------------------------- 1 | schema->create('TABLE_NAME_HERE', function(Illuminate\Database\Schema\Blueprint $table){ 9 | // Auto-increment id 10 | $table->increments('id'); 11 | // Required for Eloquent's created_at and updated_at columns 12 | $table->timestamps(); 13 | }); 14 | } 15 | 16 | public function down() { 17 | $this->schema->drop('TABLE_NAME_HERE'); 18 | } 19 | } -------------------------------------------------------------------------------- /resources/views/admin/home.twig: -------------------------------------------------------------------------------- 1 | {% extends 'admin/templates/admin.twig' %} 2 | {% set page = "adminHome" %} 3 | {% block content %} 4 |
{{ auth.user.username }}, welcome to the Admin Dashboard. Use the navigation bar above to find your way around.
5 | {% endblock %} 6 | -------------------------------------------------------------------------------- /resources/views/admin/permission/create.twig: -------------------------------------------------------------------------------- 1 | {% extends 'admin/templates/admin.twig' %} 2 | {% set page = "adminPermissionCreate" %} 3 | {% block content %} 4 |
5 |
6 |
7 |

8 | Create Permission 9 |

10 |
11 |
12 |
13 | 14 |
15 | 16 | {% if errors.has('name') %} 17 | 18 | {% endif %} 19 |
20 |
21 | {{ csrf.field | raw }} 22 |
23 |
24 |
25 | 26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | {% endblock %} -------------------------------------------------------------------------------- /resources/views/admin/permission/delete.twig: -------------------------------------------------------------------------------- 1 | {% extends 'admin/templates/admin.twig' %} 2 | {% block content %} 3 |
4 |

Are you sure you want to delete {{ permission.name}} permission?

5 |

Warning: This will delete all records tied to this permission and cannot be undone!

6 |
7 |
8 | {{ csrf.field | raw }} 9 | 10 | 11 |
12 |
13 | {% endblock %} -------------------------------------------------------------------------------- /resources/views/admin/permission/edit.twig: -------------------------------------------------------------------------------- 1 | {% extends 'admin/templates/admin.twig' %} 2 | {% set page = "adminPermissionEdit" %} 3 | {% block content %} 4 |
5 |
6 |
7 |
8 |

Edit Permission

9 |
10 | {% if auth.user.isSuperAdmin() or auth.user.can('delete permission') %} 11 | Delete Permission 12 | {% endif %} 13 |
14 |
15 |
16 |
17 |
18 | 19 |
20 | 21 | {% if errors.has('name') %} 22 | 23 | {% endif %} 24 |
25 |
26 | {{ csrf.field | raw }} 27 |
28 |
29 |
30 | 31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 | {% endblock %} -------------------------------------------------------------------------------- /resources/views/admin/permission/list.twig: -------------------------------------------------------------------------------- 1 | {% extends 'admin/templates/admin.twig' %} 2 | {% set page = "adminPermissionList" %} 3 | {% block content %} 4 | 5 |
6 |
7 |

Permission List

8 |
9 | {% if auth.user.isSuperAdmin() or auth.user.can('create permission') %} 10 | Create Permission 11 | {% endif %} 12 |
13 |
14 |
15 | {% if permissions is empty %} 16 |

No results found!

17 | {% else %} 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | {% for permission in permissions %} 28 | 29 | 30 | 31 | 44 | 45 | {% endfor %} 46 | 47 |
IDNameAction
{{ permission.id }}{{ permission.name }} 32 | {% if auth.user.isSuperAdmin() or auth.user.can('edit permission') %} 33 | 34 | {% else %} 35 | 36 | {% endif %} 37 | {% if not auth.user.isSuperAdmin() or not auth.user.can('edit permission') %} 38 | 39 | {% else %} 40 | 41 | {% endif %} 42 | 43 |
48 | {{ permissions.links|raw }} 49 | {% endif %} 50 |
51 |
52 | 53 | {% endblock %} -------------------------------------------------------------------------------- /resources/views/admin/role/create.twig: -------------------------------------------------------------------------------- 1 | {% extends 'admin/templates/admin.twig' %} 2 | {% set page = "adminRoleCreate" %} 3 | {% block content %} 4 |
5 |
6 |
7 |

8 | Create Role 9 |

10 |
11 |
12 |
13 | 14 |
15 | 16 | {% if errors.has('title') %} 17 | 18 | {% endif %} 19 |
20 |
21 |
22 | 23 |
24 | 29 | {% if errors.has('permissions') %} 30 | 31 | {% endif %} 32 |
33 |
34 | {{ csrf.field | raw }} 35 |
36 |
37 |
38 | 39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 | {% endblock %} -------------------------------------------------------------------------------- /resources/views/admin/role/delete.twig: -------------------------------------------------------------------------------- 1 | {% extends 'admin/templates/admin.twig' %} 2 | {% block content %} 3 |
4 |

Are you sure you want to delete {{ role.title}} role?

5 |

Warning: This will delete all records tied to this role and cannot be undone!

6 |
7 |
8 | {{ csrf.field | raw }} 9 | 10 | 11 |
12 |
13 | {% endblock %} -------------------------------------------------------------------------------- /resources/views/admin/role/edit.twig: -------------------------------------------------------------------------------- 1 | {% extends 'admin/templates/admin.twig' %} 2 | {% set page = "adminRoleEdit" %} 3 | {% block content %} 4 |
5 |
6 |
7 |
8 |

Edit Role

9 |
10 | {% if auth.user.isSuperAdmin() or auth.user.can('delete role') %} 11 | Delete Role 12 | {% endif %} 13 |
14 |
15 |
16 |
17 |
18 | 19 |
20 | 21 | {% if errors.has('title') %} 22 | 23 | {% endif %} 24 |
25 |
26 |
27 | 28 |
29 | 34 | {% if errors.has('permissions') %} 35 | 36 | {% endif %} 37 |
38 |
39 | {{ csrf.field | raw }} 40 |
41 |
42 |
43 | 44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 | {% endblock %} -------------------------------------------------------------------------------- /resources/views/admin/role/list.twig: -------------------------------------------------------------------------------- 1 | {% extends 'admin/templates/admin.twig' %} 2 | {% set page = "adminRoleList" %} 3 | {% block content %} 4 | 5 |
6 |
7 |

Role List

8 |
9 | {% if auth.user.isSuperAdmin() or auth.user.can('create role') %} 10 | Create Role 11 | {% endif %} 12 |
13 |
14 |
15 | {% if roles is empty %} 16 |

No results found!

17 | {% else %} 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | {% for role in roles %} 28 | 29 | 30 | 31 | 41 | 42 | {% endfor %} 43 | 44 |
IDNameAction
{{ role.id }}{{ role.title }} 32 | {% if auth.user.isSuperAdmin() or auth.user.can('edit role') %} 33 | 34 | 35 | {% else %} 36 | 37 | 38 | {% endif %} 39 | 40 |
45 | {{ roles.links|raw }} 46 | {% endif %} 47 |
48 |
49 | 50 | {% endblock %} 51 | -------------------------------------------------------------------------------- /resources/views/admin/templates/admin.twig: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | {% block styles %}{% endblock %} 10 | 11 | 14 | 15 | {{ title is defined ? title : getenv('APP_NAME', 'My App') }} 16 | 17 | 18 | {% include 'templates/partials/nav.twig'%} 19 | 20 |
21 |
22 |
23 | {% include 'templates/partials/alerts.twig'%} 24 |
25 |
26 |

Admin Dashboard

27 |
28 |
29 |
30 | {% include 'admin/templates/partials/_menu.twig' %} 31 |
32 |
33 | {% block content %}{% endblock %} 34 |
35 |
36 | 37 |
38 | 39 | 40 | {% block scripts %}{% endblock %} 41 | 42 | 43 | -------------------------------------------------------------------------------- /resources/views/admin/templates/partials/_menu.twig: -------------------------------------------------------------------------------- 1 |
2 | 3 |  Home 4 | 5 | 6 |  User List 7 | 8 | 9 |  Admin List 10 | 11 | 12 |  Role List 13 | 14 | 15 |  Permission List 16 | 17 |
-------------------------------------------------------------------------------- /resources/views/admin/user/adminlist.twig: -------------------------------------------------------------------------------- 1 | {% extends 'admin/templates/admin.twig' %} 2 | {% set page = "adminAdminList" %} 3 | {% block content %} 4 | 5 |
6 |
7 |

Admin List

8 |
9 |
10 | {% if users is empty %} 11 |

You don't have any registerd users.

12 | {% else %} 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | {% for user in users %} 25 | 26 | 27 | 28 | 29 | 32 | 45 | 46 | {% endfor %} 47 | 48 |
IDUsernameE-MailActiveAction
{{ user.id }}{{ user.username }}{{ user.email }} 30 | 31 | 33 | {% if auth.user.canEdit(user) %} 34 | 35 | {% else %} 36 | 37 | {% endif %} 38 | {% if not auth.user.canEdit(user) %} 39 | 40 | {% else %} 41 | 42 | {% endif %} 43 | 44 |
49 | {{ roles.users|raw }} 50 | {% endif %} 51 |
52 |
53 | 54 | {% endblock %} -------------------------------------------------------------------------------- /resources/views/admin/user/delete.twig: -------------------------------------------------------------------------------- 1 | {% extends 'admin/templates/admin.twig' %} 2 | {% block content %} 3 |
4 |

Are you sure you want to delete {{ user.username }}'s account?

5 |

Warning: This will delete all records tied to this account and cannot be undone!

6 |
7 |
8 | {{ csrf.field | raw }} 9 | 10 | 11 |
12 |
13 | {% endblock %} -------------------------------------------------------------------------------- /resources/views/admin/user/edit.twig: -------------------------------------------------------------------------------- 1 | {% extends 'admin/templates/admin.twig' %} 2 | {% set page = "adminUserEdit" %} 3 | {% block content %} 4 |
5 |
6 |
7 | {% if auth.user.can('make admin') %} 8 | {{ user.isAdmin() ? 'Remove Admin Privileges' : 'Give Admin Privileges'}} 9 | {% endif %} 10 | {% if auth.user.can('delete users') %} 11 | Delete Account 12 | {% endif %} 13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |

21 | Profile 22 |

23 |
24 |
25 |
26 | 27 |
28 | 29 | {% if errors.has('username') %} 30 | 31 | {% endif %} 32 |
33 |
34 |
35 | 36 |
37 | 38 | {% if errors.has('email') %} 39 | 40 | {% endif %} 41 |
42 |
43 | {{ csrf.field | raw }} 44 |
45 |
46 |
47 | 48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |

57 | Settings 58 |

59 |
60 |
61 |
62 | 63 |
64 | 71 |
72 |
73 |
74 | {{ csrf.field | raw }} 75 |
76 |
77 | 78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 | {% if auth.user.can('make admin') %} 86 |
87 | {{ csrf.field | raw }} 88 |
89 | {% endif %} 90 | {% endblock %} -------------------------------------------------------------------------------- /resources/views/admin/user/list.twig: -------------------------------------------------------------------------------- 1 | {% extends 'admin/templates/admin.twig' %} 2 | {% set page = "adminUserList" %} 3 | {% block content %} 4 | 5 |
6 |
7 |

User List

8 |
9 |
10 | {% if users is empty %} 11 |

You don't have any registerd users.

12 | {% else %} 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | {% for user in users %} 25 | 26 | 27 | 28 | 29 | 32 | 45 | 46 | {% endfor %} 47 | 48 |
IDUsernameE-MailActiveAction
{{ user.id }}{{ user.username }}{{ user.email }} 30 | 31 | 33 | {% if auth.user.canEdit(user) %} 34 | 35 | {% else %} 36 | 37 | {% endif %} 38 | {% if not auth.user.canEdit(user) %} 39 | 40 | {% else %} 41 | 42 | {% endif %} 43 | 44 |
49 | {{ users.links|raw }} 50 | {% endif %} 51 |
52 |
53 | 54 | {% endblock %} -------------------------------------------------------------------------------- /resources/views/auth/account/settings.twig: -------------------------------------------------------------------------------- 1 | {% extends 'templates/app.twig' %} 2 | 3 | {% block content %} 4 |
5 |

Settings

6 |
7 |
8 |
9 |
10 |

Profile

11 |
12 |
13 |
14 | 15 |
16 |

{{ auth.user.username }}

17 |
18 |
19 |
20 | 21 |
22 | 23 | {% if errors.has('email') %} 24 | 25 | {% endif %} 26 |
27 |
28 | {{ csrf.field | raw }} 29 |
30 | 31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |

Password

39 |
40 |
41 |
42 | 43 | 44 | {% if errors.has('current_password') %} 45 | 46 | {% endif %} 47 |
48 |
49 | 50 | 51 | {% if errors.has('new_password') %} 52 | 53 | {% endif %} 54 |
55 |
56 | 57 | 58 | {% if errors.has('confirm_new_password') %} 59 | 60 | {% endif %} 61 |
62 | {{ csrf.field | raw }} 63 |
64 | 65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 | {% endblock %} 73 | -------------------------------------------------------------------------------- /resources/views/auth/login.twig: -------------------------------------------------------------------------------- 1 | {% extends 'templates/app.twig' %} 2 | {% set page = "login" %} 3 | {% block content %} 4 |
5 |
6 |

Login

7 |
8 |
9 |
10 | 11 |
12 | 13 | {% if errors.has('username') %} 14 | 15 | {% endif %} 16 |
17 |
18 |
19 | 20 |
21 | 22 | {% if errors.has('password') %} 23 | 24 | {% endif %} 25 |
26 |
27 | 28 |
29 |
30 |
31 | 35 |
36 |
37 |
38 |
39 | Forgot password? 40 |
41 |
42 |
43 | 44 | {{ csrf.field | raw }} 45 | 46 |
47 | 48 |
49 |
50 |
51 | 54 |
55 |
56 | 57 | {% endblock %} 58 | -------------------------------------------------------------------------------- /resources/views/auth/password/forgot.twig: -------------------------------------------------------------------------------- 1 | {% extends 'templates/app.twig' %} 2 | 3 | {% block content %} 4 |
5 |
6 |
7 |
8 | Forgot Your Password 9 |
10 |
11 |
12 |
13 | 14 |
15 | 16 |
17 |
18 |
19 | 20 |
21 |
22 |
23 |
24 | {{ csrf.field | raw }} 25 |
26 |
27 | 28 |
29 |
30 |
31 |
32 |
33 |
34 | {% endblock %} 35 | {% block scripts %} 36 | 37 | {% endblock %} 38 | -------------------------------------------------------------------------------- /resources/views/auth/password/reset.twig: -------------------------------------------------------------------------------- 1 | {% extends 'templates/app.twig' %} 2 | 3 | {% block content %} 4 |
5 |
6 |
7 |
8 | Reset Your Password 9 |
10 |
11 |
12 |
13 | 14 |
15 | 16 | Please verify your e-mail address. 17 |
18 |
19 |
20 | 21 |
22 | 23 | {% if errors.has('new_password') %} 24 | 25 | {% endif %} 26 |
27 |
28 |
29 | 30 |
31 | 32 | {% if errors.has('confirm_new_password') %} 33 | 34 | {% endif %} 35 |
36 |
37 | {{ csrf.field | raw }} 38 |
39 |
40 | 41 |
42 |
43 |
44 |
45 |
46 |
47 | {% endblock %} 48 | -------------------------------------------------------------------------------- /resources/views/auth/register.twig: -------------------------------------------------------------------------------- 1 | {% extends 'templates/app.twig' %} 2 | {% set page = "register" %} 3 | {% block content %} 4 |
5 |
6 |

Register

7 |
8 |
9 |
10 | 11 |
12 | 13 | {% if errors.has('username') %} 14 | 15 | {% endif %} 16 |
17 |
18 |
19 | 20 |
21 | 22 | {% if errors.has('email') %} 23 | 24 | {% endif %} 25 |
26 |
27 |
28 | 29 |
30 | 31 | {% if errors.has('password') %} 32 | 33 | {% endif %} 34 |
35 |
36 |
37 | 38 |
39 | 40 | {% if errors.has('confirm_password') %} 41 | 42 | {% endif %} 43 |
44 |
45 | {% if getenv('APP_ACTIVATION_METHOD') == 'recaptcha' %} 46 |
47 | 48 |
49 |
50 |
51 |
52 | {% endif %} 53 | {{ csrf.field | raw }} 54 |
55 | 56 |
57 |
58 |
59 | 62 |
63 |
64 | 65 | {% endblock %} 66 | {% block scripts %} 67 | {% if getenv('APP_ACTIVATION_METHOD') == 'recaptcha' %} 68 | 69 | {% endif %} 70 | {% endblock %} 71 | -------------------------------------------------------------------------------- /resources/views/errors/404.twig: -------------------------------------------------------------------------------- 1 | {% extends 'templates/app.twig' %} 2 | {% set title = "Error 404 (Not Found)" %} 3 | {% block content %} 4 |
5 |

404. That's an error.

6 |
7 |
The requested URL {{ request_uri }} was not found on this server.
8 |
9 |

That's all we know.

10 |
11 | {% endblock %} 12 | -------------------------------------------------------------------------------- /resources/views/errors/405.twig: -------------------------------------------------------------------------------- 1 | {% extends 'templates/app.twig' %} 2 | {% set title = "Error 405 (Method Not Allowed)" %} 3 | {% block content %} 4 |
5 |

405. That's an error.

6 |
7 |
Your requested method ({{ method }}) is not allowed for {{ request_uri }}.
8 |
9 |

Acceptable Methods: {{ methods }}

10 |
11 | {% endblock %} 12 | -------------------------------------------------------------------------------- /resources/views/errors/500.twig: -------------------------------------------------------------------------------- 1 | {% extends 'templates/app.twig' %} 2 | {% set title = "Error 500 (Internal Server Error)" %} 3 | {% block content %} 4 |
5 |

500. That's a (bad) error.

6 |
7 |
Sorry, but the server could not handle your request at this time.
You can try refreshing or try your request again later.
8 |
9 | {% if exception %} 10 |
Exception: {{ exception }}
11 |
12 | {% endif %} 13 |

Sorry about that.

14 |
15 | {% endblock %} 16 | -------------------------------------------------------------------------------- /resources/views/home.twig: -------------------------------------------------------------------------------- 1 | {% extends 'templates/app.twig' %} 2 | {% set page = "home" %} 3 | {% block content %} 4 |

Welcome home{{ auth.check ? ", " ~ auth.user.username ~ "!" : "." }}

5 | {% if auth.check and auth.user.isAdmin() or auth.user.isSuperAdmin() %} 6 |
7 |
8 |

You are an admin!

9 |
10 | {% endif %} 11 | {% endblock %} 12 | -------------------------------------------------------------------------------- /resources/views/mail/auth/activate.twig: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 15 | 16 | 17 | 18 | 19 | 20 | 103 | 104 |
21 | 22 | 23 | 28 | 29 | 30 | 31 | 84 | 85 | 86 | 87 | 100 | 101 |
24 | 25 | {{ getenv('APP_NAME') }} 26 | 27 |
32 | 33 | 34 | 81 | 82 |
35 |

36 | Hello, {{ data.user.username }}! 37 |

38 | 39 |

40 | Click the button below to activate your account: 41 |

42 | 43 | 44 | 45 | 56 | 57 |
46 | 47 | 53 | Activate My Account 54 | 55 |
58 | 59 | 60 |

61 | Regards,
{{ getenv('APP_NAME') }} 62 |

63 | 64 | 65 | 66 | 78 | 79 |
67 |

68 | If you're having trouble clicking the "Activate Account" button, 69 | copy and paste the URL below into your web browser: 70 |

71 | 72 |

73 | 74 | {{ getenv('APP_URL') }}/auth/activate?identifier={{ data.hash }} 75 | 76 |

77 |
80 |
83 |
88 | 89 | 90 | 97 | 98 |
91 |

92 | © {{ "now"|date("Y") }} 93 | {{ getenv('APP_NAME') }}. 94 | All rights reserved. 95 |

96 |
99 |
102 |
105 | 106 | 107 | -------------------------------------------------------------------------------- /resources/views/mail/password/forgot.twig: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 15 | 16 | 17 | 18 | 19 | 20 | 98 | 99 |
21 | 22 | 23 | 28 | 29 | 30 | 31 | 80 | 81 | 82 | 95 | 96 |
24 | 25 | {{ getenv('APP_NAME') }} 26 | 27 |
32 | 33 | 34 | 77 | 78 |

35 | Hello, {{ data.user.username }}! 36 |

37 |

38 | You are receiving this email because we received a password reset request for your account. Click the button below to reset your password: 39 |

40 | 41 | 42 | 52 | 53 |
43 | 49 | Reset Password 50 | 51 |
54 |

55 | If you did not request a password reset, no further action is required. 56 |

57 | 58 |

59 | Regards,
{{ getenv('APP_NAME') }} 60 |

61 | 62 | 63 | 74 | 75 |
64 |

65 | If you're having trouble clicking the "Reset Password" button, 66 | copy and paste the URL below into your web browser: 67 |

68 |

69 | 70 | {{ getenv('APP_URL') }}/auth/password/reset?identifier={{ data.identifier }} 71 | 72 |

73 |
76 |
79 |
83 | 84 | 85 | 92 | 93 |
86 |

87 | © {{ "now"|date("Y") }} 88 | {{ getenv('APP_NAME') }}. 89 | All rights reserved. 90 |

91 |
94 |
97 |
100 | 101 | 102 | -------------------------------------------------------------------------------- /resources/views/pagination.twig: -------------------------------------------------------------------------------- 1 | {% if paginator.hasPages() %} 2 | 17 | {% endif %} -------------------------------------------------------------------------------- /resources/views/templates/app.twig: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | {% block styles %}{% endblock %} 10 | 11 | 14 | 15 | {{ title is defined ? title : getenv('APP_NAME', 'My App') }} 16 | 17 | 18 | {% include 'templates/partials/nav.twig'%} 19 | 20 |
21 |
22 |
23 | {% include 'templates/partials/alerts.twig'%} 24 |
25 |
26 | {% block content %}{% endblock %} 27 |
28 | 29 | 30 | {% block scripts %}{% endblock %} 31 | 32 | 33 | -------------------------------------------------------------------------------- /resources/views/templates/partials/alerts.twig: -------------------------------------------------------------------------------- 1 | {% if flash.getMessage('success').0 %} 2 | 11 | {% endif %} 12 | 13 | {% if flash.getMessage('info').0 %} 14 | 23 | {% endif %} 24 | 25 | {% if flash.getMessage('warning').0 %} 26 | 35 | {% endif %} 36 | 37 | {% if flash.getMessage('error').0 %} 38 | 47 | {% endif %} 48 | 49 | {% if flash.getMessage('raw_error').0 %} 50 | 59 | {% endif %} 60 | 61 | {% if flash.getMessage('raw_warning').0 %} 62 | 71 | {% endif %} 72 | 73 | {% if flash.getMessage('raw_success').0 %} 74 | 83 | {% endif %} -------------------------------------------------------------------------------- /resources/views/templates/partials/nav.twig: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /routes/admin.php: -------------------------------------------------------------------------------- 1 | group('/admin', function() { 4 | $this->route(['GET'], '[/]', App\Http\Controllers\Admin\AdminController::class)->setName('admin.home'); 5 | 6 | //USERS 7 | $this->route(['GET'], '/users[/]', App\Http\Controllers\Admin\AdminUserController::class)->setName('admin.users.list'); 8 | $this->route(['GET'], '/admins[/]', App\Http\Controllers\Admin\AdminUserController::class, 'admins')->setName('admin.admins.list'); 9 | $this->route(['GET'], '/users/{userId}/edit[/]', App\Http\Controllers\Admin\AdminUserController::class, 'edit')->setName('admin.users.edit'); 10 | $this->route(['GET', 'POST'], '/users/{userId}/delete[/]', App\Http\Controllers\Admin\AdminUserController::class, 'delete')->setName('admin.users.delete'); 11 | $this->route(['GET', 'POST'], '/users/{userId}/edit/profile', App\Http\Controllers\Admin\AdminUserController::class, 'editProfile')->setName('admin.users.edit.profile'); 12 | $this->route(['GET', 'POST'], '/users/{userId}/edit/settings', App\Http\Controllers\Admin\AdminUserController::class, 'editSettings')->setName('admin.users.edit.settings'); 13 | $this->route(['POST'], '/users/{userId}/update/role/{role}/{action}', App\Http\Controllers\Admin\AdminUserController::class, 'updateRole')->setName('admin.users.update.role'); 14 | 15 | //ROLES 16 | $this->route(['GET'], '/roles[/]', App\Http\Controllers\Admin\AdminRoleController::class)->setName('admin.roles.list'); 17 | $this->route(['GET','POST'], '/roles/{roleId}/edit[/]', App\Http\Controllers\Admin\AdminRoleController::class, 'edit')->setName('admin.roles.edit'); 18 | $this->route(['GET','POST'], '/roles/create[/]', App\Http\Controllers\Admin\AdminRoleController::class, 'create')->setName('admin.roles.create'); 19 | $this->route(['GET', 'POST'], '/roles/{roleId}/delete[/]', App\Http\Controllers\Admin\AdminRoleController::class, 'delete')->setName('admin.roles.delete'); 20 | 21 | //PERMISSIONS 22 | $this->route(['GET'], '/permissions[/]', App\Http\Controllers\Admin\AdminPermissionController::class)->setName('admin.permissions.list'); 23 | $this->route(['GET','POST'], '/permissions/{permissionId}/edit[/]', App\Http\Controllers\Admin\AdminPermissionController::class, 'edit')->setName('admin.permissions.edit'); 24 | $this->route(['GET','POST'], '/permissions/create[/]', App\Http\Controllers\Admin\AdminPermissionController::class, 'create')->setName('admin.permissions.create'); 25 | $this->route(['GET', 'POST'], '/permissions/{permissionId}/delete[/]', App\Http\Controllers\Admin\AdminPermissionController::class, 'delete')->setName('admin.permissions.delete'); 26 | 27 | })->add(new App\Http\Middleware\AdminMiddleware($app->getContainer())); -------------------------------------------------------------------------------- /routes/web.php: -------------------------------------------------------------------------------- 1 | route(['GET'], '/', App\Http\Controllers\HomeController::class)->setName('home'); 4 | 5 | $app->group('/auth', function() { 6 | $this->route(['GET', 'POST'], '/login', App\Http\Controllers\Auth\LoginController::class) 7 | ->add(new App\Http\Middleware\GuestMiddleware($this->getContainer())) 8 | ->add(new App\Http\Middleware\RequiresSecureRequestMiddleware($this->getContainer())) 9 | ->setName('auth.login'); 10 | 11 | $this->route(['GET', 'POST'], '/register', App\Http\Controllers\Auth\RegisterController::class) 12 | ->add(new App\Http\Middleware\GuestMiddleware($this->getContainer())) 13 | ->add(new App\Http\Middleware\RequiresSecureRequestMiddleware($this->getContainer())) 14 | ->setName('auth.register'); 15 | 16 | $this->route(['GET'], '/settings', App\Http\Controllers\Auth\SettingsController::class) 17 | ->add(new App\Http\Middleware\AuthMiddleware($this->getContainer())) 18 | ->add(new App\Http\Middleware\RequiresSecureRequestMiddleware($this->getContainer())) 19 | ->setName('auth.settings'); 20 | 21 | $this->route(['GET', 'POST'], '/settings/profile', App\Http\Controllers\Auth\SettingsController::class, 'profile') 22 | ->add(new App\Http\Middleware\AuthMiddleware($this->getContainer())) 23 | ->add(new App\Http\Middleware\RequiresSecureRequestMiddleware($this->getContainer())) 24 | ->setName('auth.settings.profile'); 25 | 26 | $this->route(['GET', 'POST'], '/settings/password', App\Http\Controllers\Auth\SettingsController::class, 'password') 27 | ->add(new App\Http\Middleware\AuthMiddleware($this->getContainer())) 28 | ->add(new App\Http\Middleware\RequiresSecureRequestMiddleware($this->getContainer())) 29 | ->setName('auth.settings.password'); 30 | 31 | $this->route(['GET'], '/activate', App\Http\Controllers\Auth\ActivationController::class)->setName('auth.activate'); 32 | 33 | $this->route(['GET'], '/activate/resend', App\Http\Controllers\Auth\ActivationController::class, 'resend')->setName('auth.activate.resend'); 34 | 35 | $this->route(['GET', 'POST'], '/password/forgot', App\Http\Controllers\Auth\PasswordResetController::class, 'forgot') 36 | ->add(new App\Http\Middleware\RequiresSecureRequestMiddleware($this->getContainer())) 37 | ->add(new App\Http\Middleware\GuestMiddleware($this->getContainer())) 38 | ->setName('auth.password.forgot'); 39 | 40 | $this->route(['GET', 'POST'], '/password/reset', App\Http\Controllers\Auth\PasswordResetController::class, 'reset') 41 | ->add(new App\Http\Middleware\GuestMiddleware($this->getContainer())) 42 | ->add(new App\Http\Middleware\RequiresSecureRequestMiddleware($this->getContainer())) 43 | ->setName('auth.password.reset'); 44 | }); 45 | 46 | $app->get('/auth/logout', function($request, $response, $args) { 47 | if(App\Lib\Cookie::exists(env('APP_REMEMBER_ID', 'APP_REMEMBER_TOKEN'))) { 48 | $this['auth']->user()->removeRememberCredentials(); 49 | App\Lib\Cookie::destroy(env('APP_REMEMBER_ID', 'APP_REMEMBER_TOKEN')); 50 | } 51 | 52 | App\Lib\Session::destroy(env('APP_AUTH_ID', 'user_id')); 53 | 54 | return $response->withRedirect($this['router']->pathFor('home')); 55 | })->add(new App\Http\Middleware\AuthMiddleware($app->getContainer()))->setName('auth.logout'); 56 | --------------------------------------------------------------------------------