├── .circleci └── config.yml ├── .codecov.yml ├── .documents └── whiteboard │ ├── .gitignore │ ├── LICENSE │ ├── README.md │ ├── _config.yml │ ├── lib │ └── whiteboard.js │ ├── package.json │ ├── source │ ├── images │ │ ├── logo.png │ │ └── navbar.png │ ├── includes │ │ ├── _authenticate.md │ │ └── _errors.md │ └── index.md │ ├── themes │ └── whiteboard │ │ ├── .gitignore │ │ ├── _config.yml │ │ ├── layout │ │ └── index.ejs │ │ ├── scripts │ │ ├── highlight.js │ │ └── read.js │ │ └── source │ │ ├── css │ │ ├── _icon_font.styl │ │ ├── _monokai.css │ │ ├── _normalize.css │ │ ├── _variables.styl │ │ ├── fonts │ │ │ ├── FontAwesome.otf │ │ │ ├── fontawesome-webfont.eot │ │ │ ├── fontawesome-webfont.svg │ │ │ ├── fontawesome-webfont.ttf │ │ │ └── fontawesome-webfont.woff │ │ └── style.styl │ │ └── js │ │ ├── lib │ │ ├── energize.js │ │ ├── imagesloaded.min.js │ │ ├── jquery.highlight.js │ │ ├── jquery.tocify.js │ │ ├── jquery_ui.js │ │ └── lunr.js │ │ └── script.js │ └── yarn.lock ├── .editorconfig ├── .env.dev.example ├── .env.example ├── .envs └── dev │ ├── cert │ ├── Dockerfile │ ├── command.sh │ ├── create-certs.sh │ ├── create-htpasswd.sh │ ├── create-rootCA.sh │ ├── entrypoint.sh │ ├── files │ │ └── .gitignore │ ├── rootCA.csr.cnf │ └── v3.ext │ ├── common │ └── wait-for-it.sh │ ├── memcached │ └── Dockerfile │ ├── mysql │ ├── .gitignore │ ├── Dockerfile │ └── entrypoint.sh │ ├── nginx │ ├── .gitignore │ ├── Dockerfile │ ├── command.sh │ ├── conf.d │ │ ├── default.conf │ │ ├── documents.conf │ │ ├── ip-whitelist.conf │ │ └── phpmyadmin.conf │ ├── logs │ │ └── .gitkeep │ └── nginx.conf │ ├── node │ ├── Dockerfile │ └── command.sh │ ├── php │ ├── Dockerfile │ ├── command.sh │ ├── crontab │ │ ├── cron.daily.logrotate │ │ ├── cron.minutely.schedule │ │ └── crontab │ ├── entrypoint.sh │ ├── passport.sh │ ├── php-fpm.conf │ ├── php-worker │ ├── php-worker.conf │ ├── php.ini │ └── www.conf │ ├── phpcs │ └── SunOS │ │ └── ruleset.xml │ └── phpmyadmin │ ├── command.sh │ ├── phpMyAdmin-4.8.5.tar.gz │ └── src │ └── .gitignore ├── .eslintignore ├── .eslintrc.js ├── .gitattributes ├── .github └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── .stylelintignore ├── .stylelintrc.js ├── app ├── Console │ ├── Commands │ │ └── GitGetCommit.php │ └── Kernel.php ├── Events │ └── ExceptionThrown.php ├── Exceptions │ ├── Api │ │ ├── ActionException.php │ │ ├── ApiException.php │ │ ├── NotFoundException.php │ │ ├── NotOwnerException.php │ │ └── UnknownException.php │ ├── Handler.php │ └── Permission │ │ ├── PermissionDoesNotExist.php │ │ ├── RoleDoesNotExist.php │ │ └── UnauthorizedException.php ├── Http │ ├── Controllers │ │ ├── Api │ │ │ ├── ApiController.php │ │ │ ├── Auth │ │ │ │ ├── ForgotPasswordController.php │ │ │ │ └── LoginController.php │ │ │ └── UserController.php │ │ ├── Controller.php │ │ └── Web │ │ │ ├── Auth │ │ │ ├── ForgotPasswordController.php │ │ │ ├── LoginController.php │ │ │ ├── RegisterController.php │ │ │ ├── ResetPasswordController.php │ │ │ └── VerificationController.php │ │ │ ├── ExportController.php │ │ │ ├── HomeController.php │ │ │ ├── ImportController.php │ │ │ ├── UserController.php │ │ │ └── WebController.php │ ├── Kernel.php │ ├── Middleware │ │ ├── Authenticate.php │ │ ├── CheckForMaintenanceMode.php │ │ ├── EncryptCookies.php │ │ ├── Permission │ │ │ ├── PermissionMiddleware.php │ │ │ └── RoleMiddleware.php │ │ ├── RedirectIfAuthenticated.php │ │ ├── TrimStrings.php │ │ ├── TrustProxies.php │ │ └── VerifyCsrfToken.php │ ├── Requests │ │ ├── Auth │ │ │ ├── ForgotPasswordRequest.php │ │ │ ├── LoginRequest.php │ │ │ ├── RegisterRequest.php │ │ │ └── ResetPasswordRequest.php │ │ ├── ExportFormRequest.php │ │ └── ImportFileCsvRequest.php │ └── Resources │ │ ├── ApiCollection.php │ │ ├── ApiResource.php │ │ ├── AuthResource.php │ │ ├── ExportResource.php │ │ └── UserResource.php ├── Libraries │ ├── ChatApp │ │ ├── ChatAppException.php │ │ ├── ChatAppHandler.php │ │ ├── ChatAppManager.php │ │ ├── Handlers │ │ │ ├── Chatwork.php │ │ │ └── Slack.php │ │ └── Messages │ │ │ ├── Chatwork.php │ │ │ └── Slack.php │ ├── PermissionRegister.php │ └── helpers.php ├── Listeners │ └── ExceptionThrownListener.php ├── Mail │ └── MailForgotPassword.php ├── Models │ ├── BaseModel.php │ ├── Import.php │ ├── PasswordResetToken.php │ ├── Permission.php │ ├── Role.php │ └── User.php ├── Policies │ └── AbstractPolicy.php ├── Providers │ ├── AppServiceProvider.php │ ├── AuthServiceProvider.php │ ├── BroadcastServiceProvider.php │ ├── ChatAppProvider.php │ ├── EventServiceProvider.php │ ├── PermissionServiceProvider.php │ ├── RepositoryServiceProvider.php │ └── RouteServiceProvider.php ├── Repositories │ ├── AppRepository.php │ ├── AppRepositoryInterface.php │ ├── ExportRepository.php │ ├── ExportRepositoryInterface.php │ ├── ImportRepository.php │ ├── ImportRepositoryInterface.php │ ├── PasswordResetTokenRepository.php │ ├── PasswordResetTokenRepositoryInterface.php │ ├── PermissionRepository.php │ ├── PermissionRepositoryInterface.php │ ├── RoleRepository.php │ ├── RoleRepositoryInterface.php │ ├── UserRepository.php │ └── UserRepositoryInterface.php ├── Rules │ ├── CheckEmail.php │ ├── CheckExtension.php │ ├── CheckImportFile.php │ └── CheckValidPasswordResetToken.php ├── Services │ ├── AppService.php │ ├── AuthService.php │ ├── ExportService.php │ ├── ImportService.php │ └── UserService.php └── Traits │ ├── RoleHasPermissions.php │ └── UserHasRolesAndPermissions.php ├── artisan ├── bootstrap ├── app.php └── cache │ └── .gitignore ├── composer.json ├── composer.lock ├── config ├── api.php ├── app.php ├── auth.php ├── broadcasting.php ├── cache.php ├── common.php ├── database.php ├── filesystems.php ├── hashing.php ├── laroute.php ├── logging.php ├── mail.php ├── permission.php ├── queue.php ├── services.php ├── session.php ├── view.php └── web.php ├── database ├── .gitignore ├── factories │ ├── ImportFactory.php │ ├── PermissionFactory.php │ ├── RoleFactory.php │ └── UserFactory.php ├── migrations │ ├── 2014_10_12_000000_create_users_table.php │ ├── 2014_10_12_100000_create_password_resets_table.php │ ├── 2019_05_27_071248_create_roles_and_permissions_table.php │ └── 2019_08_19_102724_create_imports_table.php └── seeds │ ├── DatabaseSeeder.php │ ├── RolePermissionSeeder.php │ └── UserTableSeeder.php ├── docker-compose.dev.yml ├── docker.sh ├── mergeManifest.js ├── package.json ├── phpunit.xml ├── public ├── .htaccess ├── css │ └── .gitignore ├── export.csv ├── favicon.ico ├── index.php ├── js │ └── .gitignore ├── robots.txt └── web.config ├── readme.md ├── resources ├── js │ ├── App.vue │ ├── app.js │ ├── components │ │ ├── Login │ │ │ ├── Authentication.vue │ │ │ └── Registeration.vue │ │ └── Navbar │ │ │ └── Navbar.vue │ ├── constants │ │ └── index.js │ ├── langs │ │ ├── en.js │ │ └── vi.js │ ├── mixins │ │ └── RedirectIfAuthenticated.js │ ├── pages │ │ ├── Auth │ │ │ ├── LoginPage.vue │ │ │ └── RegisterPage.vue │ │ ├── DashboardPage.vue │ │ ├── Export.vue │ │ └── Layout │ │ │ └── AppLayout.vue │ ├── router │ │ ├── index.js │ │ └── middlewares │ │ │ └── auth.js │ ├── store │ │ ├── auth │ │ │ ├── index.js │ │ │ └── mutation-types.js │ │ └── index.js │ └── utils │ │ ├── api.js │ │ ├── env.js │ │ ├── i18n │ │ ├── formatter.js │ │ └── index.js │ │ ├── index.js │ │ ├── route.js │ │ └── swal.js ├── lang │ └── en │ │ ├── auth.php │ │ ├── common.php │ │ ├── exception.php │ │ ├── export.php │ │ ├── http_message.php │ │ ├── import.php │ │ ├── pagination.php │ │ ├── passwords.php │ │ └── validation.php ├── sass │ ├── _mixins.scss │ ├── _variables.scss │ └── app.scss └── views │ ├── auth │ ├── login.blade.php │ ├── passwords │ │ ├── email.blade.php │ │ └── reset.blade.php │ ├── register.blade.php │ └── verify.blade.php │ ├── client.blade.php │ ├── emails │ └── mail_forgot_password.blade.php │ ├── home.blade.php │ ├── imports │ └── index.blade.php │ ├── layouts │ └── app.blade.php │ └── notification_template │ ├── chatwork.blade.php │ └── slack.blade.php ├── routes ├── api.php ├── channels.php ├── console.php └── web.php ├── server.php ├── storage ├── app │ ├── .gitignore │ └── public │ │ └── .gitignore ├── framework │ ├── .gitignore │ ├── cache │ │ ├── .gitignore │ │ └── data │ │ │ └── .gitignore │ ├── sessions │ │ └── .gitignore │ ├── testing │ │ └── .gitignore │ └── views │ │ └── .gitignore └── logs │ └── .gitignore ├── tests ├── CreatesApplication.php ├── Feature │ └── Http │ │ └── Controller │ │ └── Web │ │ └── Auth │ │ ├── ForgetPasswordControllerTest.php │ │ ├── LoginControllerTest.php │ │ ├── RegisterControllerTest.php │ │ └── ResetPasswordControllerTest.php ├── ModelTestCase.php ├── TestCase.php ├── Unit │ ├── ExampleTest.php │ ├── Http │ │ ├── Controller │ │ │ └── Web │ │ │ │ ├── Auth │ │ │ │ ├── LoginControllerTest.php │ │ │ │ └── RegisterControllerTest.php │ │ │ │ ├── ExportControllerTest.php │ │ │ │ └── ImportControllerTest.php │ │ ├── Middleware │ │ │ ├── PermissionMiddlewareTest.php │ │ │ └── RoleMiddlewareTest.php │ │ └── Requests │ │ │ ├── ExportFormRequestTest.php │ │ │ └── ImportFileCsvRequestTest.php │ ├── Libraries │ │ └── PermissionRegisterTest.php │ ├── Models │ │ ├── PermissionTest.php │ │ ├── RoleTest.php │ │ └── UserTest.php │ ├── Repositories │ │ ├── ExportRepositoryTest.php │ │ └── ImportRepositoryTest.php │ ├── Rules │ │ └── CheckImportFileTest.php │ ├── Services │ │ ├── ExportServiceTest.php │ │ └── ImportServiceTest.php │ └── Traits │ │ ├── RoleHasPermissionsTest.php │ │ └── UserHasRolesAndPermissionsTest.php └── files │ ├── data_check_header_rule.csv │ ├── data_check_row_rule.csv │ └── data_check_rule.csv ├── webpack.css.mix.js ├── webpack.js.mix.js └── yarn.lock /.codecov.yml: -------------------------------------------------------------------------------- 1 | codecov: 2 | notify: 3 | require_ci_to_pass: yes 4 | 5 | coverage: 6 | precision: 2 7 | round: down 8 | range: "70...100" 9 | 10 | status: 11 | project: yes 12 | patch: yes 13 | changes: no 14 | 15 | parsers: 16 | gcov: 17 | branch_detection: 18 | conditional: yes 19 | loop: yes 20 | method: no 21 | macro: no 22 | 23 | comment: 24 | layout: "header, diff" 25 | behavior: default 26 | require_changes: no 27 | -------------------------------------------------------------------------------- /.documents/whiteboard/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | Thumbs.db 3 | db.json 4 | *.log 5 | node_modules/ 6 | public/ 7 | .deploy*/ -------------------------------------------------------------------------------- /.documents/whiteboard/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2016 Marcel Pociot 2 | Copyright 2008-2013 Concur Technologies, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); you may 5 | not use this file except in compliance with the License. You may obtain 6 | a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | License for the specific language governing permissions and limitations 14 | under the License. 15 | -------------------------------------------------------------------------------- /.documents/whiteboard/README.md: -------------------------------------------------------------------------------- 1 | Whiteboard 2 | 3 | # Whiteboard 4 | #### Simply write beautiful API documentation. 5 | -------------------------------------------------------------------------------- /.documents/whiteboard/_config.yml: -------------------------------------------------------------------------------- 1 | # Whiteboard Configuration 2 | ## Docs: https://hexo.io/docs/configuration.html 3 | 4 | # Site 5 | title: API Documentation 6 | subtitle: 7 | description: 8 | author: John Doe 9 | language: 10 | timezone: 11 | 12 | # URL (Used when deploying) 13 | ## If your site is put in a subdirectory, set url as 'http://yoursite.com/child' and root as '/child/' 14 | url: http://yoursite.com 15 | root: / 16 | 17 | # Directory 18 | source_dir: source 19 | public_dir: public 20 | i18n_dir: :lang 21 | skip_render: 22 | 23 | # Writing 24 | relative_link: true 25 | future: true 26 | highlight: 27 | enable: true 28 | line_number: false 29 | auto_detect: false 30 | tab_replace: 31 | 32 | # Extensions 33 | ## Plugins: https://hexo.io/plugins/ 34 | ## Themes: https://hexo.io/themes/ 35 | theme: whiteboard 36 | 37 | # Deployment 38 | ## Docs: https://hexo.io/docs/deployment.html 39 | deploy: 40 | type: 41 | 42 | -------------------------------------------------------------------------------- /.documents/whiteboard/lib/whiteboard.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var Hexo = require('hexo'); 4 | var hexo = new Hexo(); 5 | var Promise = require("bluebird"); 6 | 7 | module.exports = { 8 | 9 | 'generate': function () { 10 | return new Promise(function (resolve, reject) { 11 | hexo.init().then(function () { 12 | hexo.call('generate', {force: true}).then(resolve, reject); 13 | }); 14 | }); 15 | } 16 | 17 | }; 18 | -------------------------------------------------------------------------------- /.documents/whiteboard/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "whiteboard", 3 | "version": "1.1.0", 4 | "license": "Apache-2.0", 5 | "main": "lib/whiteboard", 6 | "hexo": { 7 | "version": "3.9.0" 8 | }, 9 | "dependencies": { 10 | "bluebird": "^3.5.5", 11 | "cheerio": "^1.0.0-rc.3", 12 | "hexo": "^3.9.0", 13 | "hexo-cli": "^2.0.0", 14 | "hexo-generator-archive": "^0.1.5", 15 | "hexo-generator-category": "^0.1.3", 16 | "hexo-generator-index": "^0.2.1", 17 | "hexo-generator-tag": "^0.2.0", 18 | "hexo-renderer-ejs": "^0.3.1", 19 | "hexo-renderer-stylus": "^0.3.3", 20 | "hexo-renderer-marked": "^1.0.1", 21 | "hexo-server": "^0.3.3" 22 | }, 23 | "scripts": { 24 | "start": "hexo server", 25 | "generate": "hexo generate" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /.documents/whiteboard/source/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/euclid1990/laravel/19a5b008c5649aef143b988c233c4fcfbb88557f/.documents/whiteboard/source/images/logo.png -------------------------------------------------------------------------------- /.documents/whiteboard/source/images/navbar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/euclid1990/laravel/19a5b008c5649aef143b988c233c4fcfbb88557f/.documents/whiteboard/source/images/navbar.png -------------------------------------------------------------------------------- /.documents/whiteboard/source/includes/_errors.md: -------------------------------------------------------------------------------- 1 | # Errors 2 | 3 | 4 | 5 | The Kittn API uses the following error codes: 6 | 7 | 8 | Error Code | Meaning 9 | ---------- | ------- 10 | 400 | Bad Request -- Your request sucks 11 | 401 | Unauthorized -- Your API key is wrong 12 | 403 | Forbidden -- The kitten requested is hidden for administrators only 13 | 404 | Not Found -- The specified kitten could not be found 14 | 405 | Method Not Allowed -- You tried to access a kitten with an invalid method 15 | 406 | Not Acceptable -- You requested a format that isn't json 16 | 410 | Gone -- The kitten requested has been removed from our servers 17 | 418 | I'm a teapot 18 | 429 | Too Many Requests -- You're requesting too many kittens! Slow down! 19 | 500 | Internal Server Error -- We had a problem with our server. Try again later. 20 | 503 | Service Unavailable -- We're temporarily offline for maintenance. Please try again later. 21 | -------------------------------------------------------------------------------- /.documents/whiteboard/source/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: SUNOS API Reference 3 | 4 | includes: 5 | - authenticate 6 | - errors 7 | 8 | search: true 9 | --- 10 | -------------------------------------------------------------------------------- /.documents/whiteboard/themes/whiteboard/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | tmp -------------------------------------------------------------------------------- /.documents/whiteboard/themes/whiteboard/_config.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/euclid1990/laravel/19a5b008c5649aef143b988c233c4fcfbb88557f/.documents/whiteboard/themes/whiteboard/_config.yml -------------------------------------------------------------------------------- /.documents/whiteboard/themes/whiteboard/scripts/highlight.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var cheerio; 4 | 5 | hexo.extend.filter.register('after_render:html', function(str, data){ 6 | if (!cheerio) cheerio = require('cheerio'); 7 | var $ = cheerio.load(str, {decodeEntities: false}); 8 | 9 | $('figure.highlight').each(function(){ 10 | var code = $(this).find('.code > pre').html(); 11 | var html = '
' + code + '
'; 12 | $(this).replaceWith(html) 13 | }); 14 | 15 | $('pre > code').each(function(){ 16 | if( !$(this).hasClass('highlight') ){ 17 | $(this).addClass('highlight'); 18 | } 19 | }); 20 | 21 | return $.html(); 22 | }); 23 | -------------------------------------------------------------------------------- /.documents/whiteboard/themes/whiteboard/scripts/read.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var fs = require('fs'); 4 | var pathFn = require('path'); 5 | 6 | hexo.extend.helper.register('read', function(path){ 7 | var src = pathFn.join(hexo.source_dir, 'includes', pathFn.join(pathFn.dirname(path), '_' + pathFn.basename(path) + '.md')); 8 | if( fs.existsSync(src) ) { 9 | return fs.readFileSync(src, { 10 | encoding: 'utf-8' 11 | }); 12 | } 13 | return ''; 14 | }); 15 | -------------------------------------------------------------------------------- /.documents/whiteboard/themes/whiteboard/source/css/_icon_font.styl: -------------------------------------------------------------------------------- 1 | @font-face 2 | font-family: FontAwesome 3 | font-style: normal 4 | font-weight: normal 5 | src: url($font-icon-path + ".eot?v=#" + $font-icon-version) 6 | src: url($font-icon-path + ".eot?#iefix&v=#" + $font-icon-version) format("embedded-opentype"), 7 | url($font-icon-path + ".woff?v=#" + $font-icon-version) format("woff"), 8 | url($font-icon-path + ".ttf?v=#" + $font-icon-version) format("truetype"), 9 | url($font-icon-path + ".svg#fontawesomeregular?v=#" + $font-icon-version) format("svg") 10 | 11 | $icon 12 | font-family: 'FontAwesome' 13 | speak: none 14 | font-style: normal 15 | font-weight: normal 16 | font-variant: normal 17 | text-transform: none 18 | line-height: 1 19 | 20 | $icon-exclamation-sign 21 | @extend $icon 22 | content: "\f06a" 23 | 24 | $icon-info-sign 25 | @extend $icon 26 | content: "\f05a" 27 | 28 | $icon-ok-sign 29 | @extend $icon 30 | content: "\f058" 31 | 32 | $icon-search 33 | @extend $icon 34 | content: "\f002" 35 | -------------------------------------------------------------------------------- /.documents/whiteboard/themes/whiteboard/source/css/_monokai.css: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Monokai Sublime style. Derived from Monokai by noformnocontent http://nn.mit-license.org/ 4 | 5 | */ 6 | 7 | .hljs { 8 | display: block; 9 | overflow-x: auto; 10 | padding: 0.5em; 11 | background: #23241f; 12 | } 13 | 14 | .hljs, 15 | .hljs-tag, 16 | .hljs-subst { 17 | color: #f8f8f2; 18 | } 19 | 20 | .hljs-strong, 21 | .hljs-emphasis { 22 | color: #a8a8a2; 23 | } 24 | 25 | .hljs-bullet, 26 | .hljs-quote, 27 | .hljs-number, 28 | .hljs-regexp, 29 | .hljs-literal, 30 | .hljs-link { 31 | color: #ae81ff; 32 | } 33 | 34 | .hljs-code, 35 | .hljs-title, 36 | .hljs-section, 37 | .hljs-selector-class { 38 | color: #a6e22e; 39 | } 40 | 41 | .hljs-strong { 42 | font-weight: bold; 43 | } 44 | 45 | .hljs-emphasis { 46 | font-style: italic; 47 | } 48 | 49 | .hljs-keyword, 50 | .hljs-selector-tag, 51 | .hljs-name, 52 | .hljs-attr { 53 | color: #f92672; 54 | } 55 | 56 | .hljs-symbol, 57 | .hljs-attribute { 58 | color: #66d9ef; 59 | } 60 | 61 | .hljs-params, 62 | .hljs-class .hljs-title { 63 | color: #f8f8f2; 64 | } 65 | 66 | .hljs-string, 67 | .hljs-type, 68 | .hljs-built_in, 69 | .hljs-builtin-name, 70 | .hljs-selector-id, 71 | .hljs-selector-attr, 72 | .hljs-selector-pseudo, 73 | .hljs-addition, 74 | .hljs-variable, 75 | .hljs-template-variable { 76 | color: #e6db74; 77 | } 78 | 79 | .hljs-comment, 80 | .hljs-deletion, 81 | .hljs-meta { 82 | color: #75715e; 83 | } 84 | -------------------------------------------------------------------------------- /.documents/whiteboard/themes/whiteboard/source/css/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/euclid1990/laravel/19a5b008c5649aef143b988c233c4fcfbb88557f/.documents/whiteboard/themes/whiteboard/source/css/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /.documents/whiteboard/themes/whiteboard/source/css/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/euclid1990/laravel/19a5b008c5649aef143b988c233c4fcfbb88557f/.documents/whiteboard/themes/whiteboard/source/css/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /.documents/whiteboard/themes/whiteboard/source/css/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/euclid1990/laravel/19a5b008c5649aef143b988c233c4fcfbb88557f/.documents/whiteboard/themes/whiteboard/source/css/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /.documents/whiteboard/themes/whiteboard/source/css/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/euclid1990/laravel/19a5b008c5649aef143b988c233c4fcfbb88557f/.documents/whiteboard/themes/whiteboard/source/css/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | insert_final_newline = true 7 | indent_style = space 8 | indent_size = 4 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | 14 | [*.yml] 15 | indent_size = 2 16 | -------------------------------------------------------------------------------- /.env.dev.example: -------------------------------------------------------------------------------- 1 | APP_NAME=Laravel 2 | APP_ENV=local 3 | APP_KEY= 4 | APP_DEBUG=true 5 | APP_URL=https://localhost:8443 6 | APP_VERSION= 7 | 8 | LOG_CHANNEL=stack 9 | 10 | DB_CONNECTION=mysql 11 | DB_HOST=mysql 12 | DB_PORT=3306 13 | DB_DATABASE=ms_database 14 | DB_USERNAME=ms_user 15 | DB_PASSWORD=ms_password 16 | 17 | BROADCAST_DRIVER=log 18 | CACHE_DRIVER=file 19 | QUEUE_CONNECTION=redis 20 | SESSION_DRIVER=file 21 | SESSION_LIFETIME=120 22 | 23 | REDIS_HOST=redis 24 | REDIS_PASSWORD=rd_password 25 | REDIS_PORT=6379 26 | 27 | MEMCACHED_PERSISTENT_ID=memcached 28 | MEMCACHED_HOST=memcached 29 | MEMCACHED_PORT=11211 30 | MEMCACHED_USERNAME=mem_user 31 | MEMCACHED_PASSWORD=mem_password 32 | 33 | MAIL_DRIVER=smtp 34 | MAIL_HOST=smtp.mailtrap.io 35 | MAIL_PORT=2525 36 | MAIL_USERNAME=null 37 | MAIL_PASSWORD=null 38 | MAIL_ENCRYPTION=null 39 | 40 | AWS_ACCESS_KEY_ID= 41 | AWS_SECRET_ACCESS_KEY= 42 | AWS_DEFAULT_REGION=us-east-1 43 | AWS_BUCKET= 44 | 45 | PUSHER_APP_ID= 46 | PUSHER_APP_KEY= 47 | PUSHER_APP_SECRET= 48 | PUSHER_APP_CLUSTER=mt1 49 | 50 | MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}" 51 | MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}" 52 | 53 | API_CLIENT_ID= 54 | API_CLIENT_SECRET= 55 | 56 | MIX_BASE_URL="${APP_URL}" 57 | MIX_BASIC_AUTHEN="web:123456" 58 | MIX_API_PREFIX="api" 59 | MIX_API_VERSION="v1" 60 | 61 | CHATWORK_API_KEY="" 62 | CHATWORK_ROOM_ID="" 63 | SLACK_HOOK="" 64 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | APP_NAME=Laravel 2 | APP_ENV=local 3 | APP_KEY= 4 | APP_DEBUG=true 5 | APP_URL=http://localhost 6 | APP_VERSION= 7 | 8 | LOG_CHANNEL=stack 9 | 10 | DB_CONNECTION=mysql 11 | DB_HOST=127.0.0.1 12 | DB_PORT=3306 13 | DB_DATABASE=homestead 14 | DB_USERNAME=homestead 15 | DB_PASSWORD=secret 16 | 17 | BROADCAST_DRIVER=log 18 | CACHE_DRIVER=file 19 | QUEUE_CONNECTION=sync 20 | SESSION_DRIVER=file 21 | SESSION_LIFETIME=120 22 | 23 | REDIS_HOST=127.0.0.1 24 | REDIS_PASSWORD=null 25 | REDIS_PORT=6379 26 | 27 | MAIL_DRIVER=smtp 28 | MAIL_HOST=smtp.mailtrap.io 29 | MAIL_PORT=2525 30 | MAIL_USERNAME=null 31 | MAIL_PASSWORD=null 32 | MAIL_ENCRYPTION=null 33 | 34 | AWS_ACCESS_KEY_ID= 35 | AWS_SECRET_ACCESS_KEY= 36 | AWS_DEFAULT_REGION=us-east-1 37 | AWS_BUCKET= 38 | 39 | PUSHER_APP_ID= 40 | PUSHER_APP_KEY= 41 | PUSHER_APP_SECRET= 42 | PUSHER_APP_CLUSTER=mt1 43 | 44 | MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}" 45 | MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}" 46 | 47 | MIX_BASE_URL="${APP_URL}" 48 | MIX_BASIC_AUTHEN="web:123456" 49 | MIX_API_PREFIX="api" 50 | MIX_API_VERSION="v1" 51 | 52 | CHATWORK_API_KEY="" 53 | CHATWORK_ROOM_ID="" 54 | SLACK_HOOK="" 55 | -------------------------------------------------------------------------------- /.envs/dev/cert/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:18.04 2 | 3 | ENV DEBIAN_FRONTEND noninteractive 4 | ENV USERID=1001 GROUPID=1001 5 | 6 | # Install os packages 7 | RUN apt-get update && apt-get install -y \ 8 | sudo \ 9 | openssl \ 10 | apache2-utils \ 11 | --no-install-recommends apt-utils \ 12 | && rm -r /var/lib/apt/lists/* 13 | 14 | COPY cert/rootCA.csr.cnf /scripts/ 15 | 16 | COPY cert/v3.ext /scripts/ 17 | 18 | COPY cert/*.sh /scripts/ 19 | 20 | RUN chmod a+x /scripts/*.sh 21 | 22 | RUN mkdir /files 23 | 24 | # Create new username: cert 25 | RUN useradd -ms /bin/bash cert --no-log-init 26 | # Modify cert user_id:group_id to current host_user_id:host_group_id 27 | RUN usermod -u $USERID cert 28 | RUN groupmod -g $GROUPID cert 29 | 30 | # Set user to running image 31 | USER root 32 | 33 | ENTRYPOINT ["sh", "/scripts/entrypoint.sh"] 34 | 35 | CMD ["/scripts/command.sh", "localhost"] 36 | -------------------------------------------------------------------------------- /.envs/dev/cert/command.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | DOMAIN=${1:-localhost} 4 | 5 | if [[ ! -f "/files/${DOMAIN}.crt" ]]; then 6 | /scripts/create-rootCA.sh 7 | /scripts/create-certs.sh $DOMAIN 8 | fi 9 | 10 | if [[ ! -f "/files/.htpasswd" ]]; then 11 | /scripts/create-htpasswd.sh 12 | fi 13 | 14 | -------------------------------------------------------------------------------- /.envs/dev/cert/create-certs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Create a new private key if one doesnt exist, or use the xeisting one if it does 4 | DOMAIN=$1 5 | NUM_OF_DAYS=999 6 | 7 | openssl req -new -sha256 -nodes -out "/files/$DOMAIN.csr" -newkey rsa:2048 -keyout "/files/$DOMAIN.key" -config /scripts/rootCA.csr.cnf 8 | cat /scripts/v3.ext | sed s/%%DOMAIN%%/"$DOMAIN"/g > /tmp/__v3.ext 9 | openssl x509 -req -in "/files/$DOMAIN.csr" -CA /files/rootCA.pem -CAkey /files/rootCA.key -CAcreateserial -out "/files/$DOMAIN.crt" -days $NUM_OF_DAYS -sha256 -extfile /tmp/__v3.ext 10 | rm /tmp/__v3.ext 11 | -------------------------------------------------------------------------------- /.envs/dev/cert/create-htpasswd.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | htpasswd -b -c /files/.htpasswd $HT_USER $HT_PASSWORD 4 | -------------------------------------------------------------------------------- /.envs/dev/cert/create-rootCA.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Create CA key and cert 4 | openssl genrsa -out /files/rootCA.key 2048 5 | openssl req -subj "/C=VN/ST=Hanoi/L=Hanoi/O=MyCompany/OU=Division/emailAddress=admin@example.com/CN=Localhost Certification Authority" \ 6 | -x509 -new -nodes -key /files/rootCA.key -sha256 -days 1024 -out /files/rootCA.pem 7 | -------------------------------------------------------------------------------- /.envs/dev/cert/entrypoint.sh: -------------------------------------------------------------------------------- 1 | # Change owner of /files directory to user cert 2 | chown -R cert:cert /files 3 | exec runuser -u cert "$@" 4 | -------------------------------------------------------------------------------- /.envs/dev/cert/files/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /.envs/dev/cert/rootCA.csr.cnf: -------------------------------------------------------------------------------- 1 | [req] 2 | default_bits = 2048 3 | prompt = no 4 | default_md = sha256 5 | distinguished_name = dn 6 | 7 | [dn] 8 | C=VN 9 | ST=Hanoi 10 | L=Hanoi 11 | O=MyCompany 12 | OU=Division 13 | emailAddress=admin@example.com 14 | CN=Localhost Certification Authority 15 | -------------------------------------------------------------------------------- /.envs/dev/cert/v3.ext: -------------------------------------------------------------------------------- 1 | authorityKeyIdentifier=keyid,issuer 2 | basicConstraints=CA:FALSE 3 | keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment 4 | subjectAltName = @alt_names 5 | 6 | [alt_names] 7 | DNS.1 = %%DOMAIN%% 8 | -------------------------------------------------------------------------------- /.envs/dev/memcached/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM memcached:1.5.12 2 | -------------------------------------------------------------------------------- /.envs/dev/mysql/.gitignore: -------------------------------------------------------------------------------- 1 | /data 2 | -------------------------------------------------------------------------------- /.envs/dev/mysql/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mysql:5.7 2 | 3 | RUN apt-get update && \ 4 | apt-get install -y vim sudo \ 5 | --no-install-recommends apt-utils \ 6 | && rm -r /var/lib/apt/lists/* 7 | 8 | COPY mysql/entrypoint.sh /usr/local/bin/docker-entrypoint.sh 9 | 10 | RUN chmod a+x /usr/local/bin/docker-entrypoint.sh 11 | 12 | RUN rm /entrypoint.sh 13 | 14 | RUN ln -s /usr/local/bin/docker-entrypoint.sh /entrypoint.sh # backward compatibility 15 | 16 | ENTRYPOINT ["docker-entrypoint.sh"] 17 | 18 | EXPOSE 3306 33060 19 | 20 | CMD ["mysqld"] 21 | -------------------------------------------------------------------------------- /.envs/dev/nginx/.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | -------------------------------------------------------------------------------- /.envs/dev/nginx/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM nginx:1.15.11 2 | 3 | # Install os packages 4 | RUN apt-get update && apt-get install -y \ 5 | vim \ 6 | curl \ 7 | && rm -r /var/lib/apt/lists/* 8 | 9 | COPY nginx/*.sh /scripts/ 10 | 11 | COPY common/wait-for-it.sh /scripts/ 12 | 13 | RUN chmod a+x /scripts/*.sh 14 | 15 | EXPOSE 80 443 16 | 17 | CMD ["/scripts/command.sh"] 18 | -------------------------------------------------------------------------------- /.envs/dev/nginx/command.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | until [[ -f /etc/nginx/certs/localhost.crt && -f /etc/nginx/certs/localhost.key && -f /etc/nginx/certs/.htpasswd ]]; do 4 | echo "Waiting for self-certificates existing..." 5 | sleep 1 6 | done 7 | 8 | /scripts/wait-for-it.sh php:9000 --timeout=300 -- echo 'PHP service is ready!' 9 | 10 | nginx -g 'daemon off;' 11 | -------------------------------------------------------------------------------- /.envs/dev/nginx/conf.d/default.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | listen [::]:80; 4 | server_name _; 5 | return 301 https://$host:8443$request_uri; 6 | } 7 | 8 | server { 9 | error_log /var/www/app/.envs/dev/nginx/logs/error.log; 10 | access_log /var/www/app/.envs/dev/nginx/logs/access.log; 11 | 12 | satisfy any; 13 | # Add basic authentication use auth_basic setting 14 | auth_basic "Staging's Area"; 15 | auth_basic_user_file /etc/nginx/certs/.htpasswd; 16 | # IP whitelist 17 | include /etc/nginx/conf.d/ip-whitelist.conf; 18 | deny all; 19 | 20 | listen 443 ssl default_server; 21 | listen [::]:443 ssl default_server ; 22 | server_name localhost; 23 | 24 | # SSL certificates 25 | ssl_certificate /etc/nginx/certs/localhost.crt; 26 | ssl_certificate_key /etc/nginx/certs/localhost.key; 27 | 28 | # Recommendations from https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html 29 | ssl_ciphers EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH; 30 | ssl_protocols TLSv1.1 TLSv1.2; 31 | ssl_prefer_server_ciphers on; 32 | ssl_session_cache shared:SSL:10m; 33 | 34 | # Disable any limits to avoid HTTP 413 for large image uploads 35 | client_max_body_size 0; 36 | 37 | # Laravel directory 38 | root /var/www/app/public; 39 | index index.php index.html index.htm; 40 | 41 | # Nginx will reject anything not matching / 42 | location / { 43 | try_files $uri $uri/ /index.php$is_args$args; 44 | } 45 | 46 | location ~ \.php$ { 47 | fastcgi_split_path_info ^(.+?\.php)(/.*)$; 48 | if (!-f $document_root$fastcgi_script_name) { 49 | return 404; 50 | } 51 | include fastcgi_params; 52 | fastcgi_pass php-fpm; 53 | fastcgi_index index.php; 54 | fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name; 55 | fastcgi_param DOCUMENT_ROOT $realpath_root; 56 | fastcgi_param HTTP_AUTHORIZATION $http_authorization_bearer; 57 | fastcgi_param HTTP_AUTHORIZATION_BEARER ''; 58 | fastcgi_param REALPATHTEST $realpath_root; 59 | internal; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /.envs/dev/nginx/conf.d/documents.conf: -------------------------------------------------------------------------------- 1 | upstream documents { 2 | server node:4000; 3 | } 4 | 5 | server { 6 | listen 445 ssl; 7 | listen [::]:445 ssl ; 8 | server_name documents; 9 | 10 | # SSL certificates 11 | ssl_certificate /etc/nginx/certs/localhost.crt; 12 | ssl_certificate_key /etc/nginx/certs/localhost.key; 13 | 14 | # Recommendations from https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html 15 | ssl_ciphers EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH; 16 | ssl_protocols TLSv1.1 TLSv1.2; 17 | ssl_prefer_server_ciphers on; 18 | ssl_session_cache shared:SSL:10m; 19 | 20 | location / { 21 | proxy_pass http://documents; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /.envs/dev/nginx/conf.d/ip-whitelist.conf: -------------------------------------------------------------------------------- 1 | # Company's Global IP List 2 | allow 192.168.1.1; 3 | # Customer's Global IP List 4 | allow 192.168.1.2; -------------------------------------------------------------------------------- /.envs/dev/nginx/conf.d/phpmyadmin.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 444 ssl; 3 | listen [::]:444 ssl ; 4 | server_name phpmyadmin; 5 | 6 | # SSL certificates 7 | ssl_certificate /etc/nginx/certs/localhost.crt; 8 | ssl_certificate_key /etc/nginx/certs/localhost.key; 9 | 10 | # Recommendations from https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html 11 | ssl_ciphers EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH; 12 | ssl_protocols TLSv1.1 TLSv1.2; 13 | ssl_prefer_server_ciphers on; 14 | ssl_session_cache shared:SSL:10m; 15 | 16 | # Phpmyadmin directory 17 | root /var/www/app/.envs/dev/phpmyadmin/src/phpMyAdmin-4.8.5; 18 | 19 | index index.php index.html index.htm; 20 | 21 | location / { 22 | index index.html index.htm index.php 23 | try_files $uri /index.php$is_args$args; 24 | } 25 | 26 | location ~ ^/.+\.php(/|$) { 27 | fastcgi_split_path_info ^(.+?\.php)(/.*)$; 28 | if (!-f $document_root$fastcgi_script_name) { 29 | return 404; 30 | } 31 | include fastcgi_params; 32 | fastcgi_pass php-fpm; 33 | fastcgi_index index.php; 34 | fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /.envs/dev/nginx/logs/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/euclid1990/laravel/19a5b008c5649aef143b988c233c4fcfbb88557f/.envs/dev/nginx/logs/.gitkeep -------------------------------------------------------------------------------- /.envs/dev/nginx/nginx.conf: -------------------------------------------------------------------------------- 1 | user nginx; 2 | # Number workers to spawn once it has become bound to the proper IP and port 3 | worker_processes 1; 4 | 5 | error_log /var/log/nginx/error.log warn; 6 | pid /var/run/nginx.pid; 7 | 8 | events { 9 | # Nginx can server 1024 clients/second 10 | worker_connections 1024; 11 | } 12 | 13 | http { 14 | include /etc/nginx/mime.types; 15 | default_type application/octet-stream; 16 | 17 | log_format main '$remote_addr - $remote_user [$time_local] "$request" ' 18 | '$status $body_bytes_sent "$http_referer" ' 19 | '"$http_user_agent" "$http_x_forwarded_for"'; 20 | 21 | access_log /var/log/nginx/access.log main; 22 | 23 | # Nginx will handle gzip compression of responses from the app server 24 | gzip on; 25 | gzip_comp_level 2; 26 | gzip_proxied any; 27 | gzip_types text/plain application/json; 28 | gzip_min_length 1000; 29 | charset utf-8; 30 | sendfile off; 31 | keepalive_timeout 65; 32 | 33 | # PHP-FPM reverse proxy 34 | upstream php-fpm { 35 | server php:9000; 36 | } 37 | 38 | include /etc/nginx/conf.d/*.conf; 39 | } 40 | -------------------------------------------------------------------------------- /.envs/dev/node/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:10.15.3-stretch 2 | 3 | COPY node/*.sh /scripts/ 4 | 5 | RUN chmod a+x /scripts/*.sh 6 | 7 | EXPOSE 80 443 8 | 9 | CMD ["/scripts/command.sh"] 10 | -------------------------------------------------------------------------------- /.envs/dev/node/command.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | yarn install 4 | 5 | # Sleep untils backend api endpoint existing 6 | while [ ! -f /var/www/app/resources/js/endpoint.js ] 7 | do 8 | sleep 3 9 | done 10 | 11 | yarn run dev 12 | 13 | yarn run documents 14 | 15 | sleep infinity 16 | -------------------------------------------------------------------------------- /.envs/dev/php/command.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | /scripts/wait-for-it.sh mysql:3306 --timeout=300 -- echo 'Mysql service is ready!' 4 | 5 | /scripts/passport.sh 6 | 7 | php-fpm 8 | -------------------------------------------------------------------------------- /.envs/dev/php/crontab/cron.daily.logrotate: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | test -x /usr/sbin/logrotate || exit 0 4 | /usr/sbin/logrotate -f /etc/logrotate.conf 5 | -------------------------------------------------------------------------------- /.envs/dev/php/crontab/cron.minutely.schedule: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | test -x php /var/www/app/artisan || exit 0 4 | php /var/www/app/artisan schedule:run >> /dev/null 2>&1 5 | -------------------------------------------------------------------------------- /.envs/dev/php/crontab/crontab: -------------------------------------------------------------------------------- 1 | # /etc/crontab: system-wide crontab 2 | # Unlike any other crontab you don't have to run the `crontab' 3 | # command to install the new version when you edit this file 4 | # and files in /etc/cron.d. These files also have username fields, 5 | # that none of the other crontabs do. 6 | 7 | SHELL=/bin/sh 8 | PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin 9 | 10 | # m h dom mon dow user command 11 | * * * * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.minutely ) 12 | 15 * * * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.hourly ) 13 | 30 10 * * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily ) 14 | 40 10 * * 7 root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly ) 15 | 50 10 1 * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly ) 16 | # 17 | -------------------------------------------------------------------------------- /.envs/dev/php/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copy development environment file if not existing 4 | if [[ ! -f /var/www/app/.env && -f /var/www/app/.env.dev.example ]]; then 5 | cp /var/www/app/.env.dev.example /var/www/app/.env 6 | fi 7 | 8 | # Generate application key if it not set 9 | APP_KEY=$(cat .env | sed -n 's/^APP_KEY=/ /p') 10 | if [[ -z "${APP_KEY// }" ]]; then 11 | php artisan key:generate 12 | fi 13 | 14 | vendorDir=/var/www/app/vendor 15 | # Install composer if it not existing 16 | if [[ ! -d $vendorDir ]]; then 17 | composer install 18 | fi 19 | 20 | vendorOwner=$(stat -c '%U' $vendorDir) 21 | if [ "$vendorOwer" != "php-fpm" ]; then 22 | # Change owner of $vendorDir directory to user php-fpm 23 | sudo chown -R php-fpm:php-fpm $vendorDir 24 | fi 25 | 26 | standardPath=/var/www/app/vendor/squizlabs/php_codesniffer/src/Standards/SunOS 27 | if [ ! -d "$standardPath" ]; then 28 | # Copy php code sniff to vendor 29 | cp -i -r .envs/dev/phpcs/SunOS/ $standardPath 30 | fi 31 | 32 | # Discovery new packages and generate manifest 33 | composer dump-autoload 34 | 35 | # Generate application routes for client 36 | php artisan laroute:generate 37 | 38 | # Starting Supervisor to start the queue process 39 | sudo /etc/init.d/supervisor start 40 | 41 | exec "$@" 42 | -------------------------------------------------------------------------------- /.envs/dev/php/passport.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ $(cat ./.env | grep "API_CLIENT_ID") == "API_CLIENT_ID=" ] || [ $(cat ./.env | grep "API_CLIENT_SECRET") == "API_CLIENT_SECRET=" ]; then 4 | echo "---GENERATING PASSPORT CLIENT ID & SECRET.---" 5 | 6 | passport=$(php artisan passport:client --password --no-interaction) 7 | clientId=$(expr match "$passport" '.*\(Client ID: [[:digit:]]*\)') 8 | clientSecret=$(expr match "$passport" '.*\(Client secret: [[:alnum:]]*\)') 9 | 10 | clientId=${clientId:11} 11 | clientSecret=${clientSecret:15} 12 | 13 | sed -i "s/API_CLIENT_ID=.*/API_CLIENT_ID=$clientId/g" .env 14 | sed -i "s/API_CLIENT_SECRET=.*/API_CLIENT_SECRET=$clientSecret/g" .env 15 | 16 | echo "---PASSPORT CLIENT ID & SECRET IS GENERATED.---" 17 | fi 18 | -------------------------------------------------------------------------------- /.envs/dev/php/php-worker: -------------------------------------------------------------------------------- 1 | /var/www/app/storage/logs/worker.log { 2 | daily 3 | rotate 30 4 | copytruncate 5 | missingok 6 | notifempty 7 | dateext 8 | sharedscripts 9 | postrotate 10 | dir=/var/www/app/storage/logs 11 | day=$(date +%Y%m%d) 12 | dayNew=$(date +%Y-%m-%d) 13 | mv $dir/worker.log-$day $dir/worker-$dayNew.log 14 | endscript 15 | } 16 | -------------------------------------------------------------------------------- /.envs/dev/php/php-worker.conf: -------------------------------------------------------------------------------- 1 | [program:cron] 2 | autorestart=false 3 | command=cron -f 4 | 5 | [program:php-worker] 6 | process_name=%(program_name)s_%(process_num)02d 7 | command=php /var/www/app/artisan queue:work redis --sleep=3 --tries=1 --timeout=180 8 | autostart=true 9 | autorestart=true 10 | user=php-fpm 11 | numprocs=1 12 | redirect_stderr=true 13 | stdout_logfile=/var/www/app/storage/logs/worker.log 14 | stdout_logfile_backups=0 15 | stdout_logfile_maxbytes=0 16 | 17 | [program:php-monitor] 18 | process_name=%(program_name)s_%(process_num)02d 19 | command=php /var/www/app/artisan queue:work redis --queue=monitor --sleep=3 --tries=1 --timeout=180 20 | autostart=true 21 | autorestart=true 22 | user=php-fpm 23 | numprocs=1 24 | redirect_stderr=true 25 | stdout_logfile=/var/www/app/storage/logs/monitor.log 26 | stdout_logfile_backups=0 27 | stdout_logfile_maxbytes=0 28 | -------------------------------------------------------------------------------- /.envs/dev/phpcs/SunOS/ruleset.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | The SunOS Coding Standard package for Code Sniffer. 4 | .documents 5 | .circleci 6 | .github 7 | .envs 8 | public 9 | bootstrap 10 | storage 11 | resources 12 | vendor 13 | node_modules 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /.envs/dev/phpmyadmin/command.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ ! -d "src/phpMyAdmin-4.8.5" ]; then 4 | echo "------ [BEGIN] Extract PhpMyAdmin Source Code ------" 5 | tar -zxf phpMyAdmin-4.8.5.tar.gz -C src/ 6 | echo "------ [END] Extract PhpMyAdmin Source Code ------" 7 | fi 8 | -------------------------------------------------------------------------------- /.envs/dev/phpmyadmin/phpMyAdmin-4.8.5.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/euclid1990/laravel/19a5b008c5649aef143b988c233c4fcfbb88557f/.envs/dev/phpmyadmin/phpMyAdmin-4.8.5.tar.gz -------------------------------------------------------------------------------- /.envs/dev/phpmyadmin/src/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | public/**/*.js 3 | vendor 4 | resources/js/endpoint.js 5 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'extends': [ 3 | 'standard', 4 | 'plugin:vue/recommended' 5 | ], 6 | 'parser': 'vue-eslint-parser', 7 | 'parserOptions': { 8 | "parser": "babel-eslint", 9 | 'ecmaVersion': 2017, 10 | 'sourceType': 'module', 11 | 'ecmaFeatures': { 12 | 'jsx': true, 13 | legacyDecorators: true 14 | } 15 | }, 16 | 'rules': { 17 | 'indent': ['error', 2], 18 | 'quotes': ['warn', 'single'], 19 | 'semi': [1, 'never'], 20 | 'space-before-function-paren': ['error', { 21 | 'anonymous': 'never', 22 | 'named': 'never', 23 | 'asyncArrow': 'always' 24 | }], 25 | 'no-useless-constructor': 'off', 26 | 'no-unused-vars': 'warn', 27 | 'no-new': 'warn', 28 | 'new-cap': 'off', 29 | 'eol-last': ['error', 'always'] 30 | }, 31 | "globals": { 32 | "workbox": true 33 | } 34 | }; 35 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | *.css linguist-vendored 3 | *.scss linguist-vendored 4 | *.js linguist-vendored 5 | CHANGELOG.md export-ignore 6 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## 1. Task Link 2 | 3 | 4 | 5 | ## 2. What you did 6 | 7 | 11 | 12 | ## 3. Screen Shots 13 | 14 | 18 | 19 | ## 4. Checklists 20 | 21 | - [ ] Did you read task requirement? 22 | - [ ] Did you confirm task related question with Team Lead or Brse? 23 | - [ ] Did you check UI is as same as design? 24 | - [ ] Did you check Web behavior as same as requirements? 💣 25 | - [ ] Did you implement and run unit testing? 💣 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /public/hot 3 | /public/storage 4 | /public/mix-manifest.json 5 | /storage/*.key 6 | /resources/js/endpoint.js 7 | /vendor 8 | .env 9 | .phpintel 10 | .phpunit.result.cache 11 | Homestead.json 12 | Homestead.yaml 13 | npm-debug.log 14 | yarn-error.log 15 | .DS_Store 16 | docker-compose.yml 17 | public/examples 18 | reports 19 | package-lock.json 20 | .idea 21 | /coverage 22 | -------------------------------------------------------------------------------- /.stylelintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | public/**/*.css 3 | -------------------------------------------------------------------------------- /.stylelintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'extends': 'stylelint-config-standard', 3 | 'plugins': [ 4 | 'stylelint-scss' 5 | ], 6 | 'rules': { 7 | 'indentation': 2, 8 | 'at-rule-empty-line-before': null, 9 | 'unit-no-unknown': [ true, { 'ignoreUnits': ['x'] }], 10 | 'no-empty-source': null, 11 | 'at-rule-no-unknown': null, 12 | 'scss/at-rule-no-unknown': true 13 | } 14 | }; 15 | -------------------------------------------------------------------------------- /app/Console/Commands/GitGetCommit.php: -------------------------------------------------------------------------------- 1 | writeNewEnvironmentFileWith($hash)) { 43 | return; 44 | } 45 | 46 | $this->info('App version set successfully.'); 47 | } 48 | 49 | /** 50 | * Write a new environment file with the given key. 51 | * 52 | * @param string $key 53 | * @return void 54 | */ 55 | protected function writeNewEnvironmentFileWith($version) 56 | { 57 | file_put_contents($this->laravel->environmentFilePath(), preg_replace( 58 | '/^APP_VERSION=(\s*|.+)$/m', 59 | 'APP_VERSION=' . $version, 60 | file_get_contents($this->laravel->environmentFilePath()) 61 | )); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /app/Console/Kernel.php: -------------------------------------------------------------------------------- 1 | command('inspire') 28 | // ->hourly(); 29 | } 30 | 31 | /** 32 | * Register the commands for the application. 33 | * 34 | * @return void 35 | */ 36 | protected function commands() 37 | { 38 | $this->load(__DIR__.'/Commands'); 39 | 40 | require base_path('routes/console.php'); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /app/Exceptions/Api/ActionException.php: -------------------------------------------------------------------------------- 1 | data = $data; 31 | $this->statusCode = $statusCode; 32 | $this->description = $description; 33 | 34 | parent::__construct($description, $statusCode); 35 | } 36 | 37 | public function getErrorDescription() 38 | { 39 | return $this->getMessage(); 40 | } 41 | 42 | public function getStatusCode() 43 | { 44 | return $this->statusCode; 45 | } 46 | 47 | public function getData() 48 | { 49 | return $this->data; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /app/Exceptions/Api/NotFoundException.php: -------------------------------------------------------------------------------- 1 | $permissionName])); 12 | } 13 | 14 | public static function withId(int $permissionId) 15 | { 16 | return new InvalidArgumentException(__('exception.there_no_permission_id', ['permissionId' => $permissionId])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /app/Exceptions/Permission/RoleDoesNotExist.php: -------------------------------------------------------------------------------- 1 | $roleName])); 12 | } 13 | 14 | public static function withId(int $roleId) 15 | { 16 | return new InvalidArgumentException(__('exception.there_no_role_id', ['roleId' => $roleId])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /app/Exceptions/Permission/UnauthorizedException.php: -------------------------------------------------------------------------------- 1 | $permStr]); 14 | 15 | $exception = new static(Response::HTTP_FORBIDDEN, $message, null, []); 16 | 17 | return $exception; 18 | } 19 | 20 | public static function forPermissions($permissions): self 21 | { 22 | $permStr = implode(', ', $permissions); 23 | $message = __('exception.not_have_permission', ['permissions' => $permStr]); 24 | 25 | $exception = new static(Response::HTTP_FORBIDDEN, $message, null, []); 26 | 27 | return $exception; 28 | } 29 | 30 | public static function notLoggedIn(): self 31 | { 32 | return new static(Response::HTTP_FORBIDDEN, __('exception.not_loggin'), null, []); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /app/Http/Controllers/Api/ApiController.php: -------------------------------------------------------------------------------- 1 | userService = $userService; 27 | $this->authService = $authService; 28 | } 29 | 30 | public function sendResetTokenEmail(ForgotPasswordRequest $request) 31 | { 32 | $email = $request->email; 33 | $updateToken = null; 34 | $user = $this->userService->getUserByEmail($email); 35 | 36 | if ($user) { 37 | $resetToken = $this->authService->generateResetToken($user); 38 | 39 | $this->authService->queueMailResetPassword($user, $resetToken); 40 | 41 | $updateToken = $this->authService->createResetPasswordToken($request->email, $resetToken); 42 | } 43 | 44 | return new AuthResource($updateToken, __FUNCTION__, __('passwords.sent')); 45 | } 46 | 47 | public function reset(ResetPasswordRequest $request) 48 | { 49 | $params = $request->only('password', 'token'); 50 | $reset = $this->authService->resetPassword($params['password'], $params['token']); 51 | 52 | return new AuthResource($reset, 'resetPassword', __('passwords.reset')); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /app/Http/Controllers/Api/UserController.php: -------------------------------------------------------------------------------- 1 | middleware('guest')->except('logout'); 30 | $this->authService = $authService; 31 | } 32 | 33 | /** 34 | * Show the application's login form. 35 | * 36 | * @return \Illuminate\Http\Response 37 | */ 38 | public function showLoginForm() 39 | { 40 | return view('auth.login'); 41 | } 42 | /** 43 | * Handle a login request to the application. 44 | * 45 | * @param \App\Http\Requests\LoginRequest $request 46 | * @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\Response|\Illuminate\Http\JsonResponse 47 | * 48 | * @throws \Illuminate\Validation\ValidationException 49 | */ 50 | public function login(LoginRequest $request) 51 | { 52 | if ($this->authService->attempt($request)) { 53 | $request->session()->regenerate(); 54 | 55 | return redirect(route('home')); 56 | } else { 57 | throw ValidationException::withMessages([ 58 | 'email' => [trans('auth.failed')], 59 | ]); 60 | } 61 | } 62 | /** 63 | * Log the user out of the application. 64 | * 65 | * @param \Illuminate\Http\Request $request 66 | * @return \Illuminate\Http\Response 67 | */ 68 | public function logout(Request $request) 69 | { 70 | auth()->guard()->logout(); 71 | 72 | $request->session()->invalidate(); 73 | 74 | return redirect(route('home')); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /app/Http/Controllers/Web/Auth/RegisterController.php: -------------------------------------------------------------------------------- 1 | middleware('guest'); 42 | $this->userService = $userService; 43 | } 44 | /** 45 | * Show the application registration form. 46 | * 47 | * @return \Illuminate\Http\Response 48 | */ 49 | public function showRegistrationForm() 50 | { 51 | return view('auth.register'); 52 | } 53 | /** 54 | * Handle a registration request for the application. 55 | * 56 | * @param \App\Http\Requests\RegistersUsers $request 57 | * @return \Illuminate\Http\Response 58 | */ 59 | public function register(RegisterRequest $request) 60 | { 61 | event(new Registered($user = $this->userService->store($request->all()))); 62 | 63 | $this->guard()->login($user); 64 | 65 | return $this->registered($request, $user) ?: redirect($this->redirectPath()); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /app/Http/Controllers/Web/Auth/ResetPasswordController.php: -------------------------------------------------------------------------------- 1 | middleware('guest'); 31 | $this->authService = $authService; 32 | } 33 | 34 | /** 35 | * Display the password reset view for the given token. 36 | * 37 | * If no token is present, display the link request form. 38 | * 39 | * @param \Illuminate\Http\Request $request 40 | * @param string|null $token 41 | * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View 42 | */ 43 | public function showResetForm(Request $request, $token = null) 44 | { 45 | return view('auth.passwords.reset')->with( 46 | ['token' => $token] 47 | ); 48 | } 49 | 50 | /** 51 | * Reset the given user's password. 52 | * 53 | * @param \App\Http\Requests\Auth\ResetPasswordRequest 54 | * @return \Illuminate\Http\RedirectResponse 55 | */ 56 | public function reset(ResetPasswordRequest $request) 57 | { 58 | $params = $request->all(); 59 | $reset = $this->authService->resetPassword($params['password'], $params['token']); 60 | 61 | return redirect($this->redirectTo)->with('status', __('passwords.reset')); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /app/Http/Controllers/Web/ExportController.php: -------------------------------------------------------------------------------- 1 | exportService = $exportService; 18 | } 19 | 20 | public function export(ExportFormRequest $request) 21 | { 22 | // phpcs:ignore Squiz.NamingConventions.ValidVariableName 23 | $fileType = $request->file_type; 24 | $fileName = $this->exportService->makeFilename($fileType); 25 | 26 | $data = $this->exportService->getData($fileType, $request); 27 | 28 | $types = config('common.export.types.' . $fileType . '.mime'); 29 | 30 | if ($request->expectsJson()) { 31 | return new ExportResource([ 32 | 'fileName' => $fileName, 33 | 'fileMime' => $types, 34 | 'fileDataBase64' => base64_encode($data['encoded']), 35 | 'fileData' => $data['raw'], 36 | ]); 37 | } 38 | 39 | return response()->streamDownload(function () use ($data) { 40 | echo $data; 41 | }, $fileName); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /app/Http/Controllers/Web/HomeController.php: -------------------------------------------------------------------------------- 1 | middleware('auth'); 17 | } 18 | 19 | /** 20 | * Show the application dashboard. 21 | * 22 | * @return \Illuminate\Contracts\Support\Renderable 23 | */ 24 | public function index() 25 | { 26 | return view('home'); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /app/Http/Controllers/Web/ImportController.php: -------------------------------------------------------------------------------- 1 | importService = $importService; 18 | } 19 | 20 | public function index() 21 | { 22 | $user = Auth::user(); 23 | return view('imports.index', compact('user')); 24 | } 25 | 26 | public function import(ImportFileCsvRequest $request) 27 | { 28 | try { 29 | $this->importService->importFile($request->get('data')); 30 | 31 | return redirect(route('import.create'))->with('message', trans('import.message.success')); 32 | } catch (QueryException $e) { 33 | return redirect()->back()->withErrors([ 34 | 'errors' => trans('import.message.import_failed'), 35 | ]); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /app/Http/Controllers/Web/UserController.php: -------------------------------------------------------------------------------- 1 | prefix = config('web.view_prefix'); 14 | } 15 | 16 | protected function render(array $data = [], string $view = null) 17 | { 18 | $view = $view ?: $this->view; 19 | $compacts = array_merge($this->compacts, $data); 20 | return view($this->prefix . $view, $compacts); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/Http/Middleware/Authenticate.php: -------------------------------------------------------------------------------- 1 | expectsJson()) { 18 | return route('login'); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/Http/Middleware/CheckForMaintenanceMode.php: -------------------------------------------------------------------------------- 1 | guest()) { 13 | throw UnauthorizedException::notLoggedIn(); 14 | } 15 | 16 | if (!auth()->user()->hasPermission($permissions)) { 17 | throw UnauthorizedException::forPermissions($permissions); 18 | } 19 | 20 | return $next($request); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/Http/Middleware/Permission/RoleMiddleware.php: -------------------------------------------------------------------------------- 1 | guest()) { 13 | throw UnauthorizedException::notLoggedIn(); 14 | } 15 | 16 | if (!auth()->user()->hasRole($roles)) { 17 | throw UnauthorizedException::forRoles($roles); 18 | } 19 | 20 | return $next($request); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/Http/Middleware/RedirectIfAuthenticated.php: -------------------------------------------------------------------------------- 1 | check()) { 21 | return redirect('/'); 22 | } 23 | 24 | return $next($request); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/Http/Middleware/TrimStrings.php: -------------------------------------------------------------------------------- 1 | 'required|email', 28 | ]; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /app/Http/Requests/Auth/LoginRequest.php: -------------------------------------------------------------------------------- 1 | 'required|email|exists:users,email', 28 | 'password' => 'required|min:6', 29 | ]; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /app/Http/Requests/Auth/RegisterRequest.php: -------------------------------------------------------------------------------- 1 | 'required', 28 | 'email' => 'required|email|unique:users,email', 29 | 'password' => 'required|min:6|confirmed', 30 | ]; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/Http/Requests/Auth/ResetPasswordRequest.php: -------------------------------------------------------------------------------- 1 | 'required|min:6|confirmed', 29 | 'token' => [ 30 | 'required', 31 | 'exists:password_resets,token', 32 | new CheckValidPasswordResetToken, 33 | ], 34 | ]; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /app/Http/Requests/ExportFormRequest.php: -------------------------------------------------------------------------------- 1 | [ 29 | 'required', 30 | 'in:' . implode(',', array_keys($cfg['types'])), 31 | ], 32 | 'separation' => Rule::requiredIf(function () use ($cfg) { 33 | // phpcs:ignore Squiz.NamingConventions.ValidVariableName 34 | return $this->file_type === $cfg['types']['csv']['value']; 35 | }), 36 | 'encoding' => [ 37 | 'required', 38 | 'in:' . implode(',', array_keys($cfg['encoding'])), 39 | ], 40 | 'export_column' => 'required', 41 | ]; 42 | } 43 | 44 | public function messages() 45 | { 46 | return [ 47 | 'separation.required' => trans('export.message.separation_required'), 48 | 'encoding.required' => trans('export.message.encoding_required'), 49 | 'encoding.in' => trans('export.message.encoding_in'), 50 | 'file_type.required' => trans('export.message.file_type_required'), 51 | 'file_type.in' => trans('export.message.file_type_in'), 52 | 'export_column.required' => trans('export.message.export_column_required'), 53 | ]; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /app/Http/Requests/ImportFileCsvRequest.php: -------------------------------------------------------------------------------- 1 | [ 34 | 'bail', 35 | 'required', 36 | 'max:' . $cfg['max'], 37 | new CheckExtension($cfg['type']), 38 | ], 39 | ]; 40 | } 41 | 42 | /** 43 | * Configure the validator instance. 44 | * 45 | * @param \Illuminate\Validation\Validator $validator 46 | * @return void 47 | */ 48 | 49 | public function withValidator($validator) 50 | { 51 | if (!$validator->fails()) { 52 | $v = Validator::make(['file' => $this->file], [ 53 | 'file' => [new CheckImportFile($this)], 54 | ]); 55 | $v->validate(); 56 | } 57 | } 58 | 59 | public function messages() 60 | { 61 | return [ 62 | 'file.required' => trans('import.message.file_required'), 63 | 'file.max' => trans('import.message.file_max', ['max' => config('common.import.validation.file.max')]), 64 | ]; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /app/Http/Resources/ApiCollection.php: -------------------------------------------------------------------------------- 1 | message = $message; 17 | 18 | parent::__construct($resource); 19 | } 20 | 21 | public function with($request, object $errors = null) 22 | { 23 | if ($errors === null) { 24 | $errors = new stdClass; 25 | } 26 | 27 | return [ 28 | 'message' => $this->message, 29 | 'code' => Response::HTTP_OK, 30 | 'errors' => $errors, 31 | ]; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /app/Http/Resources/ApiResource.php: -------------------------------------------------------------------------------- 1 | message = $message; 19 | $this->errors = $errors; 20 | } 21 | 22 | public function with($request) 23 | { 24 | $this->message = $this->message ?? ''; 25 | $this->errors = $this->errors ?? new stdClass; 26 | 27 | return [ 28 | 'message' => $this->message, 29 | 'errors' => $this->errors, 30 | 'code' => Response::HTTP_OK, 31 | ]; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /app/Http/Resources/AuthResource.php: -------------------------------------------------------------------------------- 1 | method = $method; 13 | } 14 | 15 | public function toArray($request) 16 | { 17 | return $this->{$this->method}(); 18 | } 19 | 20 | public function login() 21 | { 22 | return $this->resource; 23 | } 24 | 25 | public function logout() 26 | { 27 | return [ 28 | 'data' => null, 29 | ]; 30 | } 31 | 32 | public function register() 33 | { 34 | return $this->resource; 35 | } 36 | 37 | public function sendResetTokenEmail() 38 | { 39 | return [ 40 | 'data' => (bool) $this->resource, 41 | ]; 42 | } 43 | 44 | public function resetPassword() 45 | { 46 | return [ 47 | 'data' => (bool) $this->resource, 48 | ]; 49 | } 50 | 51 | public function refreshToken() 52 | { 53 | return $this->resource; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /app/Http/Resources/ExportResource.php: -------------------------------------------------------------------------------- 1 | method = $method; 12 | parent::__construct($resource, $message); 13 | } 14 | 15 | public function toArray($request) 16 | { 17 | return $this->{$this->method}(); 18 | } 19 | 20 | public function export() 21 | { 22 | return [ 23 | 'data' => $this->resource, 24 | ]; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/Http/Resources/UserResource.php: -------------------------------------------------------------------------------- 1 | method = $method; 12 | parent::__construct($resource, $message); 13 | } 14 | 15 | public function toArray($request) 16 | { 17 | return $this->{$this->method}(); 18 | } 19 | 20 | public function show() 21 | { 22 | return [ 23 | 'id' => $this->id, 24 | 'name' => $this->name, 25 | 'email' => $this->email, 26 | 'created_at' => $this->created_at->toDateTimeString(), // phpcs:ignore Squiz.NamingConventions.ValidVariableName 27 | 'updated_at' => $this->updated_at->toDateTimeString(), // phpcs:ignore Squiz.NamingConventions.ValidVariableName 28 | ]; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /app/Libraries/ChatApp/ChatAppException.php: -------------------------------------------------------------------------------- 1 | driver($driver); 18 | } 19 | /** 20 | * {@inheritdoc} 21 | */ 22 | public function getDefaultDriver() 23 | { 24 | return 'chatwork'; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/Libraries/ChatApp/Handlers/Slack.php: -------------------------------------------------------------------------------- 1 | message = $message; 35 | 36 | parent::__construct($client); 37 | } 38 | 39 | public function withEndPoint($endPoint) 40 | { 41 | $this->endPoint = $endPoint; 42 | 43 | return $this; 44 | } 45 | 46 | public function withEnv() 47 | { 48 | $this->endPoint = env('SLACK_HOOK'); 49 | 50 | return $this; 51 | } 52 | 53 | /** 54 | * slack message content data. 55 | * 56 | * @return string 57 | */ 58 | public function withMessage($message) 59 | { 60 | $this->message->content = $message; 61 | 62 | return $this; 63 | } 64 | 65 | /** 66 | * Send Request to Slack. 67 | * 68 | * @throws RequestFailException 69 | * 70 | * @return array 71 | */ 72 | public function dispatch() 73 | { 74 | $this->http->post($this->endPoint, $this->buildJsonPayload( 75 | $this->message 76 | )); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /app/Libraries/ChatApp/Messages/Chatwork.php: -------------------------------------------------------------------------------- 1 | message = $message; 20 | } 21 | 22 | /** 23 | * Reset message to empty string. 24 | */ 25 | public function resetMessage() 26 | { 27 | $this->setMessage(''); 28 | } 29 | 30 | /** 31 | * @return string message 32 | */ 33 | public function getMessage() 34 | { 35 | return $this->message; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /app/Libraries/ChatApp/Messages/Slack.php: -------------------------------------------------------------------------------- 1 | message = $message; 22 | } 23 | 24 | /** 25 | * Reset message to empty string. 26 | */ 27 | public function resetMessage() 28 | { 29 | $this->setMessage(''); 30 | } 31 | 32 | /** 33 | * @return string message 34 | */ 35 | public function getMessage() 36 | { 37 | return $this->message; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /app/Libraries/PermissionRegister.php: -------------------------------------------------------------------------------- 1 | gate = $gate; 22 | } 23 | 24 | /** 25 | * Register the permission check method on the gate. 26 | * 27 | * @return bool 28 | */ 29 | public function registerPermissions() 30 | { 31 | $this->gate->before(function (User $user, string $ability) { 32 | try { 33 | if (method_exists($user, 'hasPermission')) { 34 | return $user->hasPermission($ability) ?: null; 35 | } 36 | } catch (PermissionDoesNotExist $e) { 37 | } 38 | }); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /app/Libraries/helpers.php: -------------------------------------------------------------------------------- 1 | $data])->render(); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /app/Listeners/ExceptionThrownListener.php: -------------------------------------------------------------------------------- 1 | handle('chatwork') 31 | ->withEnv() 32 | ->withMessage(generate_message('notification_template.chatwork', $event)) 33 | ->dispatch(); 34 | resolve('chatapp') 35 | ->handle('slack') 36 | ->withEnv() 37 | ->withMessage(generate_message('notification_template.slack', $event)) 38 | ->dispatch(); 39 | } catch (Throwable $e) { 40 | Log::error($e); 41 | 42 | throw new ChatAppException(); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /app/Mail/MailForgotPassword.php: -------------------------------------------------------------------------------- 1 | token = $token; 26 | $this->user = $user; 27 | $this->url = $url; 28 | } 29 | 30 | /** 31 | * Build the message. 32 | * 33 | * @return $this 34 | */ 35 | public function build() 36 | { 37 | return $this->to($this->user->email) 38 | ->view('emails.mail_forgot_password') 39 | ->with([ 40 | 'url' => $this->url ? $this->url : url(sprintf(config('api.auth.reset_password.url'), $this->token)), 41 | 'name' => $this->user->name, 42 | 'timeOut' => config('api.auth.reset_password.token_timeout'), 43 | ]); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /app/Models/BaseModel.php: -------------------------------------------------------------------------------- 1 | belongsToMany( 18 | Role::class, 19 | 'role_permissions', 20 | 'permission_id', 21 | 'role_id' 22 | ); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/Models/Role.php: -------------------------------------------------------------------------------- 1 | belongsToMany( 20 | Permission::class, 21 | 'role_permissions', 22 | 'role_id', 23 | 'permission_id' 24 | ); 25 | } 26 | 27 | /** 28 | * A role belongs to some users of the model associated with its guard. 29 | */ 30 | public function users(): BelongsToMany 31 | { 32 | return $this->belongsToMany( 33 | User::class, 34 | 'user_roles', 35 | 'role_id', 36 | 'user_id' 37 | ); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /app/Models/User.php: -------------------------------------------------------------------------------- 1 | 'datetime', 42 | ]; 43 | 44 | /** 45 | * A user can be applied to roles. 46 | */ 47 | public function roles(): BelongsToMany 48 | { 49 | return $this->belongsToMany( 50 | Role::class, 51 | 'user_roles', 52 | 'user_id', 53 | 'role_id' 54 | ); 55 | } 56 | 57 | public function setPasswordAttribute($value) 58 | { 59 | $this->attributes['password'] = bcrypt($value); 60 | } 61 | 62 | public function getPermissionsAttribute() 63 | { 64 | if (!$this->relationLoaded('roles') || !$this->roles->first()->relationLoaded('permissions')) { 65 | $this->load('roles.permissions'); 66 | } 67 | 68 | return collect($this->roles->pluck('permissions'))->collapse()->unique(); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /app/Policies/AbstractPolicy.php: -------------------------------------------------------------------------------- 1 | deny($message); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/Providers/AppServiceProvider.php: -------------------------------------------------------------------------------- 1 | 'App\Policies\ModelPolicy', 18 | ]; 19 | 20 | /** 21 | * Register any authentication / authorization services. 22 | * 23 | * @return void 24 | */ 25 | public function boot() 26 | { 27 | $this->registerPolicies(); 28 | 29 | Passport::routes(); 30 | 31 | Passport::tokensExpireIn(now()->addHours(config('api.auth.token_lifetime_hour.access_token'))); 32 | 33 | Passport::refreshTokensExpireIn(now()->addHours(config('api.auth.token_lifetime_hour.refresh_token'))); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /app/Providers/BroadcastServiceProvider.php: -------------------------------------------------------------------------------- 1 | registerManager(); 32 | } 33 | 34 | /** 35 | * Register the chatapp manager. 36 | * 37 | * @return void 38 | */ 39 | protected function registerManager() 40 | { 41 | $this->app->singleton('chatapp', function ($app) { 42 | return tap(new ChatAppManager($app), function ($manager) { 43 | $this->registerHandlers($manager); 44 | }); 45 | }); 46 | } 47 | 48 | /** 49 | * Register chatapp handlers. 50 | * 51 | * @param \App\ChatAppNotification\ChatAppManager $manager 52 | * @return void 53 | */ 54 | protected function registerHandlers($manager) 55 | { 56 | foreach ([ 57 | [ 58 | 'chatwork', 59 | Chatwork::class, 60 | ], 61 | [ 62 | 'slack', 63 | Slack::class, 64 | ], 65 | ] as $driver) { 66 | $manager->extend($driver[0], function ($app) use ($driver) { 67 | return $this->app->make($driver[1]); 68 | }); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /app/Providers/EventServiceProvider.php: -------------------------------------------------------------------------------- 1 | [ 21 | SendEmailVerificationNotification::class, 22 | ], 23 | ExceptionThrown::class => [ 24 | ExceptionThrownListener::class 25 | ], 26 | ]; 27 | 28 | /** 29 | * Register any events for your application. 30 | * 31 | * @return void 32 | */ 33 | public function boot() 34 | { 35 | parent::boot(); 36 | 37 | // 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /app/Providers/RepositoryServiceProvider.php: -------------------------------------------------------------------------------- 1 | app = $app; 25 | } 26 | 27 | /** 28 | * Register the application services. 29 | * 30 | * @return void 31 | */ 32 | public function register() 33 | { 34 | $this->app->bind(UserRepositoryInterface::class, UserRepository::class); 35 | $this->app->bind(PasswordResetTokenRepositoryInterface::class, PasswordResetTokenRepository::class); 36 | $this->app->bind(ImportRepositoryInterface::class, ImportRepository::class); 37 | $this->app->bind(ExportRepositoryInterface::class, ExportRepository::class); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /app/Providers/RouteServiceProvider.php: -------------------------------------------------------------------------------- 1 | mapApiRoutes(); 39 | 40 | $this->mapWebRoutes(); 41 | 42 | // 43 | } 44 | 45 | /** 46 | * Define the "web" routes for the application. 47 | * 48 | * These routes all receive session state, CSRF protection, etc. 49 | * 50 | * @return void 51 | */ 52 | protected function mapWebRoutes() 53 | { 54 | Route::middleware('web') 55 | ->namespace($this->namespace) 56 | ->group(base_path('routes/web.php')); 57 | } 58 | 59 | /** 60 | * Define the "api" routes for the application. 61 | * 62 | * These routes are typically stateless. 63 | * 64 | * @return void 65 | */ 66 | protected function mapApiRoutes() 67 | { 68 | Route::prefix('api') 69 | ->middleware('api') 70 | ->namespace($this->namespace) 71 | ->group(base_path('routes/api.php')); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /app/Repositories/AppRepositoryInterface.php: -------------------------------------------------------------------------------- 1 | model = $import; 19 | } 20 | /** 21 | * @param array $data 22 | * 23 | * @return bool 24 | */ 25 | public function select(array $data) 26 | { 27 | return $this->model->get($data)->toArray(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /app/Repositories/ExportRepositoryInterface.php: -------------------------------------------------------------------------------- 1 | db = $db; 22 | } 23 | 24 | /** 25 | * @return \Illuminate\Database\Query\Builder 26 | */ 27 | protected function query() 28 | { 29 | return $this->db->table('imports'); 30 | } 31 | 32 | /** 33 | * @param array $data 34 | * 35 | * @return bool 36 | */ 37 | public function insert(array $data) 38 | { 39 | return $this->query()->insert($data); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /app/Repositories/ImportRepositoryInterface.php: -------------------------------------------------------------------------------- 1 | getObjectToken($token); 18 | $tokenObj->revoked = 1; 19 | $tokenObj->save(); 20 | 21 | return $tokenObj; 22 | } 23 | 24 | public function getObjectToken($token) 25 | { 26 | return $this->model 27 | ->where('token', $token) 28 | ->first(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /app/Repositories/PasswordResetTokenRepositoryInterface.php: -------------------------------------------------------------------------------- 1 | model 17 | ->resetPasswordToken($token) 18 | ->first(); 19 | } 20 | 21 | public function getUserByEmail($email) 22 | { 23 | return $this->model 24 | ->where('email', $email) 25 | ->first(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/Repositories/UserRepositoryInterface.php: -------------------------------------------------------------------------------- 1 | parameters = $parameters; 22 | } 23 | 24 | /** 25 | * Determine if the validation rule passes. 26 | * 27 | * @param string $attribute 28 | * @param mixed $value 29 | * @return bool 30 | */ 31 | public function passes($attribute, $value) 32 | { 33 | $extension = $value->getClientOriginalExtension(); 34 | return in_array($extension, $this->parameters); 35 | } 36 | 37 | /** 38 | * Get the validation error message. 39 | * 40 | * @return string 41 | */ 42 | public function message() 43 | { 44 | return trans('import.message.file_mimes', ['format' => implode(', ', $this->parameters)]); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /app/Rules/CheckValidPasswordResetToken.php: -------------------------------------------------------------------------------- 1 | getObjectToken($value); 30 | return !$token || !$token->revoked; 31 | } 32 | 33 | /** 34 | * Get the validation error message. 35 | * 36 | * @return string 37 | */ 38 | public function message() 39 | { 40 | return __('passwords.token'); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /app/Services/AppService.php: -------------------------------------------------------------------------------- 1 | repository = $repository; 14 | } 15 | 16 | public function getModel() 17 | { 18 | return $this->repository->getModel(); 19 | } 20 | 21 | public function fetchAll(array $columns = ['*']) 22 | { 23 | return $this->repository->fetchAll($columns); 24 | } 25 | 26 | public function fetchList() 27 | { 28 | return $this->repository->fetchList(); 29 | } 30 | 31 | public function paginateList($params) 32 | { 33 | $page = isset($params['page']) ? $params['page'] : config('common.page_default'); 34 | 35 | return $this->repository->paginateList($page); 36 | } 37 | 38 | public function findById($id, array $columns = ['*']) 39 | { 40 | return $this->repository->findById($id, $columns); 41 | } 42 | 43 | public function store(array $data) 44 | { 45 | return $this->repository->store($data); 46 | } 47 | 48 | public function update($id, array $data) 49 | { 50 | return $this->repository->update($id, $data); 51 | } 52 | 53 | public function delete(array $data) 54 | { 55 | return $this->repository->delete($data); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /app/Services/ImportService.php: -------------------------------------------------------------------------------- 1 | repoImport = $repoImport; 16 | } 17 | 18 | public function importFile($importData) 19 | { 20 | return $this->repoImport->insert($importData); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/Services/UserService.php: -------------------------------------------------------------------------------- 1 | userRepository = $userRepository; 17 | } 18 | 19 | public function paginateList($params) 20 | { 21 | $params = filter($params, ['keyword']); 22 | $page = isset($params['page']) ? $params['page'] : config('common.page_default'); 23 | $keyword = isset($params['keyword']) ? $params['keyword'] : ''; 24 | 25 | return $this->userRepository->paginateList($page, ['*'], $keyword); 26 | } 27 | 28 | public function deleteUserById(int $id) 29 | { 30 | return $this->userRepository->delete($id); 31 | } 32 | 33 | public function getUserByEmail(string $email) 34 | { 35 | return $this->userRepository->getUserByEmail($email); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /artisan: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | make(Illuminate\Contracts\Console\Kernel::class); 34 | 35 | $status = $kernel->handle( 36 | $input = new Symfony\Component\Console\Input\ArgvInput, 37 | new Symfony\Component\Console\Output\ConsoleOutput 38 | ); 39 | 40 | /* 41 | |-------------------------------------------------------------------------- 42 | | Shutdown The Application 43 | |-------------------------------------------------------------------------- 44 | | 45 | | Once Artisan has finished running, we will fire off the shutdown events 46 | | so that any final work may be done by the application before we shut 47 | | down the process. This is the last thing to happen to the request. 48 | | 49 | */ 50 | 51 | $kernel->terminate($input, $status); 52 | 53 | exit($status); 54 | -------------------------------------------------------------------------------- /bootstrap/app.php: -------------------------------------------------------------------------------- 1 | singleton( 30 | Illuminate\Contracts\Http\Kernel::class, 31 | App\Http\Kernel::class 32 | ); 33 | 34 | $app->singleton( 35 | Illuminate\Contracts\Console\Kernel::class, 36 | App\Console\Kernel::class 37 | ); 38 | 39 | $app->singleton( 40 | Illuminate\Contracts\Debug\ExceptionHandler::class, 41 | App\Exceptions\Handler::class 42 | ); 43 | 44 | /* 45 | |-------------------------------------------------------------------------- 46 | | Return The Application 47 | |-------------------------------------------------------------------------- 48 | | 49 | | This script returns the application instance. The instance is given to 50 | | the calling script so we can separate the building of the instances 51 | | from the actual running of the application and sending responses. 52 | | 53 | */ 54 | 55 | return $app; 56 | -------------------------------------------------------------------------------- /bootstrap/cache/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "laravel/laravel", 3 | "type": "project", 4 | "description": "The Laravel Framework.", 5 | "keywords": [ 6 | "framework", 7 | "laravel" 8 | ], 9 | "license": "MIT", 10 | "require": { 11 | "php": "^7.1.3", 12 | "fideloper/proxy": "^4.0", 13 | "guzzlehttp/guzzle": "^6.3", 14 | "laravel/framework": "5.8.*", 15 | "laravel/passport": "^7.3", 16 | "laravel/slack-notification-channel": "^2.0", 17 | "laravel/tinker": "^1.0", 18 | "lord/laroute": "^2.4", 19 | "predis/predis": "^1.1", 20 | "squizlabs/php_codesniffer": "^3.4" 21 | }, 22 | "require-dev": { 23 | "beyondcode/laravel-dump-server": "^1.0", 24 | "filp/whoops": "^2.0", 25 | "fzaninotto/faker": "^1.4", 26 | "mockery/mockery": "^1.0", 27 | "nunomaduro/collision": "^2.0", 28 | "phpunit/phpunit": "^7.5" 29 | }, 30 | "config": { 31 | "optimize-autoloader": true, 32 | "preferred-install": "dist", 33 | "sort-packages": true 34 | }, 35 | "extra": { 36 | "laravel": { 37 | "dont-discover": [] 38 | } 39 | }, 40 | "autoload": { 41 | "psr-4": { 42 | "App\\": "app/" 43 | }, 44 | "files": [ 45 | "app/Libraries/helpers.php" 46 | ], 47 | "classmap": [ 48 | "database/seeds", 49 | "database/factories" 50 | ] 51 | }, 52 | "autoload-dev": { 53 | "psr-4": { 54 | "Tests\\": "tests/" 55 | } 56 | }, 57 | "minimum-stability": "dev", 58 | "prefer-stable": true, 59 | "scripts": { 60 | "post-autoload-dump": [ 61 | "Illuminate\\Foundation\\ComposerScripts::postAutoloadDump", 62 | "@php artisan package:discover --ansi" 63 | ], 64 | "post-root-package-install": [ 65 | "@php -r \"file_exists('.env') || copy('.env.example', '.env');\"" 66 | ], 67 | "post-create-project-cmd": [ 68 | "@php artisan key:generate --ansi" 69 | ] 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /config/api.php: -------------------------------------------------------------------------------- 1 | 'v1', 5 | 'prefix' => 'api', 6 | 'auth' => [ 7 | 'reset_password' => [ 8 | 'token_timeout' => 60, 9 | 'url' => 'reset-password/%s', 10 | ], 11 | 'token_lifetime_hour' => [ 12 | 'access_token' => 1, 13 | 'refresh_token' => 48, 14 | ], 15 | ], 16 | ]; 17 | -------------------------------------------------------------------------------- /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/common.php: -------------------------------------------------------------------------------- 1 | 12, 5 | 'page_default' => 1, 6 | 'import' => [ 7 | 'validation' => [ 8 | 'name' => [ 9 | 'max' => 25, 10 | ], 11 | 'file' => [ 12 | 'header' => [ 13 | 'id' => 'import.header_text.id', 14 | 'name' => 'import.header_text.name', 15 | 'created_at' => 'import.header_text.created_at', 16 | ], 17 | 'type' => ['csv','tsv','xls','xlsx'], 18 | 'max' => 4096, 19 | ], 20 | ], 21 | ], 22 | 'export' => [ 23 | 'file_name' => 'Export-%s', 24 | 'types' => [ 25 | 'xlsx' => [ 26 | 'label' => 'export.file_type.excel', 27 | 'value' => 'xlsx', 28 | 'mime' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 29 | ], 30 | 'csv' => [ 31 | 'label' => 'export.file_type.csv', 32 | 'value' => 'csv', 33 | 'mime' => 'text/csv', 34 | 'separation' => [ 35 | 'tab' => [ 36 | 'label' => 'export.separate_char.tab', 37 | 'value' => '\t', 38 | ], 39 | 'comma' => [ 40 | 'label' => 'export.separate_char.comma', 41 | 'value' => ',', 42 | ], 43 | 'semi_colon' => [ 44 | 'label' => 'export.separate_char.semi_colon', 45 | 'value' => ';', 46 | ], 47 | ], 48 | ], 49 | ], 50 | 'export_column' => [ 51 | 'id' => 'export.export_column.id', 52 | 'name' => 'export.export_column.name', 53 | 'created_at' => 'export.export_column.created_at', 54 | 'updated_at' => 'export.export_column.updated_at', 55 | ], 56 | 'encoding' => [ 57 | 'utf8' => 'UTF-8', 58 | 'shiftjis' => 'Shift-JIS', 59 | 'eucjp' => 'EUC-JP', 60 | ], 61 | ], 62 | ]; 63 | -------------------------------------------------------------------------------- /config/hashing.php: -------------------------------------------------------------------------------- 1 | 'bcrypt', 19 | 20 | /* 21 | |-------------------------------------------------------------------------- 22 | | Bcrypt Options 23 | |-------------------------------------------------------------------------- 24 | | 25 | | Here you may specify the configuration options that should be used when 26 | | passwords are hashed using the Bcrypt algorithm. This will allow you 27 | | to control the amount of time it takes to hash the given password. 28 | | 29 | */ 30 | 31 | 'bcrypt' => [ 32 | 'rounds' => env('BCRYPT_ROUNDS', 10), 33 | ], 34 | 35 | /* 36 | |-------------------------------------------------------------------------- 37 | | Argon Options 38 | |-------------------------------------------------------------------------- 39 | | 40 | | Here you may specify the configuration options that should be used when 41 | | passwords are hashed using the Argon algorithm. These will allow you 42 | | to control the amount of time it takes to hash the given password. 43 | | 44 | */ 45 | 46 | 'argon' => [ 47 | 'memory' => 1024, 48 | 'threads' => 2, 49 | 'time' => 2, 50 | ], 51 | 52 | ]; 53 | -------------------------------------------------------------------------------- /config/laroute.php: -------------------------------------------------------------------------------- 1 | 'resources/js', 9 | 10 | /* 11 | * The destination filename for the javascript file. 12 | */ 13 | 'filename' => 'endpoint', 14 | 15 | /* 16 | * The namespace for the helper functions. By default this will bind them to 17 | * `window.laroute`. 18 | */ 19 | 'namespace' => 'endpoint', 20 | 21 | /* 22 | * Generate absolute URLs 23 | * 24 | * Set the Application URL in config/app.php 25 | */ 26 | 'absolute' => false, 27 | 28 | /* 29 | * The Filter Method 30 | * 31 | * 'all' => All routes except "'laroute' => false" 32 | * 'only' => Only "'laroute' => true" routes 33 | * 'force' => All routes, ignored "laroute" route parameter 34 | */ 35 | 'filter' => 'all', 36 | 37 | /* 38 | * Controller Namespace 39 | * 40 | * Set here your controller namespace (see RouteServiceProvider -> $namespace) for cleaner action calls 41 | * e.g. 'App\Http\Controllers' 42 | */ 43 | 'action_namespace' => 'Api', 44 | 45 | /* 46 | * The path to the template `laroute.js` file. This is the file that contains 47 | * the ported helper Laravel url/route functions and the route data to go 48 | * with them. 49 | */ 50 | 'template' => 'vendor/lord/laroute/src/templates/laroute.js', 51 | 52 | /* 53 | * Appends a prefix to URLs. By default the prefix is an empty string. 54 | * 55 | */ 56 | 'prefix' => '', 57 | 58 | ]; 59 | -------------------------------------------------------------------------------- /config/permission.php: -------------------------------------------------------------------------------- 1 | [ 5 | 'admin' => 'admin', 6 | ], 7 | 8 | 'permission' => [ 9 | 'user' => [ 10 | 'view' => 'view-user', 11 | 'create' => 'create-user', 12 | 'update' => 'update-user', 13 | 'delete' => 'delete-user', 14 | ], 15 | ], 16 | 17 | 'role_permission' => [ 18 | 'admin' => [ 19 | 'user.view', 20 | 'user.create', 21 | 'user.update', 22 | 'user.delete', 23 | ], 24 | ], 25 | ]; 26 | -------------------------------------------------------------------------------- /config/services.php: -------------------------------------------------------------------------------- 1 | [ 18 | 'domain' => env('MAILGUN_DOMAIN'), 19 | 'secret' => env('MAILGUN_SECRET'), 20 | 'endpoint' => env('MAILGUN_ENDPOINT', 'api.mailgun.net'), 21 | ], 22 | 23 | 'postmark' => [ 24 | 'token' => env('POSTMARK_TOKEN'), 25 | ], 26 | 27 | 'ses' => [ 28 | 'key' => env('AWS_ACCESS_KEY_ID'), 29 | 'secret' => env('AWS_SECRET_ACCESS_KEY'), 30 | 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'), 31 | ], 32 | 33 | 'sparkpost' => [ 34 | 'secret' => env('SPARKPOST_SECRET'), 35 | ], 36 | 37 | 'stripe' => [ 38 | 'model' => App\User::class, 39 | 'key' => env('STRIPE_KEY'), 40 | 'secret' => env('STRIPE_SECRET'), 41 | 'webhook' => [ 42 | 'secret' => env('STRIPE_WEBHOOK_SECRET'), 43 | 'tolerance' => env('STRIPE_WEBHOOK_TOLERANCE', 300), 44 | ], 45 | ], 46 | 47 | ]; 48 | -------------------------------------------------------------------------------- /config/view.php: -------------------------------------------------------------------------------- 1 | [ 17 | resource_path('views'), 18 | ], 19 | 20 | /* 21 | |-------------------------------------------------------------------------- 22 | | Compiled View Path 23 | |-------------------------------------------------------------------------- 24 | | 25 | | This option determines where all the compiled Blade templates will be 26 | | stored for your application. Typically, this is within the storage 27 | | directory. However, as usual, you are free to change this value. 28 | | 29 | */ 30 | 31 | 'compiled' => env( 32 | 'VIEW_COMPILED_PATH', 33 | realpath(storage_path('framework/views')) 34 | ), 35 | 36 | ]; 37 | -------------------------------------------------------------------------------- /config/web.php: -------------------------------------------------------------------------------- 1 | 'web', 5 | ]; 6 | -------------------------------------------------------------------------------- /database/.gitignore: -------------------------------------------------------------------------------- 1 | *.sqlite 2 | -------------------------------------------------------------------------------- /database/factories/ImportFactory.php: -------------------------------------------------------------------------------- 1 | define(Import::class, function (Faker $faker) { 19 | return [ 20 | 'name' => $faker->name, 21 | ]; 22 | }); 23 | -------------------------------------------------------------------------------- /database/factories/PermissionFactory.php: -------------------------------------------------------------------------------- 1 | define(Permission::class, function (Faker $faker) { 9 | return [ 10 | 'name' => $faker->name, 11 | ]; 12 | }); 13 | -------------------------------------------------------------------------------- /database/factories/RoleFactory.php: -------------------------------------------------------------------------------- 1 | define(Role::class, function (Faker $faker) { 10 | return [ 11 | 'name' => $faker->name, 12 | ]; 13 | }); 14 | -------------------------------------------------------------------------------- /database/factories/UserFactory.php: -------------------------------------------------------------------------------- 1 | define(User::class, function (Faker $faker) { 19 | return [ 20 | 'name' => $faker->name, 21 | 'email' => $faker->unique()->safeEmail, 22 | 'email_verified_at' => now(), 23 | 'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password 24 | 'remember_token' => Str::random(10), 25 | ]; 26 | }); 27 | -------------------------------------------------------------------------------- /database/migrations/2014_10_12_000000_create_users_table.php: -------------------------------------------------------------------------------- 1 | bigIncrements('id'); 18 | $table->string('name'); 19 | $table->string('email')->unique(); 20 | $table->timestamp('email_verified_at')->nullable(); 21 | $table->string('password'); 22 | $table->rememberToken(); 23 | $table->timestamps(); 24 | }); 25 | } 26 | 27 | /** 28 | * Reverse the migrations. 29 | * 30 | * @return void 31 | */ 32 | public function down() 33 | { 34 | Schema::dropIfExists('users'); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /database/migrations/2014_10_12_100000_create_password_resets_table.php: -------------------------------------------------------------------------------- 1 | bigIncrements('id'); 18 | $table->string('email')->index(); 19 | $table->string('token'); 20 | $table->tinyInteger('revoked')->default(0); 21 | $table->timestamps(); 22 | }); 23 | } 24 | 25 | /** 26 | * Reverse the migrations. 27 | * 28 | * @return void 29 | */ 30 | public function down() 31 | { 32 | Schema::dropIfExists('password_resets'); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /database/migrations/2019_08_19_102724_create_imports_table.php: -------------------------------------------------------------------------------- 1 | increments('id'); 18 | $table->string('name'); 19 | $table->timestamps(); 20 | }); 21 | } 22 | 23 | /** 24 | * Reverse the migrations. 25 | * 26 | * @return void 27 | */ 28 | public function down() 29 | { 30 | Schema::dropIfExists('imports'); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /database/seeds/DatabaseSeeder.php: -------------------------------------------------------------------------------- 1 | call(UserTableSeeder::class); 15 | $this->call(RolePermissionSeeder::class); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /database/seeds/RolePermissionSeeder.php: -------------------------------------------------------------------------------- 1 | $v]; 22 | } 23 | } 24 | foreach (config('permission.role') as $key => $value) { 25 | $role[] = ['name' => $value]; 26 | } 27 | 28 | Role::insert($role); 29 | Permission::insert($permission); 30 | 31 | foreach (config('permission.role_permission') as $key => $value) { 32 | $role = Role::where('name', $key)->first(); 33 | foreach ($value as $v) { 34 | $role->assignPermission(config('permission.permission.' . $v)); 35 | } 36 | } 37 | 38 | $users = User::get(); 39 | foreach ($users as $key => $user) { 40 | $user->assignRole(Role::all()->random()); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /database/seeds/UserTableSeeder.php: -------------------------------------------------------------------------------- 1 | 'Admin', 18 | 'email' => 'admin@example.com', 19 | 'password' => bcrypt(123456), 20 | ], 21 | [ 22 | 'name' => 'Member', 23 | 'email' => 'member@example.com', 24 | 'password' => bcrypt(123456), 25 | ], 26 | ]; 27 | User::insert($dump); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /mergeManifest.js: -------------------------------------------------------------------------------- 1 | let mix = require('laravel-mix'); 2 | let ManifestPlugin = require('laravel-mix/src/webpackPlugins/ManifestPlugin'); 3 | let merge = require('lodash').merge; 4 | 5 | /* 6 | * Because we compile css and js file in 2 seperated command, 7 | * so to prevent mix-manifest.json is overwrited by follow occured command, this function help to merge it all. 8 | */ 9 | 10 | module.exports = (config) => { 11 | config.plugins.forEach((plugin, index) => { 12 | if (plugin instanceof ManifestPlugin) { 13 | config.plugins.splice(index, 1); 14 | } 15 | }); 16 | 17 | config.plugins.push(new class { 18 | apply(compiler) { 19 | 20 | compiler.plugin('emit', (curCompiler, callback) => { 21 | let stats = curCompiler.getStats().toJson(); 22 | 23 | try { 24 | Mix.manifest.manifest = merge(Mix.manifest.read(), Mix.manifest.manifest); 25 | } catch (e) { 26 | 27 | } 28 | 29 | Mix.manifest.transform(stats).refresh(); 30 | callback(); 31 | }); 32 | } 33 | }) 34 | }; 35 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 13 | ./tests/Unit 14 | 15 | 16 | 17 | ./tests/Feature 18 | 19 | 20 | 21 | 22 | ./app 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /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/css/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /public/export.csv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/euclid1990/laravel/19a5b008c5649aef143b988c233c4fcfbb88557f/public/export.csv -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/euclid1990/laravel/19a5b008c5649aef143b988c233c4fcfbb88557f/public/favicon.ico -------------------------------------------------------------------------------- /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/js/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: 3 | -------------------------------------------------------------------------------- /public/web.config: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /resources/js/App.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 18 | 19 | 28 | -------------------------------------------------------------------------------- /resources/js/app.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * First we will load all of this project's JavaScript dependencies which 4 | * includes Vue and other libraries. It is a great starting point when 5 | * building robust, powerful web applications using Vue and Laravel. 6 | */ 7 | import App from '@/App.vue' 8 | import router from '@/router' 9 | 10 | import { i18n } from '@/utils' 11 | import store from '@/store' 12 | 13 | import BootstrapVue from 'bootstrap-vue' 14 | import VeeValidate from 'vee-validate' 15 | import VueSweetalert2 from 'vue-sweetalert2' 16 | import Fragment from 'vue-fragment' 17 | import Vue from 'vue' 18 | 19 | window.endpoint = require('./endpoint') 20 | 21 | Vue.use(Fragment.Plugin) 22 | Vue.use(BootstrapVue) 23 | Vue.use(VueSweetalert2) 24 | Vue.use(VeeValidate) 25 | 26 | new Vue({ 27 | render: h => h(App), 28 | i18n, 29 | router, 30 | store 31 | }).$mount('#app') 32 | -------------------------------------------------------------------------------- /resources/js/constants/index.js: -------------------------------------------------------------------------------- 1 | export const ACCESS_TOKEN = 'access_token' 2 | export const DEFAULT_LANGUAGE = 'en' 3 | -------------------------------------------------------------------------------- /resources/js/langs/en.js: -------------------------------------------------------------------------------- 1 | export default { 2 | en: { 3 | error: { 4 | token_expired: { 5 | title: 'Access token expired', 6 | text: 'Your access token had been expired' 7 | }, 8 | server: { 9 | 500: 'Internal server error', 10 | text: 'Something wrong with server' 11 | }, 12 | forbidden: { 13 | 403: 'Client Error', 14 | text: 'You do not have permission to access on this serve' 15 | }, 16 | not_found: { 17 | 404: 'Client Error', 18 | text: 'The requested resource could not be found' 19 | }, 20 | unknown: { 21 | title: 'Unknown error', 22 | text: 'Request error' 23 | } 24 | }, 25 | button: { 26 | swal: { 27 | ok: 'Ok !', 28 | cancel: 'Cancel !' 29 | } 30 | }, 31 | export: { 32 | export_column: { 33 | id: 'ID', 34 | name: 'Name', 35 | created_at: 'Created At', 36 | updated_at: 'Updated At' 37 | }, 38 | file_type: { 39 | excel: 'excel', 40 | csv: 'csv' 41 | }, 42 | separate_char: { 43 | tab: 'Tab', 44 | comma: 'Comma', 45 | semi_colon: 'Semi Colon' 46 | }, 47 | title: 'Export table imports to csv file', 48 | choose_file_label: 'Choose an File type', 49 | choose_separate_label: 'Choose a separate char', 50 | choose_encoding: 'Choose an type encoding', 51 | choose_field: 'Choose field', 52 | export: 'Export', 53 | file_type_validate: 'File type', 54 | separate_char_validate: 'Separate char', 55 | encoding_type_validate: 'Encoding type', 56 | allow_column_validate: 'Export column' 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /resources/js/langs/vi.js: -------------------------------------------------------------------------------- 1 | export default { 2 | vi: { 3 | error: { 4 | token_expired: { 5 | title: 'Access token expired', 6 | text: 'Your access token had been expired' 7 | }, 8 | server: 'Something wrong with server' 9 | }, 10 | button: { 11 | swal: { 12 | ok: 'Ok !', 13 | cancel: 'Cancel !' 14 | } 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /resources/js/mixins/RedirectIfAuthenticated.js: -------------------------------------------------------------------------------- 1 | import { mapGetters } from 'vuex' 2 | 3 | export default { 4 | computed: { 5 | ...mapGetters({ 6 | check: 'auth/check' 7 | }) 8 | }, 9 | 10 | methods: { 11 | __protectRoute() { 12 | if (this.check) { 13 | this.__redirect() 14 | } 15 | }, 16 | 17 | __redirect() { 18 | const redirect = { 19 | path: this.$router.resolve({ name: 'dashboard' }).href 20 | } 21 | 22 | this.$router.push(redirect) 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /resources/js/pages/Auth/LoginPage.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 29 | 30 | 31 | 33 | -------------------------------------------------------------------------------- /resources/js/pages/Auth/RegisterPage.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 29 | 30 | 31 | 33 | -------------------------------------------------------------------------------- /resources/js/pages/DashboardPage.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 23 | 24 | 25 | 35 | -------------------------------------------------------------------------------- /resources/js/pages/Layout/AppLayout.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 15 | 16 | 17 | 19 | -------------------------------------------------------------------------------- /resources/js/router/middlewares/auth.js: -------------------------------------------------------------------------------- 1 | export default function auth({ next, router }) { 2 | if (!localStorage.getItem('access_token')) { 3 | return router.push({ name: 'login' }) 4 | } 5 | 6 | return next() 7 | } 8 | -------------------------------------------------------------------------------- /resources/js/store/auth/mutation-types.js: -------------------------------------------------------------------------------- 1 | // auth.js 2 | export const LOGOUT = 'LOGOUT' 3 | export const LOGIN_SUCCESS = 'SAVE_TOKEN' 4 | export const LOGIN_FAILURE = 'FETCH_USER' 5 | export const FETCH_USER = 'UPDATE_USER' 6 | export const UPDATE_TOKEN = 'UPDATE_TOKEN' 7 | -------------------------------------------------------------------------------- /resources/js/store/index.js: -------------------------------------------------------------------------------- 1 | import Vuex from 'vuex' 2 | import Vue from 'vue' 3 | import * as auth from '@/store/auth' 4 | 5 | Vue.use(Vuex) 6 | 7 | const store = new Vuex.Store({ 8 | modules: { 9 | auth 10 | } 11 | }) 12 | 13 | export default store 14 | -------------------------------------------------------------------------------- /resources/js/utils/env.js: -------------------------------------------------------------------------------- 1 | export default function env(e, d = '') { 2 | if (typeof process.env[e] === 'undefined' || process.env[e] === '') return d 3 | 4 | return process.env[e] 5 | } 6 | -------------------------------------------------------------------------------- /resources/js/utils/i18n/formatter.js: -------------------------------------------------------------------------------- 1 | import MessageFormat from 'messageformat' 2 | import { DEFAULT_LANGUAGE } from '@/constants' 3 | 4 | export default class CustomFormatter { 5 | constructor(options = {}) { 6 | this._locale = options.locale || DEFAULT_LANGUAGE 7 | this._formatter = new MessageFormat(this._locale) 8 | this._caches = Object.create(null) 9 | } 10 | 11 | interpolate(message, values) { 12 | let fn = this._caches[message] 13 | if (!fn) { 14 | fn = this._formatter.compile(message, this._locale) 15 | this._caches[message] = fn 16 | } 17 | return [fn(values)] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /resources/js/utils/i18n/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import VueI18n from 'vue-i18n' 3 | import Formatter from '@/utils/i18n/formatter' 4 | import axios from 'axios' 5 | 6 | Vue.use(VueI18n) 7 | 8 | const messages = require(`@/langs/${window.config.lang}`).default 9 | 10 | const loadedLanguages = [] 11 | const locale = window.config.lang 12 | const formatter = new Formatter({ locale }) 13 | 14 | const i18n = new VueI18n({ 15 | locale, 16 | formatter, 17 | messages, 18 | silentTranslationWarn: false 19 | }) 20 | 21 | loadedLanguages.push(locale) 22 | 23 | function setI18nLanguage(lang) { 24 | i18n.locale = lang 25 | axios.defaults.headers.common['Accept-Language'] = lang 26 | document.querySelector('html').setAttribute('lang', lang) 27 | 28 | return lang 29 | } 30 | 31 | const $t = i18n.tc.bind(i18n) 32 | 33 | function loadLanguageAsync(lang) { 34 | if (i18n.locale !== lang) { 35 | if (!loadedLanguages.includes(lang)) { 36 | return import(/* webpackChunkName: "lang-[request]" */ `@/langs/${lang}`).then(msgs => { 37 | i18n.setLocaleMessage(lang, msgs.default) 38 | loadedLanguages.push(lang) 39 | 40 | return setI18nLanguage(lang) 41 | }) 42 | } 43 | 44 | return Promise.resolve(setI18nLanguage(lang)) 45 | } 46 | 47 | return Promise.resolve(lang) 48 | } 49 | 50 | export { 51 | i18n, 52 | $t, 53 | loadLanguageAsync 54 | } 55 | -------------------------------------------------------------------------------- /resources/js/utils/index.js: -------------------------------------------------------------------------------- 1 | import '@/utils/api' 2 | import { i18n } from './i18n' 3 | 4 | export { 5 | i18n 6 | } 7 | -------------------------------------------------------------------------------- /resources/js/utils/route.js: -------------------------------------------------------------------------------- 1 | import env from '@/utils/env' 2 | 3 | const URL_PREFIX = '/' + env('MIX_API_PREFIX', 'api') + '/' + env('MIX_API_VERSION', 'v1') + '/' 4 | 5 | const ROUTE_PREFIX = env('MIX_API_PREFIX', 'api') + '.' + env('MIX_API_VERSION', 'v1') + '.' 6 | 7 | const route = (name, parameters = {}) => { 8 | return window.endpoint.route(ROUTE_PREFIX + name, parameters) 9 | } 10 | 11 | const url = (url, parameters = {}) => { 12 | return window.endpoint.url(URL_PREFIX + url, parameters) 13 | } 14 | 15 | export { 16 | route, 17 | url 18 | } 19 | -------------------------------------------------------------------------------- /resources/js/utils/swal.js: -------------------------------------------------------------------------------- 1 | import { $t } from '@/utils/i18n' 2 | import Sweetalert2 from 'sweetalert2' 3 | 4 | const base = { 5 | reverseButtons: true, 6 | confirmButtonText: $t('button.swal.ok'), 7 | cancelButtonText: $t('button.swal.cancel') 8 | } 9 | 10 | const baseconfig = { 11 | warning: { 12 | ...base, 13 | type: 'warning' 14 | 15 | }, 16 | error: { 17 | ...base, 18 | type: 'error' 19 | 20 | }, 21 | success: { 22 | ...base, 23 | type: 'success' 24 | } 25 | } 26 | 27 | export default function swal(type, config) { 28 | return Sweetalert2.fire({ 29 | ...baseconfig[type], 30 | ...config 31 | }) 32 | } 33 | -------------------------------------------------------------------------------- /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 | 'login' => 'Login', 19 | 'logout' => 'Logout success.', 20 | 'register' => 'Register', 21 | 22 | 'email_address' => 'Email address', 23 | 'reset_password' => 'Reset password', 24 | 'name' => 'Name', 25 | 'password' => 'Password', 26 | 'confirm_password' => 'Confirm Password', 27 | 'remember_me' => 'Remember me', 28 | 'forgot_your_password' => 'Forgot your password?', 29 | 'send_password_reset_link' => 'Send password reset link', 30 | 31 | 'verify_link_notice' => 'Before proceeding, please check your email for a verification link.', 32 | 'verify_link_not_receive' => 'If you did not receive the email', 33 | 'verify_link_resend' => 'click here to request another', 34 | 'verify_link_success' => 'A fresh verification link has been sent to your email address.', 35 | 'verify_title' => 'Verify Your Email Address', 36 | 37 | ]; 38 | -------------------------------------------------------------------------------- /resources/lang/en/common.php: -------------------------------------------------------------------------------- 1 | 'Unknown', 13 | ]; 14 | -------------------------------------------------------------------------------- /resources/lang/en/exception.php: -------------------------------------------------------------------------------- 1 | "Request have exception", 5 | "action" => "Action exception", 6 | "store" => "Not store database", 7 | "store_multiple" => "Not store multiple database", 8 | "update_multiple" => "Not update multiple database", 9 | "update" => "Not update database", 10 | "delete" => "Delete fail", 11 | "restore" => "Restore fail", 12 | "remove" => "Remove fail", 13 | "not_found" => "Item not exists", 14 | "not_owner" => "Not owner", 15 | "unknown_error" => "Unknown error", 16 | "data_invalid" => "Data invalid", 17 | // Role and permission exception 18 | 'not_have_role' => 'User does not have the right roles. Necessary roles are ":roles"', 19 | 'not_have_permission' => 'User does not have the right permissions. Necessary permissions are ":permissions"', 20 | 'not_have_role_and_permission' => 'User does not have the right permissions. Necessary permissions are ":permissions"', 21 | 'not_loggin' => 'User is not logged in.', 22 | 'there_no_role_name' => 'There is no permission named ":roleName"', 23 | 'there_no_role_id' => 'There is no permission with id ":roleId"', 24 | 'there_no_permission_name' => 'There is no permission named ":permissionName"', 25 | 'there_no_permission_id' => 'There is no permission with id ":permissionId"', 26 | ]; 27 | -------------------------------------------------------------------------------- /resources/lang/en/export.php: -------------------------------------------------------------------------------- 1 | [ 5 | 'separation_required' => 'The Separation field is required!', 6 | 'encoding_required' => 'The Encoding field is required!', 7 | 'encoding_in' => 'Encoding field not on whitelist!', 8 | 'file_type_required' => 'The File Type field is required!', 9 | 'file_type_in' => 'The File Type field must be csv or xlsx', 10 | 'export_column_required' => 'The Export Column field is required!' 11 | ], 12 | 'header_export' => [ 13 | 'id' => 'ID', 14 | 'name' => 'Name', 15 | 'created_at' => 'Created At', 16 | 'updated_at' => 'Update At', 17 | ], 18 | ]; 19 | -------------------------------------------------------------------------------- /resources/lang/en/http_message.php: -------------------------------------------------------------------------------- 1 | "Not Modified", 5 | "400" => "Invalid Request", 6 | "401" => "Unauthorized", 7 | "403" => "Access Denied", 8 | "404" => "Not Found", 9 | "405" => "Method not Allowed", 10 | "422" => "Validator error", 11 | "500" => "Internal Server Error", 12 | "502" => "Bad Gateway", 13 | "503" => "Service Unavailable", 14 | "504" => "Gateway Timeout", 15 | ]; 16 | -------------------------------------------------------------------------------- /resources/lang/en/import.php: -------------------------------------------------------------------------------- 1 | [ 5 | 'file_required' => 'The import file is required !', 6 | 'file_mimes' => 'The import file must be a file of type :format', 7 | 'file_max' => 'The import file may not be greater than :max Kb.', 8 | 'success' => 'Data imported successfully !', 9 | 'error_row_name' => 'Name is invalid at row :row, column :column', 10 | 'error_header' => 'The import file header is missing or invalid', 11 | 'error_element' => 'Not enough fields at row :row', 12 | 'import_failed' => 'Integrity constraint violation. Import file failed', 13 | ], 14 | 'header_text' => [ 15 | 'id' => 'ID', 16 | 'name' => 'Name', 17 | 'created_at' => 'Created At', 18 | ], 19 | 'index' => [ 20 | 'title' => 'Import File', 21 | 'error_validation' => 'The validation error message', 22 | 'import' => 'Import', 23 | ], 24 | ]; 25 | -------------------------------------------------------------------------------- /resources/lang/en/pagination.php: -------------------------------------------------------------------------------- 1 | '« Previous', 17 | 'next' => 'Next »', 18 | 19 | ]; 20 | -------------------------------------------------------------------------------- /resources/lang/en/passwords.php: -------------------------------------------------------------------------------- 1 | 'Passwords must be at least eight 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/sass/_mixins.scss: -------------------------------------------------------------------------------- 1 | // ====================================================== 2 | // Abstracts :: Mixins 3 | // ====================================================== 4 | 5 | @mixin padding-none() { 6 | padding: 0; 7 | } 8 | -------------------------------------------------------------------------------- /resources/sass/_variables.scss: -------------------------------------------------------------------------------- 1 | 2 | // Body 3 | $body-bg: #f8fafc; 4 | 5 | // Typography 6 | $font-family-sans-serif: "Nunito", sans-serif; 7 | $font-size-base: 0.9rem; 8 | $line-height-base: 1.6; 9 | 10 | // Colors 11 | $blue: #3490dc; 12 | $indigo: #6574cd; 13 | $purple: #9561e2; 14 | $pink: #f66d9b; 15 | $red: #e3342f; 16 | $orange: #f6993f; 17 | $yellow: #ffed4a; 18 | $green: #38c172; 19 | $teal: #4dc0b5; 20 | $cyan: #6cb2eb; 21 | $white: #fff; 22 | $black: #000; 23 | $gray-light: #f7f7f7; 24 | -------------------------------------------------------------------------------- /resources/sass/app.scss: -------------------------------------------------------------------------------- 1 | 2 | // Fonts 3 | @import url('https://fonts.googleapis.com/css?family=Nunito'); 4 | 5 | // Variables 6 | @import 'variables'; 7 | @import 'mixins'; 8 | 9 | // Bootstrap 10 | @import '~bootstrap/scss/bootstrap'; 11 | @import '~bootstrap-vue/src/index.scss'; 12 | 13 | .navbar-laravel { 14 | background-color: #fff; 15 | box-shadow: 0 2px 4px rgba(0, 0, 0, 0.04); 16 | } 17 | -------------------------------------------------------------------------------- /resources/views/auth/passwords/email.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.app') 2 | 3 | @section('content') 4 |
5 |
6 |
7 |
8 |
{{ __('auth.reset_password') }}
9 | 10 |
11 | @if (session('status')) 12 | 15 | @endif 16 | 17 |
18 | @csrf 19 | 20 |
21 | 22 | 23 |
24 | 25 | 26 | @error('email') 27 | 28 | {{ $message }} 29 | 30 | @enderror 31 |
32 |
33 | 34 |
35 |
36 | 39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | @endsection 48 | -------------------------------------------------------------------------------- /resources/views/auth/verify.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.app') 2 | 3 | @section('content') 4 |
5 |
6 |
7 |
8 |
{{ __('auth.verify_title') }}
9 | 10 |
11 | @if (session('resent')) 12 | 15 | @endif 16 | 17 | {{ __('auth.verify_link_notice') }} 18 | {{ __('auth.verify_link_not_receive') }}, {{ __('auth.verify_link_resend') }}. 19 |
20 |
21 |
22 |
23 |
24 | @endsection 25 | -------------------------------------------------------------------------------- /resources/views/client.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | {{ config('app.name', 'Laravel') }} 12 | 13 | 14 |
15 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /resources/views/emails/mail_forgot_password.blade.php: -------------------------------------------------------------------------------- 1 |
Follow this link to reset password: Reset Password
2 | -------------------------------------------------------------------------------- /resources/views/home.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.app') 2 | 3 | @section('content') 4 |
5 |
6 |
7 |
8 |
Dashboard
9 | 10 |
11 | @if (session('status')) 12 | 15 | @endif 16 | 17 | You are logged in! 18 |
19 |
20 |
21 |
22 |
23 | @endsection 24 | -------------------------------------------------------------------------------- /resources/views/imports/index.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.app') 2 | 3 | @section('content') 4 | 5 | @if (count($errors)) 6 |
7 | @foreach ($errors->all() as $err) 8 | {{ $err }} 9 | @endforeach 10 |
11 | @endif 12 | @if(Session::has('message')) 13 |

{{ Session::get('message') }}

14 | @endif 15 |
16 |
17 | 18 |
19 | {{ csrf_field() }} 20 |
21 | 22 | 23 |
24 |
25 |
26 |
27 | @endsection 28 | -------------------------------------------------------------------------------- /resources/views/notification_template/chatwork.blade.php: -------------------------------------------------------------------------------- 1 | [toall][info][title]{{ $data->message }}[/title]Exception: {{ $data->context['exception'] ?: __('common.unknown') }} 2 | File: {{ $data->context['file'] ?: __('common.unknown') }} 3 | Line: {{ $data->context['line'] ?: __('common.unknown') }} 4 | User id: {{ isset($data->context['user_id']) ? $data->context['user_id'] : __('common.unknown') }} 5 | Route url: {{ $data->context['route_url'] ?: __('common.unknown') }} 6 | Git commit: {{ $data->context['commit'] ?: __('common.unknown') }} 7 | Server Ip: {{ $data->context['server_ip'] ?: __('common.unknown') }} 8 | Client Ip: {{ $data->context['client_ip'] ?: __('common.unknown') }} 9 | [/info] 10 | -------------------------------------------------------------------------------- /resources/views/notification_template/slack.blade.php: -------------------------------------------------------------------------------- 1 | Exception: {{ $data->context['exception'] ?: __('common.unknown') }} 2 | File: {{ $data->context['file'] ?: __('common.unknown') }} 3 | Line: {{ $data->context['line'] ?: __('common.unknown') }} 4 | User id: {{ isset($data->context['user_id']) ? $data->context['user_id'] : __('common.unknown') }} 5 | Route url: {{ $data->context['route_url'] ?: __('common.unknown') }} 6 | Git commit: {{ $data->context['commit'] ?: __('common.unknown') }} 7 | Server Ip: {{ $data->context['server_ip'] ?: __('common.unknown') }} 8 | Client Ip: {{ $data->context['client_ip'] ?: __('common.unknown') }} 9 | -------------------------------------------------------------------------------- /routes/api.php: -------------------------------------------------------------------------------- 1 | 'Api', 'prefix' => 'v1', 'as' => 'api.v1.'], function () { 17 | Route::group(['namespace' => 'Auth'], function () { 18 | Route::post('login', 'LoginController@login')->name('login'); 19 | Route::post('token/refresh', 'LoginController@refreshToken')->name('token.refresh'); 20 | Route::post('register', 'LoginController@register')->name('register'); 21 | Route::post('password/email', 'ForgotPasswordController@sendResetTokenEmail')->name('password.reset.email'); 22 | Route::post('password/reset', 'ForgotPasswordController@reset')->name('password.reset'); 23 | 24 | Route::group(['middleware' => ['auth:api']], function () { 25 | Route::post('logout', 'LoginController@logout')->name('logout'); 26 | }); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /routes/channels.php: -------------------------------------------------------------------------------- 1 | id === (int) $id; 16 | }); 17 | -------------------------------------------------------------------------------- /routes/console.php: -------------------------------------------------------------------------------- 1 | comment(Inspiring::quote()); 18 | })->describe('Display an inspiring quote'); 19 | -------------------------------------------------------------------------------- /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 | !data/ 3 | !.gitignore 4 | -------------------------------------------------------------------------------- /storage/framework/cache/data/.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(); 19 | 20 | return $app; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /tests/Feature/Http/Controller/Web/Auth/ForgetPasswordControllerTest.php: -------------------------------------------------------------------------------- 1 | get(route('password.request')); 19 | $response->assertSuccessful(); 20 | $response->assertViewIs('auth.passwords.email'); 21 | } 22 | 23 | public function testUserReceivesAnEmailWithAPasswordResetLink() 24 | { 25 | Mail::fake(); 26 | $user = factory(User::class)->create([ 27 | 'email' => 'phamtritrung39@gmail.com', 28 | 'password' => $password = '12345678', 29 | ]); 30 | 31 | $response = $this->post(route('password.email'), [ 32 | 'email' => $user->email, 33 | ]); 34 | 35 | $response->assertStatus(302); 36 | $this->assertNotNull($token = DB::table('password_resets')->first()); 37 | 38 | Mail::assertQueued(\App\Mail\MailForgotPassword::class, function ($mail) use ($user) { 39 | $fakeMail = new \ReflectionClass($mail); 40 | $mailUser = $fakeMail->getProperty('user'); 41 | $mailUser->setAccessible(true); 42 | $mailClone = $mailUser->getValue($mail); 43 | 44 | return $mailClone->id === $user->id; 45 | }); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /tests/TestCase.php: -------------------------------------------------------------------------------- 1 | assertContains($message, $array); 21 | } 22 | 23 | /** 24 | * Check a message exist in array error of ValidationException 25 | * 26 | * @param Illuminate\Validation\ValidationException $e 27 | * @param message $message 28 | */ 29 | public function assertValidatorExceptionContainErrorMsg(ValidationException $e, $message) 30 | { 31 | $allMessage = $e->validator->getMessageBag()->all(); 32 | $this->assertContainErrorMessage($message, $allMessage); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /tests/Unit/ExampleTest.php: -------------------------------------------------------------------------------- 1 | assertTrue(true); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /tests/Unit/Http/Controller/Web/Auth/LoginControllerTest.php: -------------------------------------------------------------------------------- 1 | manager = app('session'); 30 | $this->controller = $this->app->make('App\Http\Controllers\Web\Auth\LoginController'); 31 | } 32 | 33 | public function testUserCanLoginWithCorrectCredentials() 34 | { 35 | $this->withoutMiddleware(); 36 | $user = factory(User::class)->create([ 37 | 'password' => $password = '123456', 38 | ]); 39 | 40 | $request = new LoginRequest(); 41 | 42 | $request->headers->set('content-type', 'application/json'); 43 | $request->setJson(new ParameterBag([ 44 | 'email' => $user->email, 45 | 'password' => $password, 46 | ])); 47 | $request->setMethod('POST'); 48 | $request->setLaravelSession($this->manager->driver()); 49 | 50 | $response = $this->controller->login($request); 51 | 52 | $this->assertInstanceOf(RedirectResponse::class, $response); 53 | $this->assertEquals(route('home'), $response->headers->get('Location')); 54 | $this->assertAuthenticatedAs($user); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /tests/Unit/Http/Controller/Web/Auth/RegisterControllerTest.php: -------------------------------------------------------------------------------- 1 | manager = app('session'); 29 | $this->controller = $this->app->make('App\Http\Controllers\Web\Auth\RegisterController'); 30 | } 31 | 32 | public function testUserCanRegister() 33 | { 34 | $this->withoutMiddleware(); 35 | 36 | $data = [ 37 | 'name' => 'John Doe', 38 | 'email' => 'john@example.com', 39 | 'password' => '12345678', 40 | 'password_confirmation' => '12345678', 41 | ]; 42 | 43 | $request = new RegisterRequest(); 44 | 45 | $request->headers->set('content-type', 'application/json'); 46 | $request->setJson(new ParameterBag($data)); 47 | $request->setMethod('POST'); 48 | $request->setLaravelSession($this->manager->driver()); 49 | 50 | $response = $this->controller->register($request); 51 | 52 | $this->assertInstanceOf(RedirectResponse::class, $response); 53 | $this->assertEquals(route('home'), $response->headers->get('Location')); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /tests/Unit/Http/Middleware/PermissionMiddlewareTest.php: -------------------------------------------------------------------------------- 1 | permissionMiddleware = new PermissionMiddleware($this->app); 25 | } 26 | 27 | public function testGuestCanNotAccessRouteHasPermissionMiddleware() 28 | { 29 | $this->assertEquals($this->runMiddleware($this->permissionMiddleware, 'testPermission'), 403); 30 | } 31 | 32 | public function testUserCanAccessRouteHasRoleMiddleware() 33 | { 34 | $role = factory(Role::class)->create(); 35 | $user = factory(User::class)->create(); 36 | $permission = factory(Permission::class)->create(); 37 | $user->assignRole($role); 38 | $role->assignPermission($permission); 39 | $this->actingAs($user); 40 | 41 | $this->assertEquals($this->runMiddleware($this->permissionMiddleware, $permission->name), 200); 42 | } 43 | 44 | protected function runMiddleware($middleware, $parameter) 45 | { 46 | try { 47 | return $middleware->handle(new Request(), function () { 48 | return (new Response())->setContent(''); 49 | }, $parameter)->status(); 50 | } catch (UnauthorizedException $e) { 51 | return $e->getStatusCode(); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /tests/Unit/Http/Middleware/RoleMiddlewareTest.php: -------------------------------------------------------------------------------- 1 | roleMiddleware = new RoleMiddleware($this->app); 24 | } 25 | 26 | public function testGuestCanNotAccessRouteHasRoleMiddleware() 27 | { 28 | $this->assertEquals($this->runMiddleware($this->roleMiddleware, 'testRole'), 403); 29 | } 30 | 31 | public function testUserCanAccessRouteHasRoleMiddleware() 32 | { 33 | $role = factory(Role::class)->create(); 34 | $user = factory(User::class)->create(); 35 | $user->assignRole($role); 36 | 37 | $this->actingAs($user); 38 | 39 | $this->assertEquals($this->runMiddleware($this->roleMiddleware, $role->name), 200); 40 | } 41 | 42 | protected function runMiddleware($middleware, $parameter) 43 | { 44 | try { 45 | return $middleware->handle(new Request(), function () { 46 | return (new Response())->setContent(''); 47 | }, $parameter)->status(); 48 | } catch (UnauthorizedException $e) { 49 | return $e->getStatusCode(); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /tests/Unit/Libraries/PermissionRegisterTest.php: -------------------------------------------------------------------------------- 1 | afterApplicationCreated(function () { 19 | $this->gate = app()->make(Gate::class); 20 | $this->permissionRegister = new PermissionRegister($this->gate); 21 | }); 22 | 23 | parent::setUp(); 24 | } 25 | /** 26 | * Register the permission check method on the gate. 27 | * 28 | * @return bool 29 | */ 30 | public function testGateBeforeCallbacksReceiveClosure() 31 | { 32 | $this->permissionRegister->registerPermissions(); 33 | 34 | $gate = new \ReflectionClass(app()->make(Gate::class)); 35 | 36 | $beforeCallbacks = $gate->getProperty('beforeCallbacks'); 37 | $beforeCallbacks->setAccessible(true); 38 | 39 | $this->assertEquals(true, collect($beforeCallbacks)->isNotEmpty()); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /tests/Unit/Models/PermissionTest.php: -------------------------------------------------------------------------------- 1 | runConfigurationAssertions(new Permission()); 14 | } 15 | 16 | public function testRolesRelation() 17 | { 18 | $m = new Permission(); 19 | $r = $m->roles(); 20 | $this->assertBelongsToManyRelation($r, $m, new Role(), 'permission_id', 'role_id'); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /tests/Unit/Models/RoleTest.php: -------------------------------------------------------------------------------- 1 | runConfigurationAssertions(new Role()); 15 | } 16 | 17 | public function testUsersRelation() 18 | { 19 | $m = new Role(); 20 | $r = $m->users(); 21 | $this->assertBelongsToManyRelation($r, $m, new User(), 'role_id', 'user_id'); 22 | } 23 | 24 | public function testPermissionsRelation() 25 | { 26 | $m = new Role(); 27 | $r = $m->permissions(); 28 | $this->assertBelongsToManyRelation($r, $m, new Permission(), 'role_id', 'permission_id'); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /tests/Unit/Models/UserTest.php: -------------------------------------------------------------------------------- 1 | runConfigurationAssertions( 14 | new User(), 15 | [ 16 | 'name', 17 | 'email', 18 | 'password', 19 | ], 20 | [ 21 | 'password', 22 | 'remember_token', 23 | ], 24 | ['*'], 25 | [], 26 | [ 27 | 'id' => 'int', 28 | 'email_verified_at' => 'datetime', 29 | ] 30 | ); 31 | } 32 | 33 | public function testRolesRelation() 34 | { 35 | $m = new User(); 36 | $r = $m->roles(); 37 | $this->assertBelongsToManyRelation($r, $m, new Role(), 'user_id', 'role_id'); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /tests/Unit/Repositories/ExportRepositoryTest.php: -------------------------------------------------------------------------------- 1 | afterApplicationCreated(function () { 25 | $this->modelMock = Mockery::mock(Import::class); 26 | }); 27 | parent::setUp(); 28 | } 29 | public function testExportRepository() 30 | { 31 | $fields = [ 32 | 'id', 33 | 'name', 34 | ]; 35 | $repo = new ExportRepository($this->modelMock); 36 | 37 | $data = factory(Import::class)->make(['id' => 1]); 38 | $dataCollect = collect([$data]); 39 | $this->modelMock->shouldReceive('get') 40 | ->once() 41 | ->andReturn($dataCollect); 42 | 43 | $result = $repo->select($fields); 44 | $result = collect($result); 45 | 46 | $this->assertTrue($result->contains('id', $data->id)); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /tests/Unit/Repositories/ImportRepositoryTest.php: -------------------------------------------------------------------------------- 1 | allows() 32 | ->table() 33 | ->with(m::any()) 34 | ->andReturnUsing(function ($table) use ($connection) { 35 | return (new Builder( 36 | $connection, 37 | new SQLiteGrammar(), 38 | new Processor() 39 | ))->from($table); 40 | }); 41 | return $connection; 42 | } 43 | 44 | public function testInsertRepo() 45 | { 46 | $c = $this->mockDatabaseConnection(); 47 | $repo = $this->makeRepository($c); 48 | $data = [ 49 | 'id' => 15, 50 | 'name' => 'nam', 51 | 'created_at' => '09/04/19', 52 | ]; 53 | $c->shouldReceive('insert') 54 | ->once() 55 | ->withArgs([ 56 | 'insert into "imports" ("id", "name", "created_at") values (?, ?, ?)', 57 | array_values($data), 58 | ]) 59 | ->andReturn(true); 60 | $result = $repo->insert($data); 61 | $this->assertEquals(true, $result); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /tests/Unit/Services/ImportServiceTest.php: -------------------------------------------------------------------------------- 1 | afterApplicationCreated(function () { 23 | $this->importRepoMock = Mockery::mock(ImportRepositoryInterface::class); 24 | }); 25 | 26 | parent::setUp(); 27 | } 28 | 29 | public function testImportFileData() 30 | { 31 | $data = [ 32 | 'id' => 15, 33 | 'name' => 'nam', 34 | 'created_at' => '09/04/19', 35 | ]; 36 | $service = new ImportService($this->importRepoMock); 37 | $this->importRepoMock->shouldReceive('insert') 38 | ->once() 39 | ->andReturn(true); 40 | $response = $service->importFile($data); 41 | $this->assertEquals($response, true); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /tests/files/data_check_header_rule.csv: -------------------------------------------------------------------------------- 1 | ID,Name,CreatedAt 2 | 15,以上です,19/09/01 3 | 16,さん,19/09/02 4 | 17,thanh,19/09/03 5 | -------------------------------------------------------------------------------- /tests/files/data_check_row_rule.csv: -------------------------------------------------------------------------------- 1 | ID,Name,Created At 2 | 15,以上です,19/09/01 3 | 16,さん,19/09/02 4 | 17,19/09/03 5 | -------------------------------------------------------------------------------- /tests/files/data_check_rule.csv: -------------------------------------------------------------------------------- 1 | ID,Name,Created At 2 | 15,以上です,19/09/01 3 | 16,さん,19/09/02 4 | 17,thanh,19/09/03 5 | -------------------------------------------------------------------------------- /webpack.css.mix.js: -------------------------------------------------------------------------------- 1 | const mix = require('laravel-mix') 2 | const path = require('path') 3 | const mergeManifest = require('./mergeManifest') 4 | 5 | mix.extend('mergeManifest', mergeManifest) 6 | /* 7 | |-------------------------------------------------------------------------- 8 | | Mix Asset Management 9 | |-------------------------------------------------------------------------- 10 | | 11 | | Mix provides a clean, fluent API for defining some Webpack build steps 12 | | for your Laravel application. By default, we are compiling the Sass 13 | | file for the application as well as bundling up all the JS files. 14 | | 15 | */ 16 | 17 | mix.webpackConfig({ 18 | output: { 19 | chunkFilename: 'js/chunks/[name].js' 20 | }, 21 | resolve: { 22 | alias : { 23 | sass: path.resolve(__dirname, 'resources/sass'), 24 | }, 25 | }, 26 | }) 27 | 28 | mix.sass('resources/sass/app.scss', 'public/css') 29 | .mergeManifest(); 30 | 31 | if (mix.inProduction()) { 32 | mix.version() 33 | } else { 34 | mix.sourceMaps() 35 | } 36 | -------------------------------------------------------------------------------- /webpack.js.mix.js: -------------------------------------------------------------------------------- 1 | const mix = require('laravel-mix') 2 | const path = require('path') 3 | const mergeManifest = require('./mergeManifest') 4 | 5 | mix.extend('mergeManifest', mergeManifest) 6 | /* 7 | |-------------------------------------------------------------------------- 8 | | Mix Asset Management 9 | |-------------------------------------------------------------------------- 10 | | 11 | | Mix provides a clean, fluent API for defining some Webpack build steps 12 | | for your Laravel application. By default, we are compiling the Sass 13 | | file for the application as well as bundling up all the JS files. 14 | | 15 | */ 16 | 17 | mix.webpackConfig({ 18 | resolve: { 19 | alias: { 20 | '@': path.resolve(__dirname, 'resources/js'), 21 | 'sass': path.resolve(__dirname, 'resources/sass'), 22 | }, 23 | } 24 | }) 25 | 26 | mix.js('resources/js/app.js', 'public/js') 27 | .extract() 28 | .mergeManifest(); 29 | 30 | if (mix.inProduction()) { 31 | mix.version() 32 | } else { 33 | mix.sourceMaps() 34 | } 35 | --------------------------------------------------------------------------------