├── .babelrc
├── .editorconfig
├── .env.example
├── .eslintignore
├── .eslintrc.js
├── .gitattributes
├── .gitignore
├── .php_cs
├── LICENSE.md
├── app
├── Domains
│ ├── Audits
│ │ ├── Audit.php
│ │ ├── Database
│ │ │ └── Migrations
│ │ │ │ └── CreateAuditsTable.php
│ │ └── Providers
│ │ │ └── DomainServiceProvider.php
│ ├── Jobs
│ │ ├── Database
│ │ │ └── Migrations
│ │ │ │ ├── CreateFailedJobsTable.php
│ │ │ │ └── CreateJobsTable.php
│ │ ├── FailedJob.php
│ │ ├── Job.php
│ │ └── Providers
│ │ │ └── DomainServiceProvider.php
│ ├── Model.php
│ ├── UserModel.php
│ └── Users
│ │ ├── Contracts
│ │ └── UserRepository.php
│ │ ├── Database
│ │ ├── Factories
│ │ │ └── UserFactory.php
│ │ ├── Migrations
│ │ │ ├── CreatePasswordResetsTable.php
│ │ │ └── CreateUsersTable.php
│ │ └── Seeders
│ │ │ └── UserSeeder.php
│ │ ├── Jobs
│ │ └── TwoFactorJob.php
│ │ ├── Notifications
│ │ └── TwoFactorNotification.php
│ │ ├── Presenters
│ │ └── UserPresenter.php
│ │ ├── Providers
│ │ └── DomainServiceProvider.php
│ │ ├── Queries
│ │ └── UserQueryFilter.php
│ │ ├── Repositories
│ │ └── UserRepository.php
│ │ ├── Resources
│ │ └── Rules
│ │ │ └── UserRules.php
│ │ ├── Transformers
│ │ ├── AuthTransformer.php
│ │ └── UserTransformer.php
│ │ └── User.php
├── Support
│ ├── Console
│ │ └── Routing
│ │ │ └── RouteFile.php
│ ├── Domain
│ │ ├── Database
│ │ │ ├── Migration.php
│ │ │ └── ModelFactory.php
│ │ ├── Fractal
│ │ │ └── Manager.php
│ │ ├── Providers
│ │ │ └── FakerServiceProvider.php
│ │ ├── Repositories
│ │ │ ├── Contracts
│ │ │ │ └── Repository.php
│ │ │ ├── Fractal
│ │ │ │ ├── DataArraySerializer.php
│ │ │ │ └── Transformer.php
│ │ │ ├── Repository.php
│ │ │ └── UserRepository.php
│ │ └── ServiceProvider.php
│ ├── Exception
│ │ ├── Handler.php
│ │ ├── QueryFilterUndefinedException.php
│ │ └── UpdateFailedException.php
│ ├── Hash
│ │ ├── ID.php
│ │ ├── IDServiceProvider.php
│ │ └── functions.php
│ ├── Helpers
│ │ ├── HelperServiceProvider.php
│ │ ├── UUID.php
│ │ └── functions.php
│ ├── Http
│ │ ├── Controller.php
│ │ ├── CrudController.php
│ │ ├── Exceptions
│ │ │ └── ValidationException.php
│ │ ├── Request.php
│ │ ├── Respond.php
│ │ ├── Routing
│ │ │ └── RouteFile.php
│ │ └── ServiceProvider.php
│ ├── Notifications
│ │ └── ResetPassword.php
│ ├── Queries
│ │ └── BaseQueryBuilder.php
│ ├── Shield
│ │ ├── Contracts
│ │ │ └── Rules.php
│ │ ├── Exceptions
│ │ │ └── UndefinedRules.php
│ │ ├── HasRules.php
│ │ └── Rules.php
│ ├── Units
│ │ └── ServiceProvider.php
│ ├── Validators
│ │ ├── CustomValidatorServiceProvider.php
│ │ └── Validator.php
│ └── ViewPresenter
│ │ ├── Presentable.php
│ │ ├── Presenter.php
│ │ └── PresenterException.php
└── Units
│ ├── Admin
│ ├── Providers
│ │ └── UnitServiceProvider.php
│ └── Users
│ │ ├── Http
│ │ ├── Controllers
│ │ │ └── UserController.php
│ │ └── Requests
│ │ │ └── Users
│ │ │ ├── CreateUserRequest.php
│ │ │ └── UpdateUserRequest.php
│ │ ├── Providers
│ │ ├── RouteServiceProvider.php
│ │ └── UnitServiceProvider.php
│ │ └── Routes
│ │ └── Api.php
│ ├── Auth
│ ├── Http
│ │ └── Controllers
│ │ │ ├── ForgotPasswordController.php
│ │ │ ├── LoginController.php
│ │ │ ├── RegisterController.php
│ │ │ ├── ResetPasswordController.php
│ │ │ └── TwoFactorController.php
│ ├── Providers
│ │ ├── AuthServiceProvider.php
│ │ ├── RouteServiceProvider.php
│ │ └── UnitServiceProvider.php
│ ├── Resources
│ │ └── Views
│ │ │ └── email
│ │ │ ├── recover_password.blade.php
│ │ │ └── two_factor.blade.php
│ └── Routes
│ │ ├── Api.php
│ │ ├── Api2Factor.php
│ │ └── ApiAuth.php
│ ├── ConsoleKernel.php
│ ├── Core
│ ├── Http
│ │ ├── Controllers
│ │ │ └── WelcomeController.php
│ │ └── Middleware
│ │ │ ├── Admin.php
│ │ │ ├── EncryptCookies.php
│ │ │ ├── RedirectIfAuthenticated.php
│ │ │ ├── TrimStrings.php
│ │ │ ├── TrustProxies.php
│ │ │ ├── TwoFactorVerify.php
│ │ │ └── VerifyCsrfToken.php
│ ├── Providers
│ │ ├── RouteServiceProvider.php
│ │ └── UnitServiceProvider.php
│ ├── Resources
│ │ └── Views
│ │ │ └── welcome.blade.php
│ └── Routes
│ │ ├── Console.php
│ │ └── Web.php
│ ├── ExceptionHandler.php
│ ├── HttpKernel.php
│ └── User
│ ├── Providers
│ └── UnitServiceProvider.php
│ └── Users
│ ├── Http
│ ├── Controllers
│ │ └── ProfileController.php
│ └── Requests
│ │ └── UpdateUserRequest.php
│ ├── Providers
│ ├── RouteServiceProvider.php
│ └── UnitServiceProvider.php
│ └── Routes
│ └── Api.php
├── artisan
├── bootstrap
├── app.php
└── cache
│ └── .gitignore
├── composer.json
├── composer.lock
├── config
├── app.php
├── audit.php
├── auth.php
├── broadcasting.php
├── cache.php
├── database.php
├── filesystems.php
├── fractal.php
├── hashing.php
├── jwt.php
├── logging.php
├── mail.php
├── queue.php
├── services.php
├── session.php
└── view.php
├── docker-compose.override-dist.yml
├── docker-compose.yml
├── package-lock.json
├── package.json
├── phpunit.xml
├── public
├── .htaccess
├── favicon.ico
├── fonts
│ └── roboto
│ │ ├── Roboto-Bold.woff
│ │ ├── Roboto-Bold.woff2
│ │ ├── Roboto-Light.woff
│ │ ├── Roboto-Light.woff2
│ │ ├── Roboto-Medium.woff
│ │ ├── Roboto-Medium.woff2
│ │ ├── Roboto-Regular.woff
│ │ ├── Roboto-Regular.woff2
│ │ ├── Roboto-Thin.woff
│ │ └── Roboto-Thin.woff2
├── index.php
├── mix-manifest.json
└── robots.txt
├── readme.md
├── resources
├── assets
│ ├── copy
│ │ └── js
│ │ │ └── izitoast
│ │ │ ├── LICENSE
│ │ │ ├── README.md
│ │ │ ├── bower.json
│ │ │ ├── dist
│ │ │ ├── css
│ │ │ │ ├── iziToast.css
│ │ │ │ └── iziToast.min.css
│ │ │ └── js
│ │ │ │ ├── iziToast.js
│ │ │ │ └── iziToast.min.js
│ │ │ ├── package.json
│ │ │ └── src
│ │ │ └── css
│ │ │ ├── animations.styl
│ │ │ ├── layouts.styl
│ │ │ ├── style.styl
│ │ │ ├── themes.styl
│ │ │ └── toast.styl
│ ├── js
│ │ ├── app
│ │ │ ├── auth
│ │ │ │ ├── index.js
│ │ │ │ ├── login
│ │ │ │ │ ├── login.vue
│ │ │ │ │ └── two-factor.vue
│ │ │ │ ├── register
│ │ │ │ │ └── register.vue
│ │ │ │ ├── reset
│ │ │ │ │ ├── email.vue
│ │ │ │ │ └── password.vue
│ │ │ │ ├── routes.js
│ │ │ │ └── store.js
│ │ │ ├── home
│ │ │ │ ├── index.js
│ │ │ │ ├── index
│ │ │ │ │ └── index.vue
│ │ │ │ ├── routes.js
│ │ │ │ ├── store.js
│ │ │ │ └── store
│ │ │ │ │ ├── actions.js
│ │ │ │ │ ├── getters.js
│ │ │ │ │ ├── index.js
│ │ │ │ │ ├── mutations.js
│ │ │ │ │ └── state.js
│ │ │ ├── index.js
│ │ │ ├── perfil
│ │ │ │ ├── index.js
│ │ │ │ ├── me.vue
│ │ │ │ ├── routes.js
│ │ │ │ └── store.js
│ │ │ ├── routes.js
│ │ │ ├── store.js
│ │ │ └── users
│ │ │ │ ├── form
│ │ │ │ ├── form.vue
│ │ │ │ └── user.vue
│ │ │ │ ├── helpers
│ │ │ │ └── index.js
│ │ │ │ ├── index.js
│ │ │ │ ├── index
│ │ │ │ ├── index.vue
│ │ │ │ └── search.vue
│ │ │ │ ├── routes.js
│ │ │ │ ├── services
│ │ │ │ ├── index.js
│ │ │ │ └── sort.js
│ │ │ │ └── store
│ │ │ │ ├── actions.js
│ │ │ │ ├── getters.js
│ │ │ │ ├── index.js
│ │ │ │ ├── mutations.js
│ │ │ │ └── state.js
│ │ ├── bootstrap.js
│ │ ├── components
│ │ │ ├── Helpers
│ │ │ │ └── error.vue
│ │ │ ├── MaskTextField
│ │ │ │ └── MaskTextField.vue
│ │ │ ├── alerts
│ │ │ │ └── alerts.vue
│ │ │ ├── contacts
│ │ │ │ └── contacts.vue
│ │ │ ├── countdown
│ │ │ │ └── countdown.vue
│ │ │ ├── form
│ │ │ │ ├── index.js
│ │ │ │ └── text.vue
│ │ │ ├── index.js
│ │ │ ├── masked
│ │ │ │ ├── date
│ │ │ │ │ └── date.vue
│ │ │ │ ├── document
│ │ │ │ │ ├── document-cnpj.vue
│ │ │ │ │ └── document-cpf.vue
│ │ │ │ ├── index.js
│ │ │ │ ├── number
│ │ │ │ │ └── number.vue
│ │ │ │ ├── phone
│ │ │ │ │ ├── landline.vue
│ │ │ │ │ ├── mobile.vue
│ │ │ │ │ └── phone.vue
│ │ │ │ └── zip
│ │ │ │ │ └── zip.vue
│ │ │ └── page
│ │ │ │ └── page.vue
│ │ ├── directives
│ │ │ ├── helpers.js
│ │ │ ├── index.js
│ │ │ └── visible.js
│ │ ├── eventBus.js
│ │ ├── filters
│ │ │ ├── countryRegister.js
│ │ │ ├── get.js
│ │ │ ├── index.js
│ │ │ ├── phone.js
│ │ │ └── showDate.js
│ │ ├── helpers
│ │ │ ├── clean.js
│ │ │ ├── dates.js
│ │ │ ├── format.js
│ │ │ ├── isMobile.js
│ │ │ ├── jwt
│ │ │ │ ├── parser.js
│ │ │ │ ├── storage.js
│ │ │ │ └── utils.js
│ │ │ ├── routes.js
│ │ │ ├── sessionStorage.js
│ │ │ ├── storage.js
│ │ │ └── text
│ │ │ │ ├── index.js
│ │ │ │ └── match.js
│ │ ├── layout
│ │ │ ├── app.vue
│ │ │ ├── header
│ │ │ │ ├── header.vue
│ │ │ │ ├── menu-left.vue
│ │ │ │ └── menu-right.vue
│ │ │ └── main.vue
│ │ ├── main.js
│ │ ├── main_render.js
│ │ ├── plugins
│ │ │ ├── http
│ │ │ │ ├── baseURL.js
│ │ │ │ ├── index.js
│ │ │ │ ├── interceptors
│ │ │ │ │ ├── expired_token.js
│ │ │ │ │ ├── flatten.js
│ │ │ │ │ ├── index.js
│ │ │ │ │ ├── messages.js
│ │ │ │ │ └── token.js
│ │ │ │ └── resources
│ │ │ │ │ ├── actions.js
│ │ │ │ │ └── index.js
│ │ │ ├── index.js
│ │ │ ├── is_mobile.js
│ │ │ └── toast
│ │ │ │ ├── index.js
│ │ │ │ └── toast.js
│ │ ├── router
│ │ │ ├── before_each.js
│ │ │ ├── force_https.js
│ │ │ └── index.js
│ │ └── store
│ │ │ ├── actions.js
│ │ │ ├── getters
│ │ │ ├── index.js
│ │ │ ├── jwt.js
│ │ │ ├── two_factor.js
│ │ │ └── user.js
│ │ │ ├── index.js
│ │ │ ├── modules.js
│ │ │ ├── mutations.js
│ │ │ └── state.js
│ └── sass
│ │ ├── _variables.scss
│ │ └── app.scss
└── lang
│ ├── en
│ ├── auth.php
│ ├── pagination.php
│ ├── passwords.php
│ └── validation.php
│ └── pt_BR
│ ├── auth.php
│ ├── months.php
│ ├── pagination.php
│ ├── passwords.php
│ └── validation.php
├── server.php
├── storage
├── app
│ ├── .gitignore
│ └── public
│ │ └── .gitignore
├── framework
│ ├── .gitignore
│ ├── cache
│ │ └── .gitignore
│ ├── sessions
│ │ └── .gitignore
│ ├── testing
│ │ └── .gitignore
│ └── views
│ │ └── .gitignore
└── logs
│ └── .gitignore
├── tests
├── CreatesApplication.php
├── Feature
│ └── ExampleTest.php
├── TestCase.php
└── Unit
│ └── ExampleTest.php
├── webpack.mix.js
└── yarn.lock
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | ["env", {
4 | "modules": false,
5 | "targets": {
6 | "browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
7 | }
8 | }],
9 | "stage-2"
10 | ],
11 | "plugins": ["transform-vue-jsx", "transform-runtime"],
12 | "env": {
13 | "test": {
14 | "presets": ["env", "stage-2"],
15 | "plugins": ["transform-vue-jsx", "istanbul"]
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | indent_style = space
6 | indent_size = 2
7 | end_of_line = lf
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
11 | [*.php]
12 | charset = utf-8
13 | indent_style = space
14 | indent_size = 4
15 | end_of_line = lf
16 | insert_final_newline = true
17 | trim_trailing_whitespace = true
18 |
19 | [*.md]
20 | trim_trailing_whitespace = false
21 |
22 | [*.yml]
23 | indent_style = space
24 | indent_size = 2
25 |
--------------------------------------------------------------------------------
/.env.example:
--------------------------------------------------------------------------------
1 | APP_NAME="Emtudo Skeleton"
2 | APP_ENV=production
3 | APP_KEY=
4 | APP_DEBUG=false
5 | APP_URL=http://localhost
6 | JWT_SECRET=
7 |
8 | LOG_CHANNEL=stack
9 |
10 | DB_CONNECTION=mysql
11 | DB_HOST=mysql
12 | DB_PORT=3306
13 | DB_DATABASE=skeleton
14 | DB_USERNAME=emtudo
15 | DB_PASSWORD=emtudo
16 |
17 | BROADCAST_DRIVER=log
18 | CACHE_DRIVER=file
19 | SESSION_DRIVER=file
20 | SESSION_LIFETIME=120
21 | QUEUE_DRIVER=database
22 |
23 | REDIS_HOST=cache
24 | REDIS_PASSWORD=null
25 | REDIS_PORT=6379
26 |
27 | MAIL_DRIVER=smtp
28 | MAIL_HOST=mailcatcher
29 | MAIL_PORT=1025
30 | MAIL_USERNAME=null
31 | MAIL_PASSWORD=null
32 | MAIL_ENCRYPTION=null
33 |
34 | PUSHER_APP_ID=
35 | PUSHER_APP_KEY=
36 | PUSHER_APP_SECRET=
37 | PUSHER_APP_CLUSTER=mt1
38 |
39 | MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
40 | MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
41 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | /build/
2 | /config/
3 | /public_html/
4 | /*.js
5 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | // https://eslint.org/docs/user-guide/configuring
2 |
3 | module.exports = {
4 | root: true,
5 | parserOptions: {
6 | parser: 'babel-eslint'
7 | },
8 | env: {
9 | browser: true,
10 | },
11 | extends: [
12 | // https://github.com/vuejs/eslint-plugin-vue#priority-a-essential-error-prevention
13 | // consider switching to `plugin:vue/strongly-recommended` or `plugin:vue/recommended` for stricter rules.
14 | 'plugin:vue/essential',
15 | // https://github.com/standard/standard/blob/master/docs/RULES-en.md
16 | 'standard'
17 | ],
18 | "globals": {
19 | "window.": true,
20 | "alert": true,
21 | "$": true,
22 | "jQuery": true,
23 | "document": true,
24 | "iziToast": true,
25 | },
26 | // required to lint *.vue files
27 | plugins: [
28 | 'vue'
29 | ],
30 | // add your custom rules here
31 | rules: {
32 | // allow async-await
33 | 'generator-star-spacing': 'off',
34 | // allow debugger during development
35 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off'
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto
2 | *.css linguist-vendored
3 | *.scss linguist-vendored
4 | *.js linguist-vendored
5 | CHANGELOG.md export-ignore
6 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules
2 | /public/hot
3 | /public/css
4 | /public/js
5 | /public/*.js
6 | /public/storage
7 | /storage/*.key
8 | /vendor
9 | /.idea
10 | /.vscode
11 | /.vagrant
12 | Homestead.json
13 | Homestead.yaml
14 | npm-debug.log
15 | yarn-error.log
16 | .env
17 | .php_cs.cache
18 | docker-compose.override.yml
19 | nohup.out
20 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) Leandro Henrique
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6 |
7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8 |
9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
10 |
--------------------------------------------------------------------------------
/app/Domains/Audits/Audit.php:
--------------------------------------------------------------------------------
1 | schema->create('audits', function (Blueprint $table) {
16 | $table->bigIncrements('id');
17 | $table->unsignedInteger('user_id')->nullable()->index();
18 | $table->string('relation_name')->nullable();
19 | $table->string('event');
20 | $table->morphs('auditable');
21 | $table->text('old_values')->nullable();
22 | $table->text('new_values')->nullable();
23 | $table->text('url')->nullable();
24 | $table->ipAddress('ip_address')->nullable();
25 | $table->string('user_agent')->nullable();
26 | $table->string('tags')->nullable();
27 | $table->timestamps();
28 |
29 | $table->index(['user_id', 'auditable_type', 'auditable_id']);
30 | });
31 | }
32 |
33 | /**
34 | * Reverse the migrations.
35 | */
36 | public function down()
37 | {
38 | $this->schema->drop('audits');
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/app/Domains/Audits/Providers/DomainServiceProvider.php:
--------------------------------------------------------------------------------
1 | schema->create('failed_jobs', function (Blueprint $table) {
16 | $table->bigIncrements('id');
17 | $table->text('connection');
18 | $table->text('queue');
19 | $table->longText('payload');
20 | $table->longText('exception');
21 | $table->timestamp('failed_at')->useCurrent();
22 | });
23 | }
24 |
25 | /**
26 | * Reverse the migrations.
27 | */
28 | public function down()
29 | {
30 | $this->schema->drop('failed_jobs');
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/app/Domains/Jobs/Database/Migrations/CreateJobsTable.php:
--------------------------------------------------------------------------------
1 | schema = app('db')->connection()->getSchemaBuilder();
21 | }
22 |
23 | /**
24 | * Run the migrations.
25 | */
26 | public function up()
27 | {
28 | $this->schema->create('jobs', function (Blueprint $table) {
29 | $table->bigIncrements('id');
30 | $table->string('queue')->index();
31 | $table->longText('payload');
32 | $table->unsignedTinyInteger('attempts');
33 | $table->unsignedInteger('reserved_at')->nullable();
34 | $table->unsignedInteger('available_at');
35 | $table->unsignedInteger('created_at');
36 | });
37 | }
38 |
39 | /**
40 | * Reverse the migrations.
41 | */
42 | public function down()
43 | {
44 | $this->schema->drop('jobs');
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/app/Domains/Jobs/FailedJob.php:
--------------------------------------------------------------------------------
1 | transformerClass;
18 | }
19 |
20 | /**
21 | * @return League\Fractal\TransformerAbstract
22 | */
23 | public function getTransformer()
24 | {
25 | return app()->make($this->getTransformerClass());
26 | }
27 |
28 | public function publicId()
29 | {
30 | return app('hash.id')->encode($this->id);
31 | }
32 |
33 | public function getValue($key)
34 | {
35 | $value = array_get($this->attributes, $key, null);
36 |
37 | if ($value instanceof Carbon) {
38 | return $value->format('Y-m-d H:i:s');
39 | }
40 |
41 | return $value;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/app/Domains/UserModel.php:
--------------------------------------------------------------------------------
1 | belongsTo(User::class, 'user_id');
12 | }
13 |
14 | /**
15 | * Validate the model, so you will always have a user_id.
16 | */
17 | public static function boot()
18 | {
19 | parent::boot();
20 |
21 | self::saving(function ($model) {
22 | if (empty($model->user_id)) {
23 | $model->setOwnerUser();
24 | if (empty($model->user_id)) {
25 | throw new \InvalidArgumentException(get_class($model).' need to be a valid user_id attribute');
26 | }
27 | }
28 | });
29 | }
30 |
31 | public function setOwnerUser()
32 | {
33 | $user = auth()->user();
34 | if ($user) {
35 | $this->user_id = $user->id;
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/app/Domains/Users/Contracts/UserRepository.php:
--------------------------------------------------------------------------------
1 | $this->faker->name,
22 | 'email' => $this->faker->safeEmail,
23 | 'password' => 'abc123',
24 | ];
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/Domains/Users/Database/Migrations/CreatePasswordResetsTable.php:
--------------------------------------------------------------------------------
1 | schema->create('password_resets', function (Blueprint $table) {
16 | $table->string('email')->index();
17 | $table->string('token')->index();
18 |
19 | $table->timestamp('created_at');
20 |
21 | $table->index(['token', 'created_at']);
22 | });
23 | }
24 |
25 | /**
26 | * Reverse the migrations.
27 | */
28 | public function down()
29 | {
30 | $this->schema->drop('password_resets');
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/app/Domains/Users/Database/Migrations/CreateUsersTable.php:
--------------------------------------------------------------------------------
1 | schema->create('users', function (Blueprint $table) {
17 | $table->bigIncrements('id');
18 | $table->string('name', 50)->index();
19 | $table->string('email')->unique()->nullable();
20 | $table->boolean('email_confirmed')->default(false);
21 | $table->string('password')->nullable();
22 | $table->boolean('two_factor')->default(false);
23 | $table->string('two_factor_code', 6)->nullable();
24 |
25 | $table->boolean('is_admin')->default(false);
26 |
27 | $table->rememberToken();
28 | $table->timestamps();
29 | $table->softDeletes();
30 | });
31 |
32 | UserSeeder::start();
33 | }
34 |
35 | /**
36 | * Reverse the migrations.
37 | */
38 | public function down()
39 | {
40 | $this->schema->drop('users');
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/app/Domains/Users/Database/Seeders/UserSeeder.php:
--------------------------------------------------------------------------------
1 | create([
17 | 'name' => 'Admin',
18 | 'email' => 'admin@user.com',
19 | 'password' => 'abc123',
20 | 'is_admin' => true,
21 | 'email_confirmed' => true,
22 | ]);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/app/Domains/Users/Jobs/TwoFactorJob.php:
--------------------------------------------------------------------------------
1 | user = $user;
24 | }
25 |
26 | /**
27 | * Execute the job.
28 | */
29 | public function handle()
30 | {
31 | $user = $this->user;
32 | $user->two_factor_code = str_random(6);
33 | $user->save();
34 |
35 | $user->sendNotificationTwoFactor($user);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/app/Domains/Users/Notifications/TwoFactorNotification.php:
--------------------------------------------------------------------------------
1 | user = $user;
27 | }
28 |
29 | /**
30 | * Get the notification's delivery channels.
31 | *
32 | * @param mixed $notifiable
33 | *
34 | * @return array
35 | */
36 | public function via($notifiable)
37 | {
38 | return ['mail'];
39 | }
40 |
41 | /**
42 | * Get the mail representation of the notification.
43 | *
44 | * @param mixed $notifiable
45 | *
46 | * @return \Illuminate\Notifications\Messages\MailMessage
47 | */
48 | public function toMail($notifiable)
49 | {
50 | return (new MailMessage())
51 | ->subject('Autorização de Login')
52 | ->line("Olá, {$this->user->first_name}!")
53 | ->line('Esse é seu código de validação do login.')
54 | ->line("Código: {$this->user->two_factor_code}")
55 | ->template('auth::email.two_factor');
56 | }
57 |
58 | /**
59 | * Get the array representation of the notification.
60 | *
61 | * @param mixed $notifiable
62 | *
63 | * @return array
64 | */
65 | public function toArray($notifiable)
66 | {
67 | return [
68 | ];
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/app/Domains/Users/Presenters/UserPresenter.php:
--------------------------------------------------------------------------------
1 | entity->deleted_at) {
12 | return 'Suspenso';
13 | }
14 |
15 | return 'Ativo';
16 | }
17 |
18 | public function isActive()
19 | {
20 | return !($this->entity->deleted_at);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/app/Domains/Users/Providers/DomainServiceProvider.php:
--------------------------------------------------------------------------------
1 | Repositories\UserRepository::class,
19 | ];
20 | /**
21 | * @var string
22 | */
23 | protected $alias = 'users';
24 |
25 | protected $migrations = [
26 | Migrations\CreateUsersTable::class,
27 | Migrations\CreatePasswordResetsTable::class,
28 | ];
29 |
30 | protected $seeders = [
31 | Seeders\UserSeeder::class,
32 | ];
33 |
34 | protected $factories = [
35 | Factories\UserFactory::class,
36 | ];
37 | }
38 |
--------------------------------------------------------------------------------
/app/Domains/Users/Queries/UserQueryFilter.php:
--------------------------------------------------------------------------------
1 | applyWhere('id');
17 | $this->applyLike(['name', 'email']);
18 | $this->applyBoolean('is_admin');
19 | $this->query->orderBy('name');
20 |
21 | return $this->query;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/app/Domains/Users/Repositories/UserRepository.php:
--------------------------------------------------------------------------------
1 | password = $data['password'];
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/app/Domains/Users/Resources/Rules/UserRules.php:
--------------------------------------------------------------------------------
1 | 'required|string|min:2|max:50',
13 | 'email' => 'required|string|max:255|email|unique:users',
14 | 'password_confirmation' => 'required_with:password',
15 | ];
16 | }
17 |
18 | public function creating($callback = null)
19 | {
20 | return $this->returnRules([
21 | 'password' => 'required|min:6|confirmed',
22 | ], $callback);
23 | }
24 |
25 | public function updating($callback = null)
26 | {
27 | return $this->returnRules([
28 | 'email' => 'required|email',
29 | //'password' => 'sometimes|min:6|confirmed',
30 | ], $callback);
31 | }
32 |
33 | public function resetPassword($callback = null)
34 | {
35 | return $this->rules([
36 | 'email' => 'required|email',
37 | 'token' => 'required',
38 | 'password' => 'required|min:6',
39 | ], $callback);
40 | }
41 |
42 | public function forgotPassword($callback = null)
43 | {
44 | return $this->rules([
45 | 'email' => 'required|email',
46 | 'route' => 'required|url',
47 | ], $callback);
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/app/Domains/Users/Transformers/AuthTransformer.php:
--------------------------------------------------------------------------------
1 | $auth['token'],
18 | ];
19 | }
20 |
21 | public function includeUser($auth)
22 | {
23 | $user = $auth['user'];
24 |
25 | return $this->item($user, new UserTransformer());
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/app/Domains/Users/Transformers/UserTransformer.php:
--------------------------------------------------------------------------------
1 | $user->publicId(),
16 | 'email' => $user->email,
17 | 'name' => $user->name,
18 | 'is_admin' => $user->isAdmin(),
19 | 'first_name' => $user->first_name,
20 | 'last_name' => $user->last_name,
21 | 'two_factor' => [
22 | 'enabled' => $user->twoFactorEnabled(),
23 | 'valid' => User::$twoFactoryIsValid,
24 | ],
25 |
26 | 'deleted_at' => $user->getValue('deleted_at'),
27 | ];
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/app/Support/Console/Routing/RouteFile.php:
--------------------------------------------------------------------------------
1 | artisan = app(Kernel::class);
25 | $this->router = $this->artisan;
26 | }
27 |
28 | /**
29 | * Register Console Routes.
30 | */
31 | public function register()
32 | {
33 | return $this->routes();
34 | }
35 |
36 | /**
37 | * Declare console routes.
38 | */
39 | abstract public function routes();
40 | }
41 |
--------------------------------------------------------------------------------
/app/Support/Domain/Database/Migration.php:
--------------------------------------------------------------------------------
1 | schema = app('db')->connection()->getSchemaBuilder();
25 | $manager = app('db')->getDoctrineSchemaManager();
26 | $platform = $manager->getDatabasePlatform();
27 | $platform->registerDoctrineTypeMapping('json', 'text');
28 | }
29 |
30 | /**
31 | * Run the migrations.
32 | */
33 | abstract public function up();
34 |
35 | /**
36 | * Reverse the migrations.
37 | */
38 | abstract public function down();
39 | }
40 |
--------------------------------------------------------------------------------
/app/Support/Domain/Database/ModelFactory.php:
--------------------------------------------------------------------------------
1 | factory = app()->make(Factory::class);
43 | $faker = app()->make(Generator::class);
44 | $faker->addProvider(new \Faker\Provider\pt_BR\Person($faker));
45 | $faker->addProvider(new \Faker\Provider\pt_BR\Address($faker));
46 | $faker->addProvider(new \Faker\Provider\pt_BR\PhoneNumber($faker));
47 | $faker->addProvider(new \Faker\Provider\pt_BR\Company($faker));
48 | $faker->addProvider(new \Faker\Provider\Lorem($faker));
49 | $faker->addProvider(new \Faker\Provider\Internet($faker));
50 |
51 | $this->faker = $faker;
52 | }
53 |
54 | /**
55 | * @return mixed
56 | */
57 | public function define()
58 | {
59 | $callback = function ($faker, $fields) {
60 | return $this->fields($fields[0] ?? []);
61 | };
62 |
63 | if ($this->name) {
64 | return $this->factory->defineAs($this->model, $this->name, $callback);
65 | }
66 |
67 | return $this->factory->define($this->model, $callback);
68 | }
69 |
70 | /**
71 | * @return mixed
72 | */
73 | abstract public function fields();
74 | }
75 |
--------------------------------------------------------------------------------
/app/Support/Domain/Fractal/Manager.php:
--------------------------------------------------------------------------------
1 | isPaginated($resource) || $this->isCollection($resource)) {
22 | return $resource->first();
23 | }
24 |
25 | return $resource;
26 | }
27 |
28 | public function extractTransformer($resource)
29 | {
30 | $transformer = null;
31 |
32 | $evaluate = $this->extractFirst($resource);
33 |
34 | if ($evaluate && $this->isObject($evaluate) && method_exists($evaluate, 'getTransformer')) {
35 | $transformer = $evaluate->getTransformer();
36 | }
37 |
38 | return $transformer ?? new Transformer();
39 | }
40 |
41 | /**
42 | * @param $resource
43 | * @param array $includes
44 | * @param null|TransformerAbstract $transformer
45 | *
46 | * @return Fractal
47 | */
48 | public function transform($resource = [], $includes = [], TransformerAbstract $transformer = null)
49 | {
50 | if (!$transformer) {
51 | $transformer = $this->extractTransformer($resource);
52 | }
53 |
54 | if ($this->isPaginated($resource)) {
55 | return \fractal()->collection($resource, $transformer)
56 | ->paginateWith(new IlluminatePaginatorAdapter($resource))
57 | ->parseIncludes($includes);
58 | }
59 |
60 | if ($this->isCollection($resource)) {
61 | return \fractal()->collection($resource, $transformer)->parseIncludes($includes);
62 | }
63 |
64 | return \fractal()->item($resource, $transformer)->parseIncludes($includes);
65 | }
66 |
67 | protected function isCollection($resource)
68 | {
69 | return $resource instanceof Collection;
70 | }
71 |
72 | protected function isPaginated($resource)
73 | {
74 | return $resource instanceof LengthAwarePaginator;
75 | }
76 |
77 | protected function isObject($resource)
78 | {
79 | return is_object($resource);
80 | }
81 |
82 | protected function isModel($resource)
83 | {
84 | return $resource instanceof Model;
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/app/Support/Domain/Providers/FakerServiceProvider.php:
--------------------------------------------------------------------------------
1 | app->singleton(FakerGenerator::class, function () {
14 | return FakerFactory::create('pt_BR');
15 | });
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/app/Support/Domain/Repositories/Fractal/DataArraySerializer.php:
--------------------------------------------------------------------------------
1 | $data];
24 | }
25 |
26 | /**
27 | * Serialize an item.
28 | *
29 | * @param string $resourceKey
30 | * @param array $data
31 | *
32 | * @return array
33 | */
34 | public function item($resourceKey, array $data)
35 | {
36 | if (false === $resourceKey) {
37 | return $data;
38 | }
39 |
40 | return ['data' => $data];
41 | }
42 |
43 | /**
44 | * Serialize null resource.
45 | *
46 | * @return array
47 | */
48 | public function null()
49 | {
50 | return ['data' => []];
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/app/Support/Domain/Repositories/UserRepository.php:
--------------------------------------------------------------------------------
1 | exceptionType;
17 | }
18 | parent::__construct($this->statusCode, $message, $previous, $headers, $code);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/app/Support/Exception/UpdateFailedException.php:
--------------------------------------------------------------------------------
1 | exceptionType;
17 | }
18 | parent::__construct($this->statusCode, $message, $previous, $headers, $code);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/app/Support/Hash/ID.php:
--------------------------------------------------------------------------------
1 | hash = new Hashids($this->projectKey, $this->padLength, $this->alphabet);
20 | }
21 |
22 | public function encode($value)
23 | {
24 | return $this->hash->encode($value);
25 | }
26 |
27 | public function decode($hashed)
28 | {
29 | $value = array_first($this->hash->decode($hashed));
30 |
31 | return $value ?? $hashed;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/app/Support/Hash/IDServiceProvider.php:
--------------------------------------------------------------------------------
1 | app->singleton('hash.id', function () {
12 | return new ID();
13 | });
14 |
15 | require_once __DIR__ . '/functions.php';
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/app/Support/Hash/functions.php:
--------------------------------------------------------------------------------
1 | encode($id);
16 | }
17 | }
18 |
19 | if (!function_exists('decode_id')) {
20 | /**
21 | * @param string $encodedId
22 | *
23 | * @return string
24 | */
25 | function decode_id($encodedId)
26 | {
27 | return app('hash.id')->decode($encodedId);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/app/Support/Helpers/HelperServiceProvider.php:
--------------------------------------------------------------------------------
1 | message = $message ?? 'Os dados informados falharam a validação.';
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/app/Support/Http/Request.php:
--------------------------------------------------------------------------------
1 | expectsJson()) {
34 | return new JsonResponse(['errors' => $errors], 422);
35 | }
36 |
37 | return $this->redirector->to($this->getRedirectUrl())
38 | ->withInput($this->except($this->dontFlash))
39 | ->withErrors($errors, $this->errorBag);
40 | }
41 |
42 | /**
43 | * Handle a failed validation attempt.
44 | *
45 | * @param \Illuminate\Contracts\Validation\Validator $validator
46 | *
47 | * @throws ValidationException
48 | */
49 | protected function failedValidation(Validator $validator)
50 | {
51 | $errors = $validator->errors()->toArray();
52 |
53 | throw (new ValidationException(
54 | $validator,
55 | response()->json($errors, 422)
56 | ));
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/app/Support/Http/Routing/RouteFile.php:
--------------------------------------------------------------------------------
1 | router = app('router');
23 | $this->options = $options;
24 | }
25 |
26 | /**
27 | * Register Routes.
28 | */
29 | public function register()
30 | {
31 | $this->router->group($this->options, function () {
32 | $this->routes();
33 | });
34 | }
35 |
36 | /**
37 | * Define routes.
38 | *
39 | * @return mixed
40 | */
41 | abstract public function routes();
42 | }
43 |
--------------------------------------------------------------------------------
/app/Support/Http/ServiceProvider.php:
--------------------------------------------------------------------------------
1 | app['request'];
12 |
13 | if ($request->is('api*')) {
14 | $request->headers->add(['accept' => 'application/json']);
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/app/Support/Notifications/ResetPassword.php:
--------------------------------------------------------------------------------
1 | token);
21 | }
22 |
23 | return (new MailMessage())
24 | ->line('Você recebeu esse email pois recebemos uma solicitação de recuperação de senha para a sua conta.')
25 | ->action('Recuperar Senha', $this->token, false)
26 | ->line('Se você não fez essa requisição, fique tranquilo, nenhum ação é necessária e você pode ignorar esse email.')
27 | ->subject('Recuperar Senha')
28 | ->template('auth::email.recover_password');
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/app/Support/Shield/Contracts/Rules.php:
--------------------------------------------------------------------------------
1 | creating($callback) : [];
25 | }
26 | if ('put' === $type) {
27 | return method_exists($this, 'updating') ? $this->updating($callback) : [];
28 | }
29 |
30 | return $this->defaultRules();
31 | }
32 |
33 | protected function returnRules(array $rules = [], $callback = null)
34 | {
35 | $rules = array_merge($this->defaultRules(), $rules);
36 |
37 | return $this->rules($rules, $callback);
38 | }
39 |
40 | protected function rules(array $rules = [], $callback = null)
41 | {
42 | if (is_callable($callback)) {
43 | return $callback($rules);
44 | }
45 |
46 | return $rules;
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/app/Support/Validators/CustomValidatorServiceProvider.php:
--------------------------------------------------------------------------------
1 | app->validator->resolver(function ($translator, $data, $rules, $messages, $attributes) {
14 | return new Validator($translator, $data, $rules, $messages, $attributes);
15 | });
16 | }
17 |
18 | /**
19 | * Register the service provider.
20 | */
21 | public function register()
22 | {
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/app/Support/Validators/Validator.php:
--------------------------------------------------------------------------------
1 | clearSpecialChars($value);
20 |
21 | return parent::validateUnique($attribute, $value, $parameters); // TODO: Change the autogenerated stub
22 | }
23 |
24 | /**
25 | * @param string $attribute
26 | * @param mixed $value
27 | * @param array $parameters
28 | *
29 | * @return bool
30 | */
31 | public function validateCleanExists($attribute, $value, $parameters)
32 | {
33 | $value = $this->clearSpecialChars($value);
34 |
35 | return parent::validateExists($attribute, $value, $parameters);
36 | }
37 |
38 | public function validateValidDateFormat($attribute, $value, $parameters)
39 | {
40 | return DateHelper::isValidDate($value);
41 | }
42 |
43 | public function validateExistsPublicId($attribute, $value, $parameters)
44 | {
45 | return $this->validateExists($attribute, decode_id($value), $parameters);
46 | }
47 |
48 | /**
49 | * @param string $value
50 | *
51 | * @return string
52 | */
53 | protected function clearSpecialChars($value)
54 | {
55 | return str_replace(['.', '/', ',', '-', '_'], '', $value);
56 | }
57 |
58 | /**
59 | * Replace all params the force_user rule.
60 | *
61 | * @param string $message
62 | * @param string $attribute
63 | * @param string $rule
64 | * @param array $parameters
65 | *
66 | * @return string
67 | */
68 | protected function replaceForceYear($message, $attribute, $rule, $parameters)
69 | {
70 | $other = $this->getDisplayableAttribute($parameters[0]);
71 |
72 | return str_replace(':other', $other, $message);
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/app/Support/ViewPresenter/Presentable.php:
--------------------------------------------------------------------------------
1 | presenter or !class_exists($this->presenter)) {
24 | throw new PresenterException('Please set the $presenter property to your presenter path.');
25 | }
26 |
27 | if (!$this->presenterInstance) {
28 | $this->presenterInstance = new $this->presenter($this);
29 | }
30 |
31 | return $this->presenterInstance;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/app/Support/ViewPresenter/PresenterException.php:
--------------------------------------------------------------------------------
1 | creating();
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/app/Units/Admin/Users/Http/Requests/Users/UpdateUserRequest.php:
--------------------------------------------------------------------------------
1 | updating();
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/app/Units/Admin/Users/Providers/RouteServiceProvider.php:
--------------------------------------------------------------------------------
1 | ['api', 'auth', 'admin', 'twoFactorVerify'],
26 | 'namespace' => $this->namespace,
27 | 'prefix' => 'v1/admin/users',
28 | 'as' => 'admin::users::',
29 | ]))->register();
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/app/Units/Admin/Users/Providers/UnitServiceProvider.php:
--------------------------------------------------------------------------------
1 | router->put('users/{user}/activate', 'UserController@activate');
19 | $this->router->put('users/{user}/suspend', 'UserController@suspend');
20 | $this->router->apiResource('users', 'UserController');
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/app/Units/Auth/Http/Controllers/LoginController.php:
--------------------------------------------------------------------------------
1 | only(['email', 'password']);
15 | if ($auth->attempt($credentials)) {
16 | return $this->respond->ok([
17 | 'token' => $auth->issue(),
18 | 'user' => $auth->user(),
19 | ], null, ['user'], [], [], new AuthTransformer());
20 | }
21 |
22 | return $this->respond->error('Erro ao autenticar.');
23 | }
24 |
25 | public function user()
26 | {
27 | return $this->respond->ok($this->user, null);
28 | }
29 |
30 | public function refresh(Guard $auth)
31 | {
32 | // refresh token.
33 | $token = $auth->refresh();
34 |
35 | if (!$token) {
36 | return $this->respond->error('Erro ao atualizar token.');
37 | }
38 |
39 | return $this->respond->ok([
40 | 'token' => $token,
41 | 'user' => $auth->user(),
42 | ], null, [], [], [], new AuthTransformer());
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/app/Units/Auth/Http/Controllers/RegisterController.php:
--------------------------------------------------------------------------------
1 | 'required|string|max:255',
38 | 'email' => 'required|string|email|max:255|unique:users',
39 | 'password' => 'required|string|min:6|confirmed',
40 | ]);
41 | }
42 |
43 | /**
44 | * Create a new user instance after a valid registration.
45 | *
46 | * @param array $data
47 | *
48 | * @return \Emtudo\Domains\Users\User
49 | */
50 | protected function create(array $data)
51 | {
52 | $repository = app()->make(UserRepository::class);
53 |
54 | return $repository->create($data);
55 | }
56 |
57 | /**
58 | * The user has been registered.
59 | *
60 | * @param \Illuminate\Http\Request $request
61 | * @param mixed $user
62 | *
63 | * @return mixed
64 | */
65 | protected function registered(Request $request, $user)
66 | {
67 | $auth = $this->guard();
68 |
69 | return $this->respond->ok([
70 | 'token' => $auth->issue(),
71 | 'user' => $auth->user(),
72 | ], null, ['user'], [], [], new AuthTransformer());
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/app/Units/Auth/Http/Controllers/ResetPasswordController.php:
--------------------------------------------------------------------------------
1 | resetPassword();
30 | }
31 |
32 | /**
33 | * Reset the given user's password.
34 | *
35 | * @param \Illuminate\Contracts\Auth\CanResetPassword $user
36 | * @param string $password
37 | */
38 | protected function resetPassword($user, $password)
39 | {
40 | $user->forceFill([
41 | 'password' => $password,
42 | 'remember_token' => Str::random(60),
43 | ])->save();
44 |
45 | $this->guard()->login($user);
46 | }
47 |
48 | /**
49 | * Get the response for a successful password reset.
50 | *
51 | * @param string $response
52 | *
53 | * @return \Illuminate\Http\JsonResponse
54 | */
55 | protected function sendResetResponse($response)
56 | {
57 | $auth = $this->guard();
58 |
59 | return $this->respond->ok([
60 | 'token' => $auth->issue(),
61 | 'user' => $auth->user(),
62 | ], null, ['user'], [], [], new AuthTransformer());
63 | }
64 |
65 | /**
66 | * Get the response for a failed password reset.
67 | *
68 | * @param \Illuminate\Http\Request
69 | * @param string $response
70 | *
71 | * @return \Illuminate\Http\JsonResponse
72 | */
73 | protected function sendResetFailedResponse(Request $request, $response)
74 | {
75 | return $this->respond->notFound(trans($response));
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/app/Units/Auth/Http/Controllers/TwoFactorController.php:
--------------------------------------------------------------------------------
1 | dispatchCode();
17 |
18 | return $this->respond->ok($this->user);
19 | }
20 |
21 | public function disableTwoFactor(Guard $auth)
22 | {
23 | $user = $this->user;
24 |
25 | $user->two_factor = false;
26 | $user->save();
27 |
28 | return $this->refreshToken($auth, false);
29 | }
30 |
31 | public function verifyCode(Guard $auth)
32 | {
33 | $code = request()->get('code', null);
34 | $user = $this->user;
35 |
36 | $valid = $code === $user->two_factor_code;
37 | if ($valid) {
38 | $user->two_factor_code = null;
39 | $user->save();
40 | } else {
41 | $this->dispatchCode();
42 |
43 | return $this->respond->invalid(['code' => 'Código Inválido!']);
44 | }
45 |
46 | return $this->refreshToken($auth, true);
47 | }
48 |
49 | private function refreshToken(Guard $auth, bool $valid = true)
50 | {
51 | User::$twoFactoryIsValid = $valid;
52 | $token = $auth->refresh(null, ['two_factor' => $valid]);
53 |
54 | if (!$token) {
55 | return $this->respond->error('Erro ao atualizar token.');
56 | }
57 |
58 | return $this->respond->ok([
59 | 'token' => $token,
60 | 'user' => $auth->user(),
61 | ], null, ['user'], [], [], new AuthTransformer());
62 | }
63 |
64 | private function dispatchCode()
65 | {
66 | $user = $this->user;
67 |
68 | $user->two_factor = true;
69 | $user->two_factor_code = null;
70 | $user->save();
71 |
72 | dispatch(new TwoFactorJob($user));
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/app/Units/Auth/Providers/AuthServiceProvider.php:
--------------------------------------------------------------------------------
1 | 'Emtudo\Policies\ModelPolicy',
16 | ];
17 |
18 | /**
19 | * Register any authentication / authorization services.
20 | */
21 | public function boot()
22 | {
23 | $this->registerPolicies();
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/app/Units/Auth/Providers/RouteServiceProvider.php:
--------------------------------------------------------------------------------
1 | ['api'],
28 | 'namespace' => $this->namespace,
29 | 'prefix' => 'v1/auth',
30 | 'as' => 'auth::',
31 | ]))->register();
32 |
33 | (new ApiAuth([
34 | 'middleware' => ['api', 'auth'],
35 | 'namespace' => $this->namespace,
36 | 'prefix' => 'v1/auth',
37 | 'as' => 'auth::',
38 | ]))->register();
39 |
40 | (new Api2Factor([
41 | 'middleware' => ['api', 'auth', 'twoFactorVerify'],
42 | 'namespace' => $this->namespace,
43 | 'prefix' => 'v1/auth',
44 | 'as' => 'auth::',
45 | ]))->register();
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/app/Units/Auth/Providers/UnitServiceProvider.php:
--------------------------------------------------------------------------------
1 |
35 | @component('mail::button', ['url' => $actionUrl, 'color' => $color])
36 | {{ $actionText }}
37 | @endcomponent
38 | @endisset
39 |
40 | {{-- Outro Lines --}}
41 | @foreach ($outroLines as $line)
42 | {{ $line }}
43 |
44 | @endforeach
45 |
46 | {{-- Salutation --}}
47 | @if (! empty($salutation))
48 | {{ $salutation }}
49 | @else
50 | Atenciosamente,
{{ config('app.name') }}
51 | @endif
52 |
53 | {{-- Subcopy --}}
54 | @isset($actionText)
55 | @component('mail::subcopy')
56 | Se você está tendo problemas para clicar no "{{ $actionText }}", copie e cole a URL abaixo no seu browser:
57 | [{{ $actionUrl }}]({{ $actionUrl }})
58 | @endcomponent
59 | @endisset
60 | @endcomponent
61 |
--------------------------------------------------------------------------------
/app/Units/Auth/Resources/Views/email/two_factor.blade.php:
--------------------------------------------------------------------------------
1 | @component('mail::message')
2 |
3 | {{-- Intro Lines --}}
4 | @foreach ($introLines as $line)
5 | {{ $line }}
6 |
7 | @endforeach
8 |
9 | {{-- Salutation --}}
10 | @if (! empty($salutation))
11 | {{ $salutation }}
12 | @else
13 | Atenciosamente,
{{ config('app.name') }}
14 | @endif
15 |
16 | @endcomponent
17 |
--------------------------------------------------------------------------------
/app/Units/Auth/Routes/Api.php:
--------------------------------------------------------------------------------
1 | router->get('login', 'LoginController@showLoginForm')->name('login');
21 | $this->router->post('login', 'LoginController@login');
22 | $this->router->post('logout', 'LoginController@logout')->name('logout');
23 |
24 | // Registration Routes...
25 | $this->router->post('register', 'RegisterController@register');
26 |
27 | // Password Reset Routes...
28 | $this->router->post('password/email', 'ForgotPasswordController@sendResetLinkEmail')->name('password.email');
29 | $this->router->post('password/reset', 'ResetPasswordController@reset');
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/app/Units/Auth/Routes/Api2Factor.php:
--------------------------------------------------------------------------------
1 | router->get('two_factor/disabled', 'TwoFactorController@disableTwoFactor')
13 | ->name('disable_two_factor');
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/app/Units/Auth/Routes/ApiAuth.php:
--------------------------------------------------------------------------------
1 | router->get('user', 'LoginController@user')
16 | ->name('user');
17 |
18 | $this->router->post('two_factor/active', 'TwoFactorController@activeTwoFactor')
19 | ->name('enable_two_factor');
20 |
21 | $this->router->post('two_factor/verify', 'TwoFactorController@verifyCode')
22 | ->name('vefiry_two_factor');
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/app/Units/ConsoleKernel.php:
--------------------------------------------------------------------------------
1 | command('inspire')
26 | // ->hourly();
27 | }
28 |
29 | /**
30 | * Register the commands for the application.
31 | */
32 | protected function commands()
33 | {
34 | $this->load(__DIR__.'/Core/Commands');
35 |
36 | require base_path('app/Units/Core/Routes/Console.php');
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/app/Units/Core/Http/Controllers/WelcomeController.php:
--------------------------------------------------------------------------------
1 | user();
25 |
26 | if (!$user->isAdmin()) {
27 | throw new AuthorizationException();
28 | }
29 |
30 | return $next($request);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/app/Units/Core/Http/Middleware/EncryptCookies.php:
--------------------------------------------------------------------------------
1 | check()) {
21 | return redirect('/home');
22 | }
23 |
24 | return $next($request);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/Units/Core/Http/Middleware/TrimStrings.php:
--------------------------------------------------------------------------------
1 | $this->namespace,
26 | 'as' => 'web::',
27 | ]))->register();
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/app/Units/Core/Providers/UnitServiceProvider.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Emtudo Skeleton
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/app/Units/Core/Routes/Console.php:
--------------------------------------------------------------------------------
1 | comment(Inspiring::quote());
18 | })->describe('Display an inspiring quote');
19 |
--------------------------------------------------------------------------------
/app/Units/Core/Routes/Web.php:
--------------------------------------------------------------------------------
1 | router->get('/', 'WelcomeController@index')->name('index');
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/app/Units/HttpKernel.php:
--------------------------------------------------------------------------------
1 | [
31 | \Emtudo\Units\Core\Http\Middleware\EncryptCookies::class,
32 | // \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
33 | \Illuminate\Session\Middleware\StartSession::class,
34 | \Illuminate\Session\Middleware\AuthenticateSession::class,
35 | \Illuminate\View\Middleware\ShareErrorsFromSession::class,
36 | \Emtudo\Units\Core\Http\Middleware\VerifyCsrfToken::class,
37 | \Illuminate\Routing\Middleware\SubstituteBindings::class,
38 | ],
39 |
40 | 'api' => [
41 | 'throttle:60,1',
42 | 'bindings',
43 | ],
44 | ];
45 |
46 | /**
47 | * The application's route middleware.
48 | *
49 | * These middleware may be assigned to groups or used individually.
50 | *
51 | * @var array
52 | */
53 | protected $routeMiddleware = [
54 | 'admin' => \Emtudo\Units\Core\Http\Middleware\Admin::class,
55 | 'auth' => \Illuminate\Auth\Middleware\Authenticate::class,
56 | 'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
57 | 'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
58 | 'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
59 | 'can' => \Illuminate\Auth\Middleware\Authorize::class,
60 | 'guest' => \Emtudo\Units\Core\Http\Middleware\RedirectIfAuthenticated::class,
61 | 'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
62 | 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
63 | 'twoFactorVerify' => \Emtudo\Units\Core\Http\Middleware\TwoFactorVerify::class,
64 | ];
65 | }
66 |
--------------------------------------------------------------------------------
/app/Units/User/Providers/UnitServiceProvider.php:
--------------------------------------------------------------------------------
1 | respond->ok($this->user);
21 | }
22 |
23 | /**
24 | * Update user's data.
25 | *
26 | * @param UpdateUserRequest $request
27 | * @param UserRepository $repository
28 | *
29 | * @return [type]
30 | */
31 | public function update(UpdateUserRequest $request, UserRepository $repository)
32 | {
33 | $user = $this->user;
34 | $repository->update($user, $this->params);
35 |
36 | return $this->respond->ok($user);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/app/Units/User/Users/Http/Requests/UpdateUserRequest.php:
--------------------------------------------------------------------------------
1 | updating();
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/app/Units/User/Users/Providers/RouteServiceProvider.php:
--------------------------------------------------------------------------------
1 | ['api', 'auth', 'twoFactorVerify'],
26 | 'namespace' => $this->namespace,
27 | 'prefix' => 'v1/user/users',
28 | 'as' => 'user::users::',
29 | ]))->register();
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/app/Units/User/Users/Providers/UnitServiceProvider.php:
--------------------------------------------------------------------------------
1 | router->get('profile', 'ProfileController@show');
19 | $this->router->put('profile', 'ProfileController@update');
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/artisan:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env php
2 | make(Illuminate\Contracts\Console\Kernel::class);
34 |
35 | $status = $kernel->handle(
36 | $input = new Symfony\Component\Console\Input\ArgvInput,
37 | new Symfony\Component\Console\Output\ConsoleOutput
38 | );
39 |
40 | /*
41 | |--------------------------------------------------------------------------
42 | | Shutdown The Application
43 | |--------------------------------------------------------------------------
44 | |
45 | | Once Artisan has finished running, we will fire off the shutdown events
46 | | so that any final work may be done by the application before we shut
47 | | down the process. This is the last thing to happen to the request.
48 | |
49 | */
50 |
51 | $kernel->terminate($input, $status);
52 |
53 | exit($status);
54 |
--------------------------------------------------------------------------------
/bootstrap/app.php:
--------------------------------------------------------------------------------
1 | singleton(
30 | Illuminate\Contracts\Http\Kernel::class,
31 | Emtudo\Units\HttpKernel::class
32 | );
33 |
34 | $app->singleton(
35 | Illuminate\Contracts\Console\Kernel::class,
36 | Emtudo\Units\ConsoleKernel::class
37 | );
38 |
39 | $app->singleton(
40 | Illuminate\Contracts\Debug\ExceptionHandler::class,
41 | Emtudo\Units\ExceptionHandler::class
42 | );
43 |
44 | /*
45 | |--------------------------------------------------------------------------
46 | | Return The Application
47 | |--------------------------------------------------------------------------
48 | |
49 | | This script returns the application instance. The instance is given to
50 | | the calling script so we can separate the building of the instances
51 | | from the actual running of the application and sending responses.
52 | |
53 | */
54 |
55 | return $app;
56 |
--------------------------------------------------------------------------------
/bootstrap/cache/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "emtudo/laravel-vue",
3 | "description": "Skeleton Laravel with Vue",
4 | "keywords": ["skeleton", "laravel", "vue", "vuejs"],
5 | "license": "MIT",
6 | "type": "project",
7 | "require": {
8 | "php": "^7.2.0",
9 | "artesaos/migrator": "^1.3",
10 | "codecasts/laravel-jwt": "^0.10.0",
11 | "doctrine/dbal": "^2.6",
12 | "fico7489/laravel-pivot": "^2.2",
13 | "fideloper/proxy": "^4.0",
14 | "hashids/hashids": "^3.0",
15 | "laravel/framework": "5.6.*",
16 | "laravel/socialite": "^3.0",
17 | "laravel/tinker": "^1.0",
18 | "owen-it/laravel-auditing": "^6.0",
19 | "resultsystems/monitor": "^0.2.0",
20 | "resultsystems/validation": "^5.1",
21 | "socialiteproviders/google": "^3.0",
22 | "socialiteproviders/twitter": "^3.0",
23 | "spatie/laravel-fractal": "^5.3"
24 | },
25 | "require-dev": {
26 | "filp/whoops": "^2.0",
27 | "fzaninotto/faker": "^1.4",
28 | "mockery/mockery": "^1.0",
29 | "nunomaduro/collision": "^2.0",
30 | "phpunit/phpunit": "^7.0"
31 | },
32 | "autoload": {
33 | "classmap": [
34 | ],
35 | "psr-4": {
36 | "Emtudo\\": "app/"
37 | }
38 | },
39 | "autoload-dev": {
40 | "psr-4": {
41 | "Tests\\": "tests/"
42 | }
43 | },
44 | "extra": {
45 | "laravel": {
46 | "dont-discover": [
47 | ]
48 | }
49 | },
50 | "scripts": {
51 | "post-root-package-install": [
52 | "@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
53 | ],
54 | "post-create-project-cmd": [
55 | "@php artisan key:generate"
56 | ],
57 | "post-autoload-dump": [
58 | "Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
59 | "@php artisan package:discover"
60 | ]
61 | },
62 | "config": {
63 | "preferred-install": "dist",
64 | "sort-packages": true,
65 | "optimize-autoloader": true
66 | },
67 | "minimum-stability": "dev",
68 | "prefer-stable": true
69 | }
70 |
--------------------------------------------------------------------------------
/config/broadcasting.php:
--------------------------------------------------------------------------------
1 | env('BROADCAST_DRIVER', 'null'),
19 |
20 | /*
21 | |--------------------------------------------------------------------------
22 | | Broadcast Connections
23 | |--------------------------------------------------------------------------
24 | |
25 | | Here you may define all of the broadcast connections that will be used
26 | | to broadcast events to other systems or over websockets. Samples of
27 | | each available type of connection are provided inside this array.
28 | |
29 | */
30 |
31 | 'connections' => [
32 |
33 | 'pusher' => [
34 | 'driver' => 'pusher',
35 | 'key' => env('PUSHER_APP_KEY'),
36 | 'secret' => env('PUSHER_APP_SECRET'),
37 | 'app_id' => env('PUSHER_APP_ID'),
38 | 'options' => [
39 | 'cluster' => env('PUSHER_APP_CLUSTER'),
40 | 'encrypted' => true,
41 | ],
42 | ],
43 |
44 | 'redis' => [
45 | 'driver' => 'redis',
46 | 'connection' => 'default',
47 | ],
48 |
49 | 'log' => [
50 | 'driver' => 'log',
51 | ],
52 |
53 | 'null' => [
54 | 'driver' => 'null',
55 | ],
56 |
57 | ],
58 |
59 | ];
60 |
--------------------------------------------------------------------------------
/config/filesystems.php:
--------------------------------------------------------------------------------
1 | env('FILESYSTEM_DRIVER', 'local'),
17 |
18 | /*
19 | |--------------------------------------------------------------------------
20 | | Default Cloud Filesystem Disk
21 | |--------------------------------------------------------------------------
22 | |
23 | | Many applications store files both locally and in the cloud. For this
24 | | reason, you may specify a default "cloud" driver here. This driver
25 | | will be bound as the Cloud disk implementation in the container.
26 | |
27 | */
28 |
29 | 'cloud' => env('FILESYSTEM_CLOUD', 's3'),
30 |
31 | /*
32 | |--------------------------------------------------------------------------
33 | | Filesystem Disks
34 | |--------------------------------------------------------------------------
35 | |
36 | | Here you may configure as many filesystem "disks" as you wish, and you
37 | | may even configure multiple disks of the same driver. Defaults have
38 | | been setup for each driver as an example of the required options.
39 | |
40 | | Supported Drivers: "local", "ftp", "sftp", "s3", "rackspace"
41 | |
42 | */
43 |
44 | 'disks' => [
45 |
46 | 'local' => [
47 | 'driver' => 'local',
48 | 'root' => storage_path('app'),
49 | ],
50 |
51 | 'public' => [
52 | 'driver' => 'local',
53 | 'root' => storage_path('app/public'),
54 | 'url' => env('APP_URL').'/storage',
55 | 'visibility' => 'public',
56 | ],
57 |
58 | 's3' => [
59 | 'driver' => 's3',
60 | 'key' => env('AWS_ACCESS_KEY_ID'),
61 | 'secret' => env('AWS_SECRET_ACCESS_KEY'),
62 | 'region' => env('AWS_DEFAULT_REGION'),
63 | 'bucket' => env('AWS_BUCKET'),
64 | 'url' => env('AWS_URL'),
65 | ],
66 |
67 | ],
68 |
69 | ];
70 |
--------------------------------------------------------------------------------
/config/fractal.php:
--------------------------------------------------------------------------------
1 | Emtudo\Support\Domain\Repositories\Fractal\DataArraySerializer::class,
10 |
11 | /* The default paginator to be used when performing a transformation. It
12 | * may be left empty to use Fractal's default one. This can either be a
13 | * string or a League\Fractal\Paginator\PaginatorInterface subclass.*/
14 | 'default_paginator' => Illuminate\Pagination\LengthAwarePaginator::class,
15 | // 'default_paginator' => '',
16 |
17 | /*
18 | * League\Fractal\Serializer\JsonApiSerializer will use this value to
19 | * as a prefix for generated links. Set to `null` to disable this.
20 | */
21 | 'base_url' => null,
22 |
23 | /*
24 | * If you wish to override or extend the default Spatie\Fractal\Fractal
25 | * instance provide the name of the class you want to use.
26 | */
27 | 'fractal_class' => Spatie\Fractal\Fractal::class,
28 |
29 | 'auto_includes' => [
30 | /*
31 | * If enabled Fractal will automatically add the includes who's
32 | * names are present in the `include` request parameter.
33 | */
34 | 'enabled' => true,
35 |
36 | // The name of key in the request to where we should look for the includes to include.
37 | 'request_key' => 'include',
38 | ],
39 | ];
40 |
--------------------------------------------------------------------------------
/config/hashing.php:
--------------------------------------------------------------------------------
1 | 'argon',
18 | ];
19 |
--------------------------------------------------------------------------------
/config/logging.php:
--------------------------------------------------------------------------------
1 | env('LOG_CHANNEL', 'stack'),
19 |
20 | /*
21 | |--------------------------------------------------------------------------
22 | | Log Channels
23 | |--------------------------------------------------------------------------
24 | |
25 | | Here you may configure the log channels for your application. Out of
26 | | the box, Laravel uses the Monolog PHP logging library. This gives
27 | | you a variety of powerful log handlers / formatters to utilize.
28 | |
29 | | Available Drivers: "single", "daily", "slack", "syslog",
30 | | "errorlog", "monolog",
31 | | "custom", "stack"
32 | |
33 | */
34 |
35 | 'channels' => [
36 | 'stack' => [
37 | 'driver' => 'stack',
38 | 'channels' => ['single'],
39 | ],
40 |
41 | 'single' => [
42 | 'driver' => 'single',
43 | 'path' => storage_path('logs/laravel.log'),
44 | 'level' => 'debug',
45 | ],
46 |
47 | 'daily' => [
48 | 'driver' => 'daily',
49 | 'path' => storage_path('logs/laravel.log'),
50 | 'level' => 'debug',
51 | 'days' => 7,
52 | ],
53 |
54 | 'slack' => [
55 | 'driver' => 'slack',
56 | 'url' => env('LOG_SLACK_WEBHOOK_URL'),
57 | 'username' => 'Laravel Log',
58 | 'emoji' => ':boom:',
59 | 'level' => 'critical',
60 | ],
61 |
62 | 'stderr' => [
63 | 'driver' => 'monolog',
64 | 'handler' => StreamHandler::class,
65 | 'with' => [
66 | 'stream' => 'php://stderr',
67 | ],
68 | ],
69 |
70 | 'syslog' => [
71 | 'driver' => 'syslog',
72 | 'level' => 'debug',
73 | ],
74 |
75 | 'errorlog' => [
76 | 'driver' => 'errorlog',
77 | 'level' => 'debug',
78 | ],
79 | ],
80 |
81 | ];
82 |
--------------------------------------------------------------------------------
/config/services.php:
--------------------------------------------------------------------------------
1 | [
17 | 'domain' => env('MAILGUN_DOMAIN'),
18 | 'secret' => env('MAILGUN_SECRET'),
19 | ],
20 |
21 | 'ses' => [
22 | 'key' => env('SES_KEY'),
23 | 'secret' => env('SES_SECRET'),
24 | 'region' => 'us-east-1',
25 | ],
26 |
27 | 'sparkpost' => [
28 | 'secret' => env('SPARKPOST_SECRET'),
29 | ],
30 |
31 | 'stripe' => [
32 | 'model' => Emtudo\User::class,
33 | 'key' => env('STRIPE_KEY'),
34 | 'secret' => env('STRIPE_SECRET'),
35 | ],
36 | ];
37 |
--------------------------------------------------------------------------------
/config/view.php:
--------------------------------------------------------------------------------
1 | [
16 | resource_path('views'),
17 | ],
18 |
19 | /*
20 | |--------------------------------------------------------------------------
21 | | Compiled View Path
22 | |--------------------------------------------------------------------------
23 | |
24 | | This option determines where all the compiled Blade templates will be
25 | | stored for your application. Typically, this is within the storage
26 | | directory. However, as usual, you are free to change this value.
27 | |
28 | */
29 |
30 | 'compiled' => realpath(storage_path('framework/views')),
31 | ];
32 |
--------------------------------------------------------------------------------
/docker-compose.override-dist.yml:
--------------------------------------------------------------------------------
1 | ###################################################
2 | ### OVERRIDE DEFAULT DOCKER-COMPOSE CONFIG FILE ###
3 | ### SERVICES CAN BE REMOVED IF YOU NOT CHANGING ###
4 | ###################################################
5 |
6 | # CONFIG
7 | version: '2'
8 |
9 | # SERVICES
10 | services:
11 | # APP
12 | app:
13 | ports:
14 | - 80:8080
15 | - 443:8083
16 |
17 | # MAILCATCHER
18 | mailcatcher:
19 | ports:
20 | - 2025:1025
21 | - 2080:1080
22 |
23 | # MYSQL
24 | mysql:
25 | ports:
26 | - 4306:3306
27 | environment:
28 | - MYSQL_ROOT_PASSWORD=emtudo
29 | - MYSQL_DATABASE=emtudo
30 | - MYSQL_USER=emtudo
31 | - MYSQL_PASSWORD=emtudo
32 |
33 | # REDIS
34 | cache:
35 | ports:
36 | - 7379:6379
37 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "scripts": {
4 | "dev": "npm run watch",
5 | "development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
6 | "watch": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
7 | "watch-poll": "npm run watch -- --watch-poll",
8 | "hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js",
9 | "build": "npm run production",
10 | "prod": "npm run production",
11 | "production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
12 | },
13 | "devDependencies": {
14 | "axios": "^0.18",
15 | "babel-core": "^6.26.3",
16 | "babel-eslint": "^8.2.1",
17 | "babel-helper-vue-jsx-merge-props": "^2.0.3",
18 | "babel-loader": "^7.1.1",
19 | "babel-plugin-istanbul": "^4.1.1",
20 | "babel-plugin-syntax-jsx": "^6.18.0",
21 | "babel-plugin-transform-runtime": "^6.22.0",
22 | "babel-plugin-transform-vue-jsx": "^3.5.0",
23 | "babel-preset-env": "^1.7.0",
24 | "babel-preset-stage-2": "^6.22.0",
25 | "babel-register": "^6.22.0",
26 | "bootstrap": "^4.1.1",
27 | "cross-env": "^5.1.5",
28 | "eslint": "^4.19.1",
29 | "eslint-config-standard": "^11.0.0",
30 | "eslint-plugin-import": "^2.11.0",
31 | "eslint-plugin-node": "^6.0.1",
32 | "eslint-plugin-promise": "^3.7.0",
33 | "eslint-plugin-standard": "^3.1.0",
34 | "file-loader": "^1.1.11",
35 | "jquery": "^3.2",
36 | "laravel-mix": "^2.0",
37 | "lodash": "^4.17.10",
38 | "popper.js": "^1.14.3",
39 | "url-loader": "^1.0.1",
40 | "vue": "^2.5.7"
41 | },
42 | "dependencies": {
43 | "babel-eslint": "^8.2.3",
44 | "cpf_cnpj": "^0.2.0",
45 | "eslint-plugin-vue": "^4.5.0",
46 | "izitoast": "^1.3.0",
47 | "localforage": "^1.7.1",
48 | "localstorage": "^1.0.1",
49 | "moment": "^2.22.1",
50 | "node-sass": "^4.9.0",
51 | "pug": "^2.0.3",
52 | "sass-loader": "^7.0.1",
53 | "vue-router": "^3.0.1",
54 | "vuex": "^3.0.1"
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/phpunit.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
13 | ./tests/Feature
14 |
15 |
16 |
17 | ./tests/Unit
18 |
19 |
20 |
21 |
22 | ./app
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/public/.htaccess:
--------------------------------------------------------------------------------
1 |
2 |
3 | Options -MultiViews -Indexes
4 |
5 |
6 | RewriteEngine On
7 |
8 | # Handle Authorization Header
9 | RewriteCond %{HTTP:Authorization} .
10 | RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
11 |
12 | # Redirect Trailing Slashes If Not A Folder...
13 | RewriteCond %{REQUEST_FILENAME} !-d
14 | RewriteCond %{REQUEST_URI} (.+)/$
15 | RewriteRule ^ %1 [L,R=301]
16 |
17 | # Handle Front Controller...
18 | RewriteCond %{REQUEST_FILENAME} !-d
19 | RewriteCond %{REQUEST_FILENAME} !-f
20 | RewriteRule ^ index.php [L]
21 |
22 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/emtudo/laravel-vue/7749adf173fe7305b9d8ddbf682cb9767364d16d/public/favicon.ico
--------------------------------------------------------------------------------
/public/fonts/roboto/Roboto-Bold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/emtudo/laravel-vue/7749adf173fe7305b9d8ddbf682cb9767364d16d/public/fonts/roboto/Roboto-Bold.woff
--------------------------------------------------------------------------------
/public/fonts/roboto/Roboto-Bold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/emtudo/laravel-vue/7749adf173fe7305b9d8ddbf682cb9767364d16d/public/fonts/roboto/Roboto-Bold.woff2
--------------------------------------------------------------------------------
/public/fonts/roboto/Roboto-Light.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/emtudo/laravel-vue/7749adf173fe7305b9d8ddbf682cb9767364d16d/public/fonts/roboto/Roboto-Light.woff
--------------------------------------------------------------------------------
/public/fonts/roboto/Roboto-Light.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/emtudo/laravel-vue/7749adf173fe7305b9d8ddbf682cb9767364d16d/public/fonts/roboto/Roboto-Light.woff2
--------------------------------------------------------------------------------
/public/fonts/roboto/Roboto-Medium.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/emtudo/laravel-vue/7749adf173fe7305b9d8ddbf682cb9767364d16d/public/fonts/roboto/Roboto-Medium.woff
--------------------------------------------------------------------------------
/public/fonts/roboto/Roboto-Medium.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/emtudo/laravel-vue/7749adf173fe7305b9d8ddbf682cb9767364d16d/public/fonts/roboto/Roboto-Medium.woff2
--------------------------------------------------------------------------------
/public/fonts/roboto/Roboto-Regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/emtudo/laravel-vue/7749adf173fe7305b9d8ddbf682cb9767364d16d/public/fonts/roboto/Roboto-Regular.woff
--------------------------------------------------------------------------------
/public/fonts/roboto/Roboto-Regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/emtudo/laravel-vue/7749adf173fe7305b9d8ddbf682cb9767364d16d/public/fonts/roboto/Roboto-Regular.woff2
--------------------------------------------------------------------------------
/public/fonts/roboto/Roboto-Thin.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/emtudo/laravel-vue/7749adf173fe7305b9d8ddbf682cb9767364d16d/public/fonts/roboto/Roboto-Thin.woff
--------------------------------------------------------------------------------
/public/fonts/roboto/Roboto-Thin.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/emtudo/laravel-vue/7749adf173fe7305b9d8ddbf682cb9767364d16d/public/fonts/roboto/Roboto-Thin.woff2
--------------------------------------------------------------------------------
/public/index.php:
--------------------------------------------------------------------------------
1 |
8 | */
9 |
10 | define('LARAVEL_START', microtime(true));
11 |
12 | /*
13 | |--------------------------------------------------------------------------
14 | | Register The Auto Loader
15 | |--------------------------------------------------------------------------
16 | |
17 | | Composer provides a convenient, automatically generated class loader for
18 | | our application. We just need to utilize it! We'll simply require it
19 | | into the script here so that we don't have to worry about manual
20 | | loading any of our classes later on. It feels great to relax.
21 | |
22 | */
23 |
24 | require __DIR__.'/../vendor/autoload.php';
25 |
26 | /*
27 | |--------------------------------------------------------------------------
28 | | Turn On The Lights
29 | |--------------------------------------------------------------------------
30 | |
31 | | We need to illuminate PHP development, so let us turn on the lights.
32 | | This bootstraps the framework and gets it ready for use, then it
33 | | will load up this application so that we can run it and send
34 | | the responses back to the browser and delight our users.
35 | |
36 | */
37 |
38 | $app = require_once __DIR__.'/../bootstrap/app.php';
39 |
40 | /*
41 | |--------------------------------------------------------------------------
42 | | Run The Application
43 | |--------------------------------------------------------------------------
44 | |
45 | | Once we have the application, we can handle the incoming request
46 | | through the kernel, and send the associated response back to
47 | | the client's browser allowing them to enjoy the creative
48 | | and wonderful application we have prepared for them.
49 | |
50 | */
51 |
52 | $kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
53 |
54 | $response = $kernel->handle(
55 | $request = Illuminate\Http\Request::capture()
56 | );
57 |
58 | $response->send();
59 |
60 | $kernel->terminate($request, $response);
61 |
--------------------------------------------------------------------------------
/public/mix-manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "/js/app.js": "/js/app.js",
3 | "/css/app.css": "/css/app.css"
4 | }
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | User-agent: *
2 | Disallow:
3 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # Skeleton Laravel With Vuejs
2 |
3 | ## Dependencies
4 | - php 7.2
5 | - mysql 5.7
6 | - npm
7 | - composer
8 |
9 | ## How to install
10 |
11 | [How to install video In Portugues](https://www.youtube.com/watch?v=Vk-uuq3uuPI)
12 |
13 |
14 | ```shell
15 | composer create-project emtudo/laravel-vue
16 | cd laravel-vue
17 | npm install
18 | php artisan jwt:generate
19 | ```
20 |
21 | Configure the `.env` file after configuring run the command below to create the database:
22 |
23 | ```shell
24 | php artisan migrator
25 | ```
26 |
27 | ## How to test
28 |
29 | At the first terminal
30 | ```shell
31 | php artisan serve
32 | ```
33 |
34 | At the second terminal
35 | ```shell
36 | npm run dev
37 | ```
38 |
39 | ## Admin
40 |
41 | - username: admin@user.com
42 | - password: abc123
43 |
--------------------------------------------------------------------------------
/resources/assets/copy/js/izitoast/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "izitoast",
3 | "description": "Elegant, responsive, flexible and lightweight notification plugin with no dependencies.",
4 | "main": [
5 | "js/iziToast.js",
6 | "css/iziToast.css"
7 | ],
8 | "authors": [
9 | {
10 | "name": "Marcelo Dolce",
11 | "email": "dolcemarcelo@gmail.com",
12 | "homepage": "http://marcelodolce.com"
13 | }
14 | ],
15 | "license": "Apache-2.0",
16 | "keywords": [
17 | "izitoast",
18 | "notification",
19 | "toaster",
20 | "alert",
21 | "confirm",
22 | "js"
23 | ],
24 | "homepage": "http://izitoast.marcelodolce.com",
25 | "ignore": []
26 | }
27 |
--------------------------------------------------------------------------------
/resources/assets/copy/js/izitoast/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "_args": [
3 | [
4 | {
5 | "raw": "izitoast",
6 | "scope": null,
7 | "escapedName": "izitoast",
8 | "name": "izitoast",
9 | "rawSpec": "",
10 | "spec": "latest",
11 | "type": "tag"
12 | },
13 | "/second/home/leandro/www/result.systems/spa"
14 | ]
15 | ],
16 | "_from": "izitoast@latest",
17 | "_id": "izitoast@1.0.2-c",
18 | "_inCache": true,
19 | "_location": "/izitoast",
20 | "_nodeVersion": "4.0.0",
21 | "_npmOperationalInternal": {
22 | "host": "packages-12-west.internal.npmjs.com",
23 | "tmp": "tmp/izitoast-1.0.2-c.tgz_1480810506962_0.5749450342264026"
24 | },
25 | "_npmUser": {
26 | "name": "dolce",
27 | "email": "dolcemarcelo@gmail.com"
28 | },
29 | "_npmVersion": "2.14.2",
30 | "_phantomChildren": {},
31 | "_requested": {
32 | "raw": "izitoast",
33 | "scope": null,
34 | "escapedName": "izitoast",
35 | "name": "izitoast",
36 | "rawSpec": "",
37 | "spec": "latest",
38 | "type": "tag"
39 | },
40 | "_requiredBy": [
41 | "#USER",
42 | "/"
43 | ],
44 | "_resolved": "https://registry.npmjs.org/izitoast/-/izitoast-1.0.2-c.tgz",
45 | "_shasum": "493cf0ead2eae7a10097ed2e9b9bf9cd2ab22cda",
46 | "_shrinkwrap": null,
47 | "_spec": "izitoast",
48 | "_where": "/second/home/leandro/www/result.systems/spa",
49 | "author": {
50 | "name": "Marcelo Dolce",
51 | "email": "dolcemarcelo@gmail.com"
52 | },
53 | "bugs": {
54 | "url": "https://github.com/dolce/iziToast/issues"
55 | },
56 | "dependencies": {},
57 | "description": "Elegant, responsive, flexible and lightweight notification plugin with no dependencies.",
58 | "devDependencies": {},
59 | "directories": {},
60 | "dist": {
61 | "shasum": "493cf0ead2eae7a10097ed2e9b9bf9cd2ab22cda",
62 | "tarball": "https://registry.npmjs.org/izitoast/-/izitoast-1.0.2-c.tgz"
63 | },
64 | "gitHead": "d81554e6ff4c835c634aa061318bfce79fb6692b",
65 | "homepage": "https://github.com/dolce/iziToast#readme",
66 | "keywords": [
67 | "izitoast",
68 | "notification",
69 | "toaster",
70 | "alert",
71 | "confirm",
72 | "js"
73 | ],
74 | "license": "Apache-2.0",
75 | "main": "dist/js/iziToast.js",
76 | "maintainers": [
77 | {
78 | "name": "dolce",
79 | "email": "dolcemarcelo@gmail.com"
80 | }
81 | ],
82 | "name": "izitoast",
83 | "optionalDependencies": {},
84 | "readme": "ERROR: No README data found!",
85 | "repository": {
86 | "type": "git",
87 | "url": "git+https://github.com/dolce/iziToast.git"
88 | },
89 | "scripts": {},
90 | "version": "1.0.2-c"
91 | }
92 |
--------------------------------------------------------------------------------
/resources/assets/copy/js/izitoast/src/css/layouts.styl:
--------------------------------------------------------------------------------
1 | /*
2 | * iziToast | v1.0.2
3 | * http://izitoast.marcelodolce.com
4 | * by Marcelo Dolce.
5 | */
6 |
7 | .iziToast
8 |
9 | &.iziToast-layout2
10 | & .iziToast-body > p
11 | width 100%
12 |
13 | /*
14 | * EXAMPLE new layouts
15 | *
16 | &.iziToast-layout3
17 | margin 20px
18 | */
--------------------------------------------------------------------------------
/resources/assets/copy/js/izitoast/src/css/style.styl:
--------------------------------------------------------------------------------
1 | /*
2 | * iziToast | v1.0.2
3 | * http://izitoast.marcelodolce.com
4 | * by Marcelo Dolce.
5 | */
6 |
7 |
8 | $font-family = 'Lato', arial
9 | $animation-time1 = 0.7s
10 | $animation-time2 = 0.85s
11 | $animation-time3 = 1s
12 |
13 |
14 | @import 'toast'
15 | @import 'themes'
16 | @import 'layouts'
17 | @import 'animations'
--------------------------------------------------------------------------------
/resources/assets/copy/js/izitoast/src/css/themes.styl:
--------------------------------------------------------------------------------
1 | /*
2 | * iziToast | v1.0.2
3 | * http://izitoast.marcelodolce.com
4 | * by Marcelo Dolce.
5 | */
6 |
7 | .iziToast
8 | &.iziToast-color-dark
9 | background #565C70
10 | border-color #565C70
11 | & strong
12 | color white
13 | & p
14 | color rgba(255, 255, 255, 0.7)
15 | font-weight 300
16 | & .iziToast-close
17 | background url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAQAAADZc7J/AAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAAmJLR0QAAKqNIzIAAAAJcEhZcwAADdcAAA3XAUIom3gAAAAHdElNRQfgCR4OIQIPSao6AAAAwElEQVRIx72VUQ6EIAwFmz2XB+AConhjzqTJ7JeGKhLYlyx/BGdoBVpjIpMJNjgIZDKTkQHYmYfwmR2AfAqGFBcO2QjXZCd24bEggvd1KBx+xlwoDpYmvnBUUy68DYXD77ESr8WDtYqvxRex7a8oHP4Wo1Mkt5I68Mc+qYqv1h5OsZmZsQ3gj/02h6cO/KEYx29hu3R+VTTwz6D3TymIP1E8RvEiiVdZfEzicxYLiljSxKIqlnW5seitTW6uYnv/Aqh4whX3mEUrAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE2LTA5LTMwVDE0OjMzOjAyKzAyOjAwl6RMVgAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxNi0wOS0zMFQxNDozMzowMiswMjowMOb59OoAAAAZdEVYdFNvZnR3YXJlAHd3dy5pbmtzY2FwZS5vcmeb7jwaAAAAAElFTkSuQmCC') no-repeat 50% 50%
18 | background-size 8px
19 | & .iziToast-icon
20 | color white
21 | & strong
22 | font-weight 500
23 | & .iziToast-buttons button, & .iziToast-buttons a
24 | color rgb(255, 255, 255)
25 | background rgba(255, 255, 255, 0.1)
26 | &:hover
27 | background rgba(255, 255, 255, 0.2)
28 |
29 | &.iziToast-color-red
30 | background rgba(243, 186, 189, 0.85)
31 | border-color rgba(243, 186, 189, 0.85)
32 | &.iziToast-color-yellow
33 | background rgba(243, 237, 172, 0.85)
34 | border-color rgba(243, 237, 172, 0.85)
35 | &.iziToast-color-blue
36 | background rgba(181, 225, 249, 0.85)
37 | border-color rgba(181, 225, 249, 0.85)
38 | &.iziToast-color-green
39 | background rgba(180, 241, 196, 0.85)
40 | border-color rgba(180, 241, 196, 0.85)
41 |
42 | /*
43 | * EXAMPLE new colors
44 | *
45 | &.iziToast-color-custom
46 | */
47 |
48 |
49 | @media only screen and (min-width: 568px)
50 |
51 | .iziToast
52 | &.iziToast-color-dark
53 | &::after
54 | box-shadow inset 0 -10px 20px -10px rgba(255, 255, 255, 0.3),0 10px 10px -5px rgba(0, 0, 0, 0.25)
--------------------------------------------------------------------------------
/resources/assets/js/app/auth/index.js:
--------------------------------------------------------------------------------
1 | export { default as routes } from './routes'
2 | export { default as store } from './store'
3 |
--------------------------------------------------------------------------------
/resources/assets/js/app/auth/login/two-factor.vue:
--------------------------------------------------------------------------------
1 |
64 |
65 |
66 |
67 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/resources/assets/js/app/auth/register/register.vue:
--------------------------------------------------------------------------------
1 |
59 |
--------------------------------------------------------------------------------
/resources/assets/js/app/auth/reset/email.vue:
--------------------------------------------------------------------------------
1 |
40 |
41 |
42 |
43 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/resources/assets/js/app/auth/reset/password.vue:
--------------------------------------------------------------------------------
1 |
63 |
64 |
65 |
66 |
83 |
84 |
85 |
--------------------------------------------------------------------------------
/resources/assets/js/app/auth/routes.js:
--------------------------------------------------------------------------------
1 | import { route, meta } from '@/helpers/routes'
2 | import ResetEmail from './reset/email'
3 | import ResetPassword from './reset/password'
4 | import Login from './login/login'
5 | import TwoFactor from './login/two-factor'
6 | import Register from './register/register'
7 |
8 | export default [
9 | route('auth.login', '/auth/login', Login, meta('Login', false, false)),
10 | route('auth.register', '/auth/register', Register, meta('Registrar usuário', false, false)),
11 | route('auth.password.email', '/auth/password/email', ResetEmail, meta('Recuperar senha', false, false)),
12 | route('auth.password.reset', '/auth/password/reset/:token', ResetPassword, meta('Recuperar senha', false, false)),
13 | route('auth.two_factor', '/auth/two_factor', TwoFactor, meta('Ativar Two Factor', true, false))
14 | ]
15 |
--------------------------------------------------------------------------------
/resources/assets/js/app/auth/store.js:
--------------------------------------------------------------------------------
1 | const modules = {
2 | }
3 |
4 | /**
5 | * Export store resources.
6 | */
7 | export default {
8 | namespaced: true,
9 | modules
10 | }
11 |
--------------------------------------------------------------------------------
/resources/assets/js/app/home/index.js:
--------------------------------------------------------------------------------
1 | export { default as routes } from './routes'
2 | export { default as store } from './store'
3 |
--------------------------------------------------------------------------------
/resources/assets/js/app/home/index/index.vue:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 |
15 |
16 | Emtudo Skeleton
17 |
18 |
19 | Bem vindo, {{ userFirstName }}!
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/resources/assets/js/app/home/routes.js:
--------------------------------------------------------------------------------
1 | import Index from './index/index'
2 | import { route, metaForceSetupUser } from '@/helpers/routes'
3 |
4 | export default [
5 | route('home', '/', Index, metaForceSetupUser('Home', false, false))
6 | ]
7 |
--------------------------------------------------------------------------------
/resources/assets/js/app/home/store.js:
--------------------------------------------------------------------------------
1 | const modules = {
2 | }
3 |
4 | /**
5 | * Export store resources.
6 | */
7 | export default {
8 | namespaced: true,
9 | modules
10 | }
11 |
--------------------------------------------------------------------------------
/resources/assets/js/app/home/store/actions.js:
--------------------------------------------------------------------------------
1 | export default {
2 | action: ({commit}, value = null) => {
3 | commit('setAction', value)
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/resources/assets/js/app/home/store/getters.js:
--------------------------------------------------------------------------------
1 | export const example = ({ example }) => example
2 |
--------------------------------------------------------------------------------
/resources/assets/js/app/home/store/index.js:
--------------------------------------------------------------------------------
1 | import * as getters from './getters' // getters.
2 | import state from './state' // state.
3 | import actions from './actions' // actions.
4 | import mutations from './mutations' // mutations.
5 |
6 | /**
7 | * Export store resources.
8 | */
9 | export default {
10 | namespaced: true, // make sure the module store gets it's own namespace.
11 | state,
12 | actions,
13 | getters,
14 | mutations
15 | }
16 |
--------------------------------------------------------------------------------
/resources/assets/js/app/home/store/mutations.js:
--------------------------------------------------------------------------------
1 | export default {
2 | setAction (state, value) {
3 | state.action = value
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/resources/assets/js/app/home/store/state.js:
--------------------------------------------------------------------------------
1 | export default {
2 | action: null
3 | }
4 |
--------------------------------------------------------------------------------
/resources/assets/js/app/index.js:
--------------------------------------------------------------------------------
1 | export { default as routes } from './routes'
2 | export { default as store } from './store'
3 |
--------------------------------------------------------------------------------
/resources/assets/js/app/perfil/index.js:
--------------------------------------------------------------------------------
1 | export { default as routes } from './routes'
2 | export { default as store } from './store'
3 |
--------------------------------------------------------------------------------
/resources/assets/js/app/perfil/me.vue:
--------------------------------------------------------------------------------
1 |
53 |
--------------------------------------------------------------------------------
/resources/assets/js/app/perfil/routes.js:
--------------------------------------------------------------------------------
1 | import Me from './me'
2 | import { route, meta } from '@/helpers/routes'
3 |
4 | export default [
5 | route('perfil', '/perfil', Me, meta('Profile'))
6 | ]
7 |
--------------------------------------------------------------------------------
/resources/assets/js/app/perfil/store.js:
--------------------------------------------------------------------------------
1 | const modules = {
2 | }
3 |
4 | /**
5 | * Export store resources.
6 | */
7 | export default {
8 | namespaced: true,
9 | modules
10 | }
11 |
--------------------------------------------------------------------------------
/resources/assets/js/app/routes.js:
--------------------------------------------------------------------------------
1 | import { routes as auth } from './auth'
2 | import { routes as home } from './home'
3 | import { routes as perfil } from './perfil'
4 | import { routes as users } from './users'
5 |
6 | export default [
7 | ...auth,
8 | ...home,
9 | ...perfil,
10 | ...users
11 | ]
12 |
--------------------------------------------------------------------------------
/resources/assets/js/app/store.js:
--------------------------------------------------------------------------------
1 | import { store as users } from './users'
2 |
3 | const modules = {
4 | users
5 | }
6 |
7 | export default {
8 | namespaced: true,
9 | modules
10 | }
11 |
--------------------------------------------------------------------------------
/resources/assets/js/app/users/helpers/index.js:
--------------------------------------------------------------------------------
1 | import { get } from 'lodash'
2 |
3 | export const status = user => {
4 | const deleted = get(user, 'deleted_at', null)
5 | if (deleted) {
6 | return 'Suspenso'
7 | }
8 |
9 | return 'Ativado'
10 | }
11 |
12 | export const prepareShow = user => {
13 | user._parsed = {
14 | status: status(user)
15 | }
16 |
17 | return user
18 | }
19 |
--------------------------------------------------------------------------------
/resources/assets/js/app/users/index.js:
--------------------------------------------------------------------------------
1 | export { default as routes } from './routes'
2 | export { default as store } from './store/index'
3 |
--------------------------------------------------------------------------------
/resources/assets/js/app/users/index/search.vue:
--------------------------------------------------------------------------------
1 |
38 |
39 |
40 |
80 |
81 |
--------------------------------------------------------------------------------
/resources/assets/js/app/users/routes.js:
--------------------------------------------------------------------------------
1 | import { groupAdmin, route, meta } from '@/helpers/routes'
2 | import Index from './index/index'
3 | import Form from './form/form'
4 |
5 | export default [
6 | ...groupAdmin('/users', [
7 | route('index', '/', Index, meta('Lista de usuário')),
8 | route('create', '/create', Form, meta('Adicionar novo usuário')),
9 | route('edit', '/:id/edit', Form, meta('Editar usuário'))
10 | ])
11 | ]
12 |
--------------------------------------------------------------------------------
/resources/assets/js/app/users/services/index.js:
--------------------------------------------------------------------------------
1 | export { default as sort } from './sort'
2 |
--------------------------------------------------------------------------------
/resources/assets/js/app/users/services/sort.js:
--------------------------------------------------------------------------------
1 | // dependencies.
2 | import { flow, filter, orderBy } from 'lodash/fp'
3 |
4 | import { matchesAny } from '@/helpers/text/match'
5 |
6 | // Sort users based on filters and sort settings.
7 | export default (users, { filters }, { column, direction }) => {
8 | // do filter & sort
9 | return flow(
10 | filter((user) => matchesAny(user, filters)), // multiple field search
11 | orderBy([column], [direction]) // sort / order by a given column in a given direction
12 | )(users) // apply users as data on the flow.
13 | }
14 |
--------------------------------------------------------------------------------
/resources/assets/js/app/users/store/getters.js:
--------------------------------------------------------------------------------
1 | import { sort as doSort } from '../services'
2 | // import { filter } from 'lodash'
3 |
4 | export const errors = ({ errors }) => errors
5 | export const currentUser = ({ user }) => user
6 | export const users = ({ users }) => users
7 | export const loading = ({ loading }) => loading
8 | export const saving = ({ saving }) => saving
9 | export const filteredUsers = ({ users }) => {
10 | return users
11 | }
12 | export const sortedUsers = ({ users, filters, sort }) => doSort(filteredUsers({users}), filters, sort)
13 | export const search = ({ search }) => search
14 | export const filters = ({ filters }) => filters
15 | export const resourcePath = ({ resourcePath }) => resourcePath
16 | export const resourcePathProfile = ({ resourcePathProfile }) => resourcePathProfile
17 |
--------------------------------------------------------------------------------
/resources/assets/js/app/users/store/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Users module vuex store.
3 | */
4 |
5 | import * as getters from './getters' // getters.
6 | import state from './state' // state.
7 | import actions from './actions' // actions.
8 | import mutations from './mutations' // mutations.
9 |
10 | /**
11 | * Export store resources.
12 | */
13 | export default {
14 | namespaced: true, // make sure the module store gets it's own namespace.
15 | state,
16 | actions,
17 | getters,
18 | mutations
19 | }
20 |
--------------------------------------------------------------------------------
/resources/assets/js/app/users/store/mutations.js:
--------------------------------------------------------------------------------
1 | import { find } from 'lodash'
2 | import { prepareShow } from '../helpers'
3 |
4 | const addUser = (state, user) => {
5 | const users = state.users
6 | users.push(user)
7 | state.users = [...users]
8 | }
9 |
10 | const updateUser = (state, user, current) => {
11 | const users = state.users
12 | const index = users.indexOf(current)
13 |
14 | users[index] = user
15 |
16 | state.users = [...users]
17 | }
18 |
19 | export default {
20 | setErrors (state, values) {
21 | state.errors = values
22 | },
23 | setCurrentUser (state, value) {
24 | state.user = value
25 | },
26 | setUsers (state, values) {
27 | state.users = values.map(prepareShow)
28 | },
29 | setSearch (state, values) {
30 | state.search = {
31 | name: null,
32 | email: null,
33 | is_admin: null,
34 | trashed: null,
35 | ...values
36 | }
37 | },
38 | setFilters (state, values) {
39 | state.filters = values
40 | },
41 | setLoading (state, value) {
42 | state.loading = value
43 | },
44 | setSaving (state, value) {
45 | state.saving = value
46 | },
47 | updateUser (state, user) {
48 | const current = find(state.users, {id: user.id})
49 | if (current) {
50 | return updateUser(state, prepareShow(user), current)
51 | }
52 | return addUser(state, prepareShow(user))
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/resources/assets/js/app/users/store/state.js:
--------------------------------------------------------------------------------
1 | export default {
2 | resourcePath: 'admin/users/users/',
3 | resourcePathProfile: 'user/users/profile',
4 |
5 | /**
6 | * @type {Bool}
7 | */
8 | saving: false,
9 |
10 | /**
11 | * @type {Bool}
12 | */
13 | loading: false,
14 |
15 | /**
16 | * @type {Array}
17 | */
18 | users: [],
19 |
20 | /**
21 | * @type {Object}
22 | */
23 | errors: {},
24 |
25 | /**
26 | * @type {Object}
27 | */
28 | search: {
29 | name: null,
30 | email: null,
31 | is_admin: null,
32 | trashed: null
33 | },
34 |
35 | /**
36 | * @type {Object}
37 | */
38 | filters: {
39 | },
40 |
41 | /**
42 | * @type {Object}
43 | */
44 | sort: {
45 | column: 'name', // default sort column.
46 | direction: 'asc' // default sort direction.
47 | },
48 |
49 | /**
50 | * @type {Object}
51 | */
52 | currentUser: {
53 | name: null,
54 | email: null,
55 | is_admin: false,
56 | password: null,
57 | password_confirmation: null
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/resources/assets/js/bootstrap.js:
--------------------------------------------------------------------------------
1 | window._ = require('lodash')
2 | window.Popper = require('popper.js').default
3 |
4 | /**
5 | * We'll load jQuery and the Bootstrap jQuery plugin which provides support
6 | * for JavaScript based Bootstrap features such as modals and tabs. This
7 | * code may be modified to fit the specific needs of your application.
8 | */
9 |
10 | try {
11 | window.$ = window.jQuery = require('jquery')
12 |
13 | require('bootstrap')
14 | } catch (e) {}
15 |
--------------------------------------------------------------------------------
/resources/assets/js/components/Helpers/error.vue:
--------------------------------------------------------------------------------
1 |
15 |
16 |
17 | span.invalid-feedback
18 | strong(v-if="!isSeveral") {{ message }}
19 | strong(v-if="isSeveral") {{ message[0] }}
20 |
21 |
--------------------------------------------------------------------------------
/resources/assets/js/components/alerts/alerts.vue:
--------------------------------------------------------------------------------
1 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/resources/assets/js/components/contacts/contacts.vue:
--------------------------------------------------------------------------------
1 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/resources/assets/js/components/countdown/countdown.vue:
--------------------------------------------------------------------------------
1 |
42 |
43 |
44 | span(v-if="time>0")
45 | | {{ current }}
46 |
47 |
--------------------------------------------------------------------------------
/resources/assets/js/components/form/index.js:
--------------------------------------------------------------------------------
1 | export default (Vue) => {
2 | Vue.component('f-text', () => import('./text'))
3 | }
4 |
--------------------------------------------------------------------------------
/resources/assets/js/components/form/text.vue:
--------------------------------------------------------------------------------
1 |
93 |
94 |
95 | div(:class="className")
96 | label.form-label.text-md-right(:for="name")
97 | template(v-if="value")
98 | | {{ label }}
99 | template(v-if="!value")
100 | |
101 | input.form-control(
102 | :disabled="disabled",
103 | :placeholder="placeholder || label",
104 | :type="type",
105 | :name="name",
106 | :id="name",
107 | :maxlength="maxlength",
108 | :class="{'is-invalid': error}"
109 | :value="value",
110 | :required="required",
111 | @input="updateValue")
112 | error(:message="error")
113 |
114 |
--------------------------------------------------------------------------------
/resources/assets/js/components/index.js:
--------------------------------------------------------------------------------
1 | import Form from './form'
2 | import Masked from './masked'
3 |
4 | export default (Vue) => {
5 | Form(Vue)
6 | Masked(Vue)
7 | Vue.component('alerts', () => import('./alerts/alerts'))
8 | Vue.component('countdown', () => import('./countdown/countdown'))
9 | Vue.component('page', () => import('./page/page'))
10 | }
11 |
--------------------------------------------------------------------------------
/resources/assets/js/components/masked/date/date.vue:
--------------------------------------------------------------------------------
1 |
43 |
44 |
45 | div(:class="{invalid: errors}")
46 | input.form-control(
47 | :id="fieldId",
48 | :placeholder="placeholder || label",
49 | type="text",
50 | @keydown="keydown",
51 | @keyup="keyup",
52 | @change="change",
53 | v-model="valueInput",
54 | :maxlength="maxlength"
55 | )
56 | error(:message="errors")
57 |
58 |
59 |
64 |
--------------------------------------------------------------------------------
/resources/assets/js/components/masked/document/document-cnpj.vue:
--------------------------------------------------------------------------------
1 |
30 |
--------------------------------------------------------------------------------
/resources/assets/js/components/masked/document/document-cpf.vue:
--------------------------------------------------------------------------------
1 |
34 |
--------------------------------------------------------------------------------
/resources/assets/js/components/masked/index.js:
--------------------------------------------------------------------------------
1 | export default (Vue) => {
2 | Vue.component('f-number', () => import('./number/number'))
3 | Vue.component('f-date', () => import('./date/date'))
4 | Vue.component('f-cnpj', () => import('./document/document-cnpj'))
5 | Vue.component('f-cpf', () => import('./document/document-cpf'))
6 | Vue.component('f-zip', () => import('./zip/zip'))
7 | Vue.component('f-mobile', () => import('./phone/mobile'))
8 | Vue.component('f-phone', () => import('./phone/phone'))
9 | Vue.component('f-landline', () => import('./phone/landline'))
10 | }
11 |
--------------------------------------------------------------------------------
/resources/assets/js/components/masked/number/number.vue:
--------------------------------------------------------------------------------
1 |
24 |
--------------------------------------------------------------------------------
/resources/assets/js/components/masked/phone/landline.vue:
--------------------------------------------------------------------------------
1 |
28 |
--------------------------------------------------------------------------------
/resources/assets/js/components/masked/phone/mobile.vue:
--------------------------------------------------------------------------------
1 |
38 |
--------------------------------------------------------------------------------
/resources/assets/js/components/masked/phone/phone.vue:
--------------------------------------------------------------------------------
1 |
33 |
--------------------------------------------------------------------------------
/resources/assets/js/components/masked/zip/zip.vue:
--------------------------------------------------------------------------------
1 |
62 |
--------------------------------------------------------------------------------
/resources/assets/js/components/page/page.vue:
--------------------------------------------------------------------------------
1 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/resources/assets/js/directives/helpers.js:
--------------------------------------------------------------------------------
1 | import ucfirst from '@/helpers/ucfirst'
2 |
3 | export const datasetValue = (el, binding) => {
4 | const name = 'v' + ucfirst(binding.name)
5 | const value = el.dataset[name]
6 | if (!value) {
7 | return null
8 | }
9 |
10 | return value
11 | }
12 |
13 | export const isExecute = (el, binding) => {
14 | const value = datasetValue(el, binding)
15 | if (!value) {
16 | return true
17 | }
18 |
19 | return JSON.parse(value || false)
20 | }
21 |
22 | export const run = function (el, binding) {
23 | if (isExecute(el, binding)) {
24 | const name = binding.name
25 |
26 | el[name]()
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/resources/assets/js/directives/index.js:
--------------------------------------------------------------------------------
1 | import { run as inserted, run as update } from './helpers'
2 | import visible from './visible'
3 |
4 | /**
5 | * Export / install custom directives.
6 | *
7 | * @param Vue
8 | */
9 | export default (Vue) => {
10 | /**
11 | * How to use focus, select, visible:
12 | * v-select or:
13 | * v-select :data-v-select="true"
14 | *
15 | * v-focus or:
16 | * v-focus :data-v-focus="1 === 0"
17 | *
18 | * v-visible or:
19 | * v-visible data-v-visible="true"
20 | */
21 | Vue.directive('focus', {inserted, update})
22 | Vue.directive('select', {inserted, update})
23 | Vue.directive('visible', visible)
24 | }
25 |
--------------------------------------------------------------------------------
/resources/assets/js/directives/visible.js:
--------------------------------------------------------------------------------
1 | import { isExecute } from './helpers'
2 |
3 | /**
4 | * Bind display style into an element (block/none).
5 | *
6 | * @param el
7 | * @param binding
8 | */
9 | export default (el, binding) => {
10 | const value = isExecute(el, binding)
11 |
12 | const visible = value ? 'visible' : 'hidden'
13 |
14 | el.style.visibility = visible
15 | }
16 |
--------------------------------------------------------------------------------
/resources/assets/js/eventBus.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 |
3 | const bus = new Vue()
4 |
5 | export default bus
6 |
--------------------------------------------------------------------------------
/resources/assets/js/filters/countryRegister.js:
--------------------------------------------------------------------------------
1 | // dependencies.
2 | import { toString } from 'lodash'
3 | import { CPF, CNPJ } from 'cpf_cnpj'
4 |
5 | // Format document to person
6 | const person = document => CPF.format(document)
7 |
8 | // Format documento to company
9 | const company = document => CNPJ.format(document)
10 |
11 | // strip special chars.
12 | const strip = document => CNPJ.strip(document)
13 |
14 | /**
15 | * Returns a formatted version a country register document. (CPF / CNPJ).
16 | *
17 | * Format document
18 | **/
19 | export default (original) => {
20 | // bypass formatting if no value was passed.
21 | if (original === null) { return original }
22 |
23 | // get digits only.
24 | const document = strip(toString(original))
25 |
26 | // returns a formatted version of the document.
27 | return document.length > 11 ? company(document) : person(document)
28 | }
29 |
--------------------------------------------------------------------------------
/resources/assets/js/filters/get.js:
--------------------------------------------------------------------------------
1 | // dependencies.
2 | import { get } from 'lodash'
3 |
4 | export default (value, key = null, defaultValue = null) => {
5 | return get(value, key, defaultValue)
6 | }
7 |
--------------------------------------------------------------------------------
/resources/assets/js/filters/index.js:
--------------------------------------------------------------------------------
1 | // dependencies.
2 | import countryRegister from './countryRegister'
3 | import phone from './phone'
4 | import get from './get'
5 | import showDate from './showDate'
6 |
7 | /**
8 | * Export / install filters.
9 | * @param Vue
10 | */
11 | export default (Vue) => {
12 | Vue.filter('countryRegister', countryRegister)
13 | Vue.filter('phone', phone)
14 | Vue.filter('get', get)
15 | Vue.filter('showDate', showDate)
16 | }
17 |
--------------------------------------------------------------------------------
/resources/assets/js/filters/phone.js:
--------------------------------------------------------------------------------
1 | // dependencies.
2 | import { format } from '@/helpers/format'
3 |
4 | const defaultMask = [
5 | {
6 | min: 11,
7 | max: 11,
8 | mask: '## # ####-####'
9 | },
10 | {
11 | min: 10,
12 | max: 10,
13 | mask: '## ####-####'
14 | }
15 | ]
16 |
17 | export default (phone, mask = defaultMask) => {
18 | return format(phone, mask)
19 | }
20 |
--------------------------------------------------------------------------------
/resources/assets/js/filters/showDate.js:
--------------------------------------------------------------------------------
1 | // dependencies.
2 | import moment from 'moment'
3 |
4 | export default (date, format = 'DD/MM/YYYY', original = 'YYYY/MM/DD') => {
5 | if (date === null) {
6 | return date
7 | }
8 |
9 | return moment(date, original).format(format)
10 | }
11 |
--------------------------------------------------------------------------------
/resources/assets/js/helpers/clean.js:
--------------------------------------------------------------------------------
1 | import { isEmpty } from 'lodash'
2 |
3 | const patternOnlyNumber = /[^0-9]+/g
4 |
5 | export const replace = (value, pattern, replacement = '') => {
6 | if (value === null) {
7 | return
8 | }
9 |
10 | return value.replace(pattern, replacement)
11 | }
12 | export const onlyNumbers = value => replace(value, patternOnlyNumber)
13 |
14 | export const pickAndClean = (item, fields = [], initialData = {}, pattern = patternOnlyNumber) => {
15 | if (isEmpty(item)) {
16 | return item
17 | }
18 |
19 | return fields.reduce((acc, key) => {
20 | if (!isEmpty(item[key])) {
21 | return Object.assign({}, acc, {
22 | // está definindo um valor a parti da chave {key}
23 | [key]: replace(item[key], pattern)
24 | })
25 | }
26 |
27 | return acc
28 | }, initialData)
29 | }
30 |
31 | export const cleanProps = (item, fields = [], pattern = patternOnlyNumber) => {
32 | return pickAndClean(item, fields, item, pattern)
33 | }
34 |
--------------------------------------------------------------------------------
/resources/assets/js/helpers/dates.js:
--------------------------------------------------------------------------------
1 | import moment from 'moment'
2 |
3 | export const dateToShow = date => {
4 | return moment(date).format('DD/MM/YYYY')
5 | }
6 |
7 | export const dateToMysql = date => {
8 | return moment(date, 'DD/MM/YYYY').format('YYYY-MM-DD')
9 | }
10 |
--------------------------------------------------------------------------------
/resources/assets/js/helpers/format.js:
--------------------------------------------------------------------------------
1 | const isInvalidItem = (item) => {
2 | if (typeof (item) === 'undefined' || typeof (item.min) === 'undefined' || typeof (item.max) === 'undefined') {
3 | return true
4 | }
5 |
6 | return false
7 | }
8 |
9 | export const getMask = (mask, data) => {
10 | if (!Array.isArray(mask)) {
11 | return mask
12 | }
13 |
14 | if (typeof (data) === 'undefined' || data === null) {
15 | return mask[0].mask
16 | }
17 |
18 | return mask.reduce((standard, item) => {
19 | if (isInvalidItem(item)) {
20 | return standard
21 | }
22 |
23 | if (data.length >= item.min && data.length <= item.max) {
24 | return item.mask
25 | }
26 |
27 | return standard
28 | }, mask[0].mask)
29 | }
30 |
31 | export const format = (data, mask) => {
32 | if (data === null) {
33 | return data
34 | }
35 |
36 | /**
37 | * Simple format function borrowed from vue-mask
38 | * {@link https://github.com/probil/v-mask/blob/master/src/format.js}
39 | *
40 | * @param {String} data String to mask (input value)
41 | * @param {String|Array} [mask] Mask format, like `####-##` or [{mask: '####-##'}, {min: 1, max: 5, mask: '#####'}]
42 | * @returns {string} Formatted text
43 | */
44 |
45 | // don't do anything if mask is undefined/null/etc
46 | if (!mask) {
47 | return data
48 | }
49 | mask = getMask(mask, data)
50 |
51 | const maskStartRegExp = /^([^#ANX]+)/
52 |
53 | if (data.length === 1 && maskStartRegExp.test(mask)) {
54 | data = maskStartRegExp.exec(mask)[0] + data
55 | }
56 |
57 | let text = ''
58 | for (let i = 0, x = 1; x && i < mask.length; ++i) {
59 | let c = data.charAt(i)
60 | let m = mask.charAt(i)
61 |
62 | switch (m) {
63 | case '#' : if (/\d/.test(c)) { text += c } else { x = 0 } break
64 | case 'A' : if (/[a-z]/i.test(c)) { text += c } else { x = 0 } break
65 | case 'N' : if (/[a-z0-9]/i.test(c)) { text += c } else { x = 0 } break
66 | case 'X' : text += c; break
67 | default :
68 | if (i < data.length) {
69 | text += m
70 | }
71 |
72 | // preserve characters that are in the same spot we need to insert a mask
73 | // character by shifting the data over to the right (issue #5, & #7)
74 | if (c && c !== m) {
75 | data = ' ' + data
76 | }
77 |
78 | break
79 | }
80 | }
81 |
82 | return text
83 | }
84 |
--------------------------------------------------------------------------------
/resources/assets/js/helpers/isMobile.js:
--------------------------------------------------------------------------------
1 | export default () => {
2 | try {
3 | return ('ontouchstart' in window)
4 | } catch (e) {
5 | return false
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/resources/assets/js/helpers/jwt/parser.js:
--------------------------------------------------------------------------------
1 | // import { isEmpty } from 'lodash'
2 | import { storeOrRetrieve } from './storage'
3 | import sessionStorage from '@/helpers/sessionStorage'
4 | import { http } from '@/plugins/http'
5 | import { refreshable, expired, factory } from './utils'
6 |
7 | /**
8 | * Method that loads the JWT from local storage.
9 | * @returns {Promise}
10 | */
11 | // export const loadTokenFromLocalStorage = () => {
12 | // const token = storage.retrieve()
13 | //
14 | // return expired(token) ? null : token
15 | // }
16 |
17 | export const refreshToken = token => {
18 | // if not expired, no need for refresh.
19 | if (!expired(token)) { return Promise.resolve(token) }
20 | // if expired but after refresh limit, just reject.
21 | if (!refreshable(token)) {
22 | sessionStorage.remove('token')
23 | sessionStorage.remove('user')
24 |
25 | return Promise.reject(new Error('TOKEN_NOT_REFRESHABLE'))
26 | }
27 |
28 | // otherwise, made the refresh request.
29 | return http.post('/auth/refresh', { token: token.token })
30 | .then(({ data }) => Promise.resolve(storeOrRetrieve(factory(data.token))))
31 | }
32 |
33 | export const loadToken = (tokenString = null) => {
34 | // create a token variable
35 | return storeOrRetrieve(tokenString ? factory(tokenString) : null)
36 | .then(token => refreshToken(token))
37 | }
38 |
39 | // export default loadToken
40 |
--------------------------------------------------------------------------------
/resources/assets/js/helpers/jwt/storage.js:
--------------------------------------------------------------------------------
1 | // dependencies.
2 | // import { factory } from './utils'
3 | import { isEmpty } from 'lodash'
4 | import { get, set } from '@/helpers/storage'
5 |
6 | /**
7 | * Retrieve the token from browser storage.
8 | */
9 | export const retrieve = () => get('jwt-token') // .then(value => factory(value, true))
10 |
11 | /**
12 | * Store the token into browser storage.
13 | *
14 | * @param token
15 | */
16 | export const store = token => {
17 | return set('jwt-token', token) // .then((token) => factory(token, true))
18 | }
19 |
20 | /**
21 | * Store or retrieve a token from browser storage.
22 | *
23 | * @param token
24 | */
25 | export const storeOrRetrieve = (token = null) => {
26 | if (isEmpty(token)) {
27 | return retrieve()
28 | } else {
29 | console.log('isNotEmpty(token)', token)
30 | return store(token)
31 | }
32 | }
33 |
34 | /**
35 | * Default export.
36 | */
37 | export default {
38 | store,
39 | retrieve,
40 | storeOrRetrieve
41 | }
42 |
--------------------------------------------------------------------------------
/resources/assets/js/helpers/jwt/utils.js:
--------------------------------------------------------------------------------
1 | import jwtDecode from 'jwt-decode'
2 | import moment from 'moment'
3 | import { isEmpty, get } from 'lodash'
4 |
5 | export const decode = tokenString => !isEmpty(tokenString) ? jwtDecode(tokenString) : null
6 |
7 | export const factory = (tokenString, stored = false) => {
8 | if (isEmpty(tokenString)) {
9 | return null
10 | }
11 |
12 | let token = null
13 | try {
14 | token = decode(tokenString)
15 | } catch (e) {
16 | // not possible to parse token.
17 | }
18 |
19 | if (isEmpty(token)) {
20 | return null
21 | }
22 |
23 | return { token: tokenString, data: token, stored }
24 | }
25 |
26 | export const usable = token => {
27 | return !isEmpty(token) && !!get(token, 'data.exp')
28 | }
29 |
30 | export const valid = token => usable(token) && moment.unix(get(token, 'data.exp')).isAfter()
31 |
32 | export const expired = token => !valid(token)
33 |
34 | export const refreshable = token => {
35 | // a not usable token should not be accepted.
36 | if (!usable(token)) {
37 | return false
38 | }
39 |
40 | // a not expired token is always refreshable.
41 | if (!expired(token)) {
42 | return true
43 | }
44 |
45 | // get the refresh limit from the token, defaults to @hernandev's birthday on the 90's
46 | const refreshLimit = get(token, 'data.rli', 634780800)
47 |
48 | // return true if the refresh limit is in the future.
49 | return moment.unix(refreshLimit).isAfter()
50 | }
51 |
--------------------------------------------------------------------------------
/resources/assets/js/helpers/sessionStorage.js:
--------------------------------------------------------------------------------
1 | const storage = window.sessionStorage
2 |
3 | export const get = (item, defaultValue = null) => {
4 | const value = storage.getItem(item)
5 | if (!value || value === undefined) {
6 | return defaultValue
7 | }
8 |
9 | return JSON.parse(value)
10 | }
11 |
12 | export const set = (item, value) => storage.setItem(item, JSON.stringify(value))
13 |
14 | export const remove = item => storage.removeItem(item)
15 |
16 | export default {
17 | get,
18 | set,
19 | remove
20 | }
21 |
--------------------------------------------------------------------------------
/resources/assets/js/helpers/storage.js:
--------------------------------------------------------------------------------
1 | import localForage from 'localforage'
2 |
3 | export const storage = localForage.createInstance({
4 | name: 'emtudo-skeleton'
5 | })
6 |
7 | export const get = item => storage.getItem(item).then(v => Promise.resolve(v))
8 |
9 | export const set = (item, value) => storage.setItem(item, value).then(() => get(item))
10 |
11 | export const remove = item => storage.removeItem(item)
12 |
13 | export const clear = () => storage.clear()
14 |
15 | export default {
16 | get,
17 | set,
18 | remove,
19 | clear
20 | }
21 |
--------------------------------------------------------------------------------
/resources/assets/js/helpers/text/index.js:
--------------------------------------------------------------------------------
1 | // import dependencies.
2 | import * as match from './match'
3 |
4 | /**
5 | * Export all text related helpers.
6 | */
7 | export default {
8 | match // text matching helpers.
9 | }
10 |
--------------------------------------------------------------------------------
/resources/assets/js/helpers/text/match.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Text matching helpers.
3 | * @param term
4 | */
5 |
6 | import { method, some, isEmpty } from 'lodash'
7 |
8 | /**
9 | * Generic text match. Case Insensitive.
10 | *
11 | * @param {String} term
12 | */
13 | export const match = term => method('match', new RegExp(term, 'i'))
14 |
15 | /**
16 | * Generic match. Case Sensitive.
17 | *
18 | * @param {String} term
19 | */
20 | export const sensitiveMatch = term => method('match', new RegExp(term))
21 |
22 | /**
23 | * Return true is a a term is match against any of an array of Strings.
24 | *
25 | * @param {Array} ofThose
26 | * @param {String} thisTerm
27 | */
28 | export const matchesAny = (ofThose, thisTerm) => isEmpty(thisTerm) ? true : some(ofThose, match(thisTerm))
29 |
30 | /**
31 | * Case sensitive - Return true is a a term is match against any of an array of Strings.
32 | *
33 | * @param {Array} ofThose
34 | * @param {String} thisTerm
35 | */
36 | export const sensitiveMatchesAny = (ofThose, thisTerm) => isEmpty(thisTerm) ? true : some(ofThose, sensitiveMatch(thisTerm))
37 |
--------------------------------------------------------------------------------
/resources/assets/js/layout/app.vue:
--------------------------------------------------------------------------------
1 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
28 |
--------------------------------------------------------------------------------
/resources/assets/js/layout/header/header.vue:
--------------------------------------------------------------------------------
1 |
19 |
20 |
21 |
37 |
38 |
--------------------------------------------------------------------------------
/resources/assets/js/layout/header/menu-left.vue:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 |
15 | -
16 |
17 | Usuários
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/resources/assets/js/layout/header/menu-right.vue:
--------------------------------------------------------------------------------
1 |
30 |
31 |
32 |
33 |
65 |
66 |
--------------------------------------------------------------------------------
/resources/assets/js/layout/main.vue:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/resources/assets/js/main.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import App from './layout/app'
3 | import router from './router'
4 | import GlobalComponents from './components'
5 | import Plugins from './plugins'
6 | import store from './store'
7 | import Filters from './filters'
8 | import Directives from './directives' // custom directives.
9 |
10 | GlobalComponents(Vue)
11 | Plugins(Vue, {store, router})
12 | require('./bootstrap')
13 | Directives(Vue)
14 | Filters(Vue)
15 |
16 | Vue.config.productionTip = false
17 |
18 | /* eslint-disable no-new */
19 | new Vue({
20 | el: '#app',
21 | router,
22 | store,
23 | render: h => h(App)
24 | })
25 |
--------------------------------------------------------------------------------
/resources/assets/js/main_render.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import router from './router'
3 | import GlobalComponents from './components'
4 | import Plugins from './plugins'
5 | import store from './store'
6 | import Filters from './filters'
7 | import Directives from './directives'
8 | import App from './layout/app'
9 |
10 | GlobalComponents(Vue)
11 | Plugins(Vue, {store, router})
12 | require('./bootstrap')
13 | Directives(Vue)
14 | Filters(Vue)
15 |
16 | Vue.config.productionTip = false
17 |
18 | /* eslint-disable no-new */
19 | new Vue({
20 | el: '#app',
21 | router,
22 | store,
23 | render: h => h(App)
24 | })
25 |
--------------------------------------------------------------------------------
/resources/assets/js/plugins/http/baseURL.js:
--------------------------------------------------------------------------------
1 | /**
2 | * detect the api base URL
3 | */
4 | export default '/v1/'
5 |
--------------------------------------------------------------------------------
/resources/assets/js/plugins/http/index.js:
--------------------------------------------------------------------------------
1 | // dependencies.
2 | import axios from 'axios'
3 | import resources from './resources'
4 | import actions from './resources/actions'
5 | import baseURL from './baseURL'
6 | import interceptors from './interceptors'
7 |
8 | // create a axios client for the api.
9 | export const http = axios.create({ baseURL })
10 |
11 | // create a axios client for local requests (legacy app).
12 | export const localHttp = axios.create()
13 |
14 | // define and export the resource actions.
15 | export const resource = basePath => actions({ $http: http }, basePath)
16 |
17 | // plugin install.
18 | export default function install (Vue, {store, router}) {
19 | // enable api http client interceptors.
20 | interceptors(http, store, router)
21 |
22 | // define $http into vue prototype.
23 | Object.defineProperty(Vue.prototype, '$http', {
24 | get () {
25 | return http
26 | }
27 | })
28 |
29 | // enable api http client interceptors.
30 | interceptors(localHttp, store, router)
31 | // define $http into vue prototype.
32 | Object.defineProperty(Vue.prototype, '$localHttp', {
33 | get () {
34 | return localHttp
35 | }
36 | })
37 |
38 | // register resources.
39 | resources(Vue)
40 | }
41 |
--------------------------------------------------------------------------------
/resources/assets/js/plugins/http/interceptors/expired_token.js:
--------------------------------------------------------------------------------
1 | import { get } from 'lodash'
2 | import toast from '@/plugins/toast/toast'
3 | /**
4 | * Handle API messages.
5 | *
6 | */
7 | export default {
8 | success (store) {
9 | return function (response) {
10 | return response
11 | }
12 | },
13 | error (store) {
14 | return function (response) {
15 | const status = get(response, 'response.status')
16 |
17 | if (status === 401) {
18 | return store.dispatch('refreshToken')
19 | .then(() => {
20 | toast.warning('Sessão será atualizada!')
21 | setTimeout(() => {
22 | window.location.reload()
23 | }, 1000)
24 | })
25 | .catch(() => {
26 | return Promise.reject(response)
27 | })
28 | }
29 |
30 | return Promise.reject(response)
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/resources/assets/js/plugins/http/interceptors/flatten.js:
--------------------------------------------------------------------------------
1 | import { get } from 'lodash'
2 |
3 | /**
4 | * Flatten success responses body.
5 | *
6 | * @param response
7 | * @returns {*}
8 | */
9 | export const success = response => get(response, 'data', {})
10 |
11 | /**
12 | * Flatten error responses body.
13 | *
14 | * @param error
15 | * @returns {*}
16 | */
17 | export const error = error => Promise.reject(get(error, 'response.data', {}))
18 |
19 | /**
20 | * Default export.
21 | */
22 | export default {
23 | success,
24 | error
25 | }
26 |
--------------------------------------------------------------------------------
/resources/assets/js/plugins/http/interceptors/index.js:
--------------------------------------------------------------------------------
1 | // dependencies.
2 | import flatten from './flatten'
3 | import messages from './messages'
4 | import expiredToken from './expired_token'
5 | import token from './token'
6 |
7 | /**
8 | * Request interceptors.
9 | *
10 | * @param http
11 | * @param store
12 | * @param router
13 | */
14 | export default (http, store, router) => {
15 | // handle http expired token.
16 | http.interceptors.response.use(expiredToken.success(store), expiredToken.error(store))
17 |
18 | // handle http messages.
19 | http.interceptors.response.use(messages.success, messages.error)
20 |
21 | // flatten data
22 | http.interceptors.response.use(flatten.success, flatten.error)
23 |
24 | // set authorization token.
25 | http.interceptors.request.use(token(store, router), error => error)
26 | }
27 |
--------------------------------------------------------------------------------
/resources/assets/js/plugins/http/interceptors/messages.js:
--------------------------------------------------------------------------------
1 | import { get } from 'lodash'
2 | // import toast from '@/plugins/toast/toast'
3 |
4 | /**
5 | * Handle API messages.
6 | *
7 | */
8 | export default {
9 | success (response) {
10 | return response
11 | },
12 | error (error) {
13 | const status = get(error, 'response.status')
14 |
15 | // const message = get(error, 'response.data.meta.message') || 'Falha ao realizar operação.'
16 |
17 | if (status === 400 || (status >= 402 && status <= 599)) {
18 | // toast.error(message)
19 | }
20 |
21 | if (status === 401) {
22 | // toast.error('Permissão negada, ou sua sessão expirou!')
23 | }
24 |
25 | return Promise.reject(error)
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/resources/assets/js/plugins/http/interceptors/token.js:
--------------------------------------------------------------------------------
1 | // dependencies.
2 | import { curry, toString, get, isEmpty } from 'lodash'
3 |
4 | const bypassHeader = url => url.indexOf('auth/login') !== -1 ||
5 | url.indexOf('auth/register') !== -1 ||
6 | url.indexOf('auth/password/email') !== -1 ||
7 | url.indexOf('auth/password/reset') !== -1
8 |
9 | const bypassSetup = url => url.indexOf('auth/user') !== -1 || url.indexOf('auth/refresh') !== -1
10 | const getToken = store => get(store, 'getters.jwt', null)
11 | const getHeader = (request, store) => {
12 | const token = getToken(store)
13 | return isEmpty(token) ? null : `Bearer ${token}`
14 | }
15 |
16 | /**
17 | * Authorization / Token interceptor.
18 | */
19 | export default curry((store, router, request) => {
20 | // request url as string.
21 | const url = toString(request.url)
22 |
23 | // should a authorization header be used?
24 | if (bypassHeader(url)) {
25 | return request
26 | }
27 |
28 | // is a setup needed?
29 | if (bypassSetup(url)) {
30 | request.headers.Authorization = getHeader(request, store)
31 | return request
32 | }
33 |
34 | // dispatch the JWT setup action
35 | return store.dispatch('setupJWT').then(() => {
36 | request.headers.Authorization = getHeader(request, store)
37 | return request
38 | }).catch(() => {
39 | return request
40 | })
41 | })
42 |
--------------------------------------------------------------------------------
/resources/assets/js/plugins/http/resources/index.js:
--------------------------------------------------------------------------------
1 | // dependencies.
2 | import actions from './actions'
3 |
4 | /**
5 | * Define HTTP resource actions on vue prototype.
6 | *
7 | * @param Vue
8 | */
9 | export default (Vue) => {
10 | /**
11 | * register resources as a mixin.
12 | */
13 | Vue.mixin({
14 |
15 | /**
16 | * Created hook.
17 | */
18 | created () {
19 | // get the resource path.
20 | const { resourcePath } = this.$options
21 |
22 | // if present...
23 | if (resourcePath !== undefined) {
24 | // setup the resource into the component.
25 | this.$setupResource(resourcePath)
26 | }
27 | },
28 |
29 | /**
30 | * Mixin methods
31 | */
32 | methods: {
33 | /**
34 | * Setup the $resource into component.
35 | * @param basePath
36 | */
37 | $setupResource (basePath) {
38 | this.$resource = actions(this, basePath)
39 | }
40 | }
41 | })
42 | }
43 |
--------------------------------------------------------------------------------
/resources/assets/js/plugins/index.js:
--------------------------------------------------------------------------------
1 | // import plugins
2 | import http from './http'
3 | import Toast from './toast'
4 | import IsMobile from './is_mobile'
5 |
6 | /**
7 | * Default export.
8 | *
9 | * @param Vue
10 | * @param router
11 | */
12 | export default (Vue, { store, router }) => {
13 | // setup http
14 | Vue.use(http, { store, router })
15 |
16 | // setup toast
17 | Toast(Vue)
18 |
19 | Vue.use(IsMobile)
20 | }
21 |
--------------------------------------------------------------------------------
/resources/assets/js/plugins/is_mobile.js:
--------------------------------------------------------------------------------
1 | import isMobile from '@/helpers/isMobile'
2 |
3 | export default function install (Vue) {
4 | // define $http into vue prototype.
5 | Object.defineProperty(Vue.prototype, '$isMobile', {
6 | get () {
7 | return isMobile()
8 | }
9 | })
10 | }
11 |
--------------------------------------------------------------------------------
/resources/assets/js/plugins/toast/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * iziToast Vue.js Plugin.
3 | */
4 |
5 | // import the toast actions.
6 | import ToastPlugin from './toast'
7 |
8 | /**
9 | * Plugin install export.
10 | * @param Vue
11 | * @constructor
12 | */
13 | const ToastInstall = function (Vue) {
14 | Vue.prototype.$toast = ToastPlugin
15 | }
16 |
17 | /**
18 | * Export that accepts a vue instance.
19 | * @param Vue
20 | */
21 | export default (Vue) => {
22 | Vue.use(ToastInstall)
23 | }
24 |
--------------------------------------------------------------------------------
/resources/assets/js/router/before_each.js:
--------------------------------------------------------------------------------
1 | import store from '@/store'
2 | import { get } from 'lodash'
3 | import toast from '@/plugins/toast/toast'
4 |
5 | const requireTwoFactor = route => {
6 | return get(route, 'meta.twoFactor', false)
7 | }
8 |
9 | const routeIsAuthTwoFactor = route => {
10 | return get(route, 'name', null) === 'auth.two_factor'
11 | }
12 |
13 | /**
14 | * check if user has permission
15 | *
16 | * @param Object user
17 | * @param String route
18 | *
19 | * @return Boolean
20 | */
21 | const hasRole = (user, route) => {
22 | const role = get(route, 'meta.role', 'admin')
23 | if (role === 'guest') {
24 | return true
25 | }
26 |
27 | return user.is_admin
28 | }
29 |
30 | /**
31 | * Runs before each route change.
32 | *
33 | * @param to
34 | * @param from
35 | * @param next
36 | */
37 | const beforeEach = (to, from, next) => {
38 | // setup page title (not vue handled).
39 | document.title = get(to, 'meta.title', 'Emtudo Skeleton')
40 |
41 | if (!get(to, 'meta.auth', true)) {
42 | const force = get(to, 'meta.forceSetupUser', false)
43 | if (force) {
44 | store.dispatch('setupUserSilent')
45 | }
46 | return next()
47 | }
48 |
49 | // dispatch the user info actions and continue the request after.
50 | return store.dispatch('setupUser')
51 | .then((user) => {
52 | if (routeIsAuthTwoFactor(to)) {
53 | return next()
54 | }
55 | const twoFactor = user['two_factor']
56 | if (!hasRole(user, to)) {
57 | toast.warning('Você não tem permissão para acessar esta rota!')
58 | return
59 | }
60 | if (requireTwoFactor(to) && twoFactor.enabled && !twoFactor.valid) {
61 | return next({name: 'auth.two_factor'})
62 | }
63 | return next()
64 | })
65 | .catch(() => {
66 | return next({name: 'auth.login'})
67 | })
68 | }
69 |
70 | export default beforeEach
71 |
--------------------------------------------------------------------------------
/resources/assets/js/router/force_https.js:
--------------------------------------------------------------------------------
1 | import { get } from 'lodash'
2 |
3 | export default () => {
4 | const env = get(process.env, 'NODE_ENV')
5 | if (env !== 'production') {
6 | return
7 | }
8 |
9 | if (window.location.protocol !== 'https:') {
10 | // window.location.href = window.location.href.replace('http:', 'https:')
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/resources/assets/js/router/index.js:
--------------------------------------------------------------------------------
1 | // Vue
2 | import Vue from 'vue'
3 | // import the vue-router
4 | import VueRouter from 'vue-router'
5 |
6 | // import application routes
7 | import { routes as app } from '@/app'
8 |
9 | // run before each route change
10 | import beforeEach from './before_each'
11 | import forceHttps from './force_https'
12 | forceHttps()
13 |
14 | // make vue-router available on Vue
15 | Vue.use(VueRouter)
16 |
17 | // spread app routes
18 | const routes = [...app]
19 |
20 | // create a new router instance.
21 | const router = new VueRouter({
22 | routes,
23 | linkActiveClass: 'active'
24 | })
25 |
26 | // setup a before each for routes.
27 | router.beforeEach(beforeEach)
28 |
29 | // return the router on the default export.
30 | export default router
31 |
--------------------------------------------------------------------------------
/resources/assets/js/store/getters/index.js:
--------------------------------------------------------------------------------
1 | import * as user from './user'
2 | import * as jwt from './jwt'
3 | import * as twoFactor from './two_factor'
4 |
5 | export default {
6 | ...user,
7 | ...jwt,
8 | ...twoFactor
9 | }
10 |
--------------------------------------------------------------------------------
/resources/assets/js/store/getters/jwt.js:
--------------------------------------------------------------------------------
1 | // JWT token.
2 | export const jwt = ({ jwt }) => jwt
3 |
--------------------------------------------------------------------------------
/resources/assets/js/store/getters/two_factor.js:
--------------------------------------------------------------------------------
1 | import { get } from 'lodash'
2 |
3 | export const twoFactor = ({ user }) => get(user, 'two_factor', null)
4 | export const twoFactorIsActive = ({ user }) => get(user, 'two_factor.enabled', false)
5 | export const twoFactorIsValid = ({ user }) => {
6 | const enabled = get(user, 'two_factor.enabled', false)
7 | if (!enabled) {
8 | return true
9 | }
10 |
11 | return get(user, 'two_factor.valid', false)
12 | }
13 |
--------------------------------------------------------------------------------
/resources/assets/js/store/getters/user.js:
--------------------------------------------------------------------------------
1 | import { get, first } from 'lodash'
2 |
3 | // isLogged
4 | export const isLogged = ({ user }) => {
5 | return get(user, 'id', null) !== null
6 | } // isLogged
7 |
8 | // user getters
9 | export const currentUser = ({ user }) => user // all user data
10 | export const user = ({ user }) => user // all user data
11 | export const userId = ({ user }) => get(user, 'id') // current user id
12 | export const userName = ({ user }) => get(user, 'name') // current user name
13 | export const userAvatar = ({ user }) => get(user, 'avatar') // current user name
14 | export const userFirstName = ({ user }) => first((get(user, 'name') || '').split(' ')) // current user first name
15 | export const userEmail = ({ user }) => get(user, 'email') // current user email
16 | export const userIsLogged = ({ user }) => get(user, 'id', null) !== null
17 |
18 | // current user role
19 | export const userIsAdmin = ({ user }) => get(user, 'is_admin', false)
20 |
--------------------------------------------------------------------------------
/resources/assets/js/store/index.js:
--------------------------------------------------------------------------------
1 | // import libraries
2 | import Vue from 'vue'
3 | import Vuex from 'vuex'
4 |
5 | // import global global resources.
6 | import state from './state'
7 | import mutations from './mutations'
8 | import actions from './actions'
9 | import getters from './getters'
10 |
11 | // import module resources.
12 | import modules from './modules'
13 |
14 | // setup vuex on vue.
15 | Vue.use(Vuex)
16 |
17 | // create a store.
18 | const store = new Vuex.Store({
19 | strict: false,
20 | state,
21 | mutations,
22 | getters,
23 | actions,
24 | modules,
25 | plugins: []
26 | })
27 |
28 | // export the vuex store.
29 | export default store
30 |
--------------------------------------------------------------------------------
/resources/assets/js/store/modules.js:
--------------------------------------------------------------------------------
1 | import { store as app } from '@/app'
2 |
3 | export default { app }
4 |
--------------------------------------------------------------------------------
/resources/assets/js/store/mutations.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Global mutations.
3 | */
4 | // default export.
5 | export default {
6 | /**
7 | * Set global user data.
8 | *
9 | * @param state
10 | * @param userData
11 | */
12 | setUserData (state, userData) {
13 | state.user = userData
14 | },
15 |
16 | /**
17 | * @param state
18 | * @param avatar
19 | */
20 | setAvatar (state, avatar) {
21 | state.user.avatar = avatar
22 | },
23 |
24 | /**
25 | * Clear user data.
26 | *
27 | * @param state
28 | */
29 | clearUserData (state) {
30 | state.user = {
31 | id: null, // user id.
32 | name: null, // user name.
33 | email: null, // user email.
34 | two_factor: {
35 | enabled: false,
36 | valid: false
37 | }
38 | }
39 | },
40 |
41 | /**
42 | * Set user JWT token into local store.
43 | *
44 | * @param state
45 | * @param jwt
46 | */
47 | setJWT (state, jwt) {
48 | // set raw token data.
49 | state.jwt = jwt
50 | },
51 |
52 | setTwoFactorEnable (state, value) {
53 | state.user.two_factor.enabled = value
54 | },
55 | setTwoFactorValid (state, value) {
56 | state.user.two_factor.valid = value
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/resources/assets/js/store/state.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Global vuex state.
3 | */
4 | // default export.
5 | export default {
6 | remember: true,
7 |
8 | /**
9 | * JWT Token and Data.
10 | */
11 | jwt: {
12 | token: null
13 | },
14 |
15 | /**
16 | * Basic user information.
17 | */
18 | user: {
19 | id: null, // user id.
20 | name: null, // user name.
21 | email: null, // user email.
22 | two_factor: {
23 | enabled: false,
24 | valid: false
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/resources/assets/sass/_variables.scss:
--------------------------------------------------------------------------------
1 |
2 | // Body
3 | $body-bg: #f5f8fa;
4 |
5 | // Typography
6 | $font-family-sans-serif: "Raleway", sans-serif;
7 | $font-size-base: 0.9rem;
8 | $line-height-base: 1.6;
9 |
--------------------------------------------------------------------------------
/resources/assets/sass/app.scss:
--------------------------------------------------------------------------------
1 |
2 | // Fonts
3 | @import url("https://fonts.googleapis.com/css?family=Raleway:300,400,600");
4 |
5 | // Variables
6 | @import "variables";
7 |
8 | // Bootstrap
9 | @import '~bootstrap/scss/bootstrap';
10 |
11 | .navbar-laravel {
12 | background-color: #fff;
13 | box-shadow: 0 2px 4px rgba(0, 0, 0, 0.04);
14 | }
15 |
--------------------------------------------------------------------------------
/resources/lang/en/auth.php:
--------------------------------------------------------------------------------
1 | 'These credentials do not match our records.',
17 | 'throttle' => 'Too many login attempts. Please try again in :seconds seconds.',
18 |
19 | ];
20 |
--------------------------------------------------------------------------------
/resources/lang/en/pagination.php:
--------------------------------------------------------------------------------
1 | '« Previous',
17 | 'next' => 'Next »',
18 |
19 | ];
20 |
--------------------------------------------------------------------------------
/resources/lang/en/passwords.php:
--------------------------------------------------------------------------------
1 | 'Passwords must be at least six characters and match the confirmation.',
17 | 'reset' => 'Your password has been reset!',
18 | 'sent' => 'We have e-mailed your password reset link!',
19 | 'token' => 'This password reset token is invalid.',
20 | 'user' => "We can't find a user with that e-mail address.",
21 |
22 | ];
23 |
--------------------------------------------------------------------------------
/resources/lang/pt_BR/auth.php:
--------------------------------------------------------------------------------
1 | 'As credenciais informadas não constam no sistema.',
17 | 'throttle' => 'Muitas tentativas de login. Tente novamente em :seconds segundos.',
18 |
19 | 'login' => 'Entrar',
20 | 'email' => 'Email',
21 | 'password' => 'Senha',
22 |
23 | 'remember' => 'Lembrar nesse computador',
24 |
25 | 'forgot' => 'Esqueceu a senha?',
26 |
27 | 'reset' => 'Recuperar senha',
28 | 'send_reset' => 'Enviar Link',
29 |
30 | 'password_confirmation' => 'Confirmar Senha',
31 |
32 | 'register' => 'Cadastrar',
33 | 'name' => 'Nome',
34 |
35 | ];
36 |
--------------------------------------------------------------------------------
/resources/lang/pt_BR/months.php:
--------------------------------------------------------------------------------
1 | 'Janeiro',
5 | '02' => 'Fevereiro',
6 | '03' => 'Março',
7 | '04' => 'Abril',
8 | '05' => 'Maio',
9 | '06' => 'Junho',
10 | '07' => 'Julho',
11 | '08' => 'Agosto',
12 | '09' => 'Setembro',
13 | '10' => 'Outubro',
14 | '11' => 'Novembro',
15 | '12' => 'Dezembro',
16 | ];
--------------------------------------------------------------------------------
/resources/lang/pt_BR/pagination.php:
--------------------------------------------------------------------------------
1 | '« Anterior',
17 | 'next' => 'Próxima »',
18 |
19 | ];
20 |
--------------------------------------------------------------------------------
/resources/lang/pt_BR/passwords.php:
--------------------------------------------------------------------------------
1 | 'A senha precisa conter pelo menos 6 caracteres e ser igual a confirmação.',
17 | 'reset' => 'Sua senha foi alterada!',
18 | 'sent' => 'Enviamos um email com um link para recuperar sua senha!',
19 | 'token' => 'Esse link de recuperação de senha é inválido.',
20 | 'user' => 'Não foi possível encontrar um usuário com o email informado.',
21 |
22 | ];
23 |
--------------------------------------------------------------------------------
/server.php:
--------------------------------------------------------------------------------
1 |
8 | */
9 |
10 | $uri = urldecode(
11 | parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH)
12 | );
13 |
14 | // This file allows us to emulate Apache's "mod_rewrite" functionality from the
15 | // built-in PHP web server. This provides a convenient way to test a Laravel
16 | // application without having installed a "real" web server software here.
17 | if ($uri !== '/' && file_exists(__DIR__.'/public'.$uri)) {
18 | return false;
19 | }
20 |
21 | require_once __DIR__.'/public/index.php';
22 |
--------------------------------------------------------------------------------
/storage/app/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !public/
3 | !.gitignore
4 |
--------------------------------------------------------------------------------
/storage/app/public/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/storage/framework/.gitignore:
--------------------------------------------------------------------------------
1 | config.php
2 | routes.php
3 | schedule-*
4 | compiled.php
5 | services.json
6 | events.scanned.php
7 | routes.scanned.php
8 | down
9 |
--------------------------------------------------------------------------------
/storage/framework/cache/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/storage/framework/sessions/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/storage/framework/testing/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/storage/framework/views/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/storage/logs/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/tests/CreatesApplication.php:
--------------------------------------------------------------------------------
1 | make(Kernel::class)->bootstrap();
20 |
21 | Hash::driver('bcrypt')->setRounds(4);
22 |
23 | return $app;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/tests/Feature/ExampleTest.php:
--------------------------------------------------------------------------------
1 | get('/');
18 |
19 | $response->assertStatus(200);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/tests/TestCase.php:
--------------------------------------------------------------------------------
1 | assertTrue(true);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/webpack.mix.js:
--------------------------------------------------------------------------------
1 | const mix = require('laravel-mix')
2 | const path = require('path')
3 |
4 | /*
5 | |--------------------------------------------------------------------------
6 | | Mix Asset Management
7 | |--------------------------------------------------------------------------
8 | |
9 | | Mix provides a clean, fluent API for defining some Webpack build steps
10 | | for your Laravel application. By default, we are compiling the Sass
11 | | file for the application as well as bundling up all the JS files.
12 | |
13 | */
14 |
15 | mix.js('resources/assets/js/main.js', 'public/js/app.js')
16 | .sass('resources/assets/sass/app.scss', 'public/css')
17 |
18 | mix.copy('resources/assets/copy/js/', 'public/js/');
19 |
20 | mix.webpackConfig({
21 | resolve: {
22 | alias: {
23 | '@': path.resolve(__dirname, 'resources/assets/js')
24 | }
25 | }
26 | })
27 |
--------------------------------------------------------------------------------