├── .babelrc ├── .dockerignore ├── .editorconfig ├── .env.example ├── .gitattributes ├── .gitignore ├── Dockerfile ├── LICENSE ├── README.md ├── app ├── Article.php ├── Category.php ├── Comment.php ├── Console │ ├── Commands │ │ ├── BlogInstall.php │ │ └── CreateAdmin.php │ └── Kernel.php ├── Discussion.php ├── Exceptions │ ├── Handler.php │ └── UploadException.php ├── Follower.php ├── Helpers.php ├── Http │ ├── Controllers │ │ ├── Api │ │ │ ├── ApiController.php │ │ │ ├── ArticleController.php │ │ │ ├── CategoryController.php │ │ │ ├── CommentController.php │ │ │ ├── DiscussionController.php │ │ │ ├── HomeController.php │ │ │ ├── LinkController.php │ │ │ ├── MeController.php │ │ │ ├── PermissionsController.php │ │ │ ├── RoleController.php │ │ │ ├── SystemController.php │ │ │ ├── TagController.php │ │ │ ├── UploadController.php │ │ │ ├── UserController.php │ │ │ └── VisitorController.php │ │ ├── ArticleController.php │ │ ├── Auth │ │ │ ├── AuthController.php │ │ │ ├── ForgotPasswordController.php │ │ │ ├── LoginController.php │ │ │ ├── RegisterController.php │ │ │ └── ResetPasswordController.php │ │ ├── CategoryController.php │ │ ├── Controller.php │ │ ├── DiscussionController.php │ │ ├── HomeController.php │ │ ├── LinkController.php │ │ ├── SettingController.php │ │ ├── TagController.php │ │ └── UserController.php │ ├── Kernel.php │ ├── Middleware │ │ ├── Authenticate.php │ │ ├── CheckForMaintenanceMode.php │ │ ├── EncryptCookies.php │ │ ├── MustBeAdmin.php │ │ ├── PermissionMiddleware.php │ │ ├── RedirectIfAuthenticated.php │ │ ├── TrimStrings.php │ │ ├── TrustProxies.php │ │ └── VerifyCsrfToken.php │ └── Requests │ │ ├── ArticleRequest.php │ │ ├── CategoryRequest.php │ │ ├── CommentRequest.php │ │ ├── DiscussionRequest.php │ │ ├── ImageRequest.php │ │ ├── LinkRequest.php │ │ ├── TagRequest.php │ │ └── UserRequest.php ├── Link.php ├── Model.php ├── ModelFilters │ ├── ArticleFilter.php │ ├── CategoryFilter.php │ ├── CommentFilter.php │ ├── DiscussionFilter.php │ ├── LinkFilter.php │ ├── RoleFilter.php │ ├── TagFilter.php │ ├── UserFilter.php │ └── VisitorFilter.php ├── Notifications │ ├── FollowedUser.php │ ├── GotVote.php │ ├── MentionedUser.php │ └── ReceivedComment.php ├── Policies │ ├── ArticlePolicy.php │ ├── CommentPolicy.php │ ├── DiscussionPolicy.php │ ├── Policy.php │ └── UserPolicy.php ├── Providers │ ├── AppServiceProvider.php │ ├── AuthServiceProvider.php │ ├── BroadcastServiceProvider.php │ ├── EventServiceProvider.php │ └── RouteServiceProvider.php ├── Scopes │ ├── DraftScope.php │ └── StatusScope.php ├── Support │ ├── Response.php │ └── Transform.php ├── Tag.php ├── Tools │ ├── FileManager │ │ ├── BaseManager.php │ │ └── UpyunManager.php │ ├── IP.php │ ├── Markdowner.php │ └── Mention.php ├── Traits │ ├── BelongsToUser.php │ ├── FollowTrait.php │ ├── HasComments.php │ └── HasTags.php ├── Transformers │ ├── ArticleTransformer.php │ ├── CategoryTransformer.php │ ├── CommentTransformer.php │ ├── DiscussionTransformer.php │ ├── EmptyTransformer.php │ ├── LinkTransformer.php │ ├── PermissionTransformer.php │ ├── RoleTransformer.php │ ├── TagTransformer.php │ ├── UserTransformer.php │ └── VisitorTransformer.php ├── User.php └── Visitor.php ├── artisan ├── bootstrap ├── app.php └── cache │ └── .gitignore ├── composer.json ├── composer.lock ├── config ├── app.php ├── auth.php ├── blog.php ├── broadcasting.php ├── cache.php ├── compile.php ├── cors.php ├── database.php ├── eloquentfilter.php ├── filesystems.php ├── hashing.php ├── image.php ├── logging.php ├── mail.php ├── permission.php ├── queue.php ├── services.php ├── session.php ├── view.php └── vote.php ├── database ├── .gitignore ├── factories │ └── ModelFactory.php ├── migrations │ ├── .gitkeep │ ├── 2014_10_12_000000_create_users_table.php │ ├── 2014_10_12_100000_create_password_resets_table.php │ ├── 2016_09_02_065857_create_articles_table.php │ ├── 2016_09_02_065920_create_tags_table.php │ ├── 2016_09_02_065952_create_visitors_table.php │ ├── 2016_09_02_070119_create_categories_table.php │ ├── 2016_09_02_070132_create_discussions_table.php │ ├── 2016_09_02_070151_create_comments_table.php │ ├── 2016_09_13_022056_create_links_table.php │ ├── 2016_11_11_163610_create_taggables_table.php │ ├── 2016_12_11_153312_create_followers_table.php │ ├── 2016_12_12_171655_create_notifications_table.php │ ├── 2016_12_12_205419_create_failed_jobs_table.php │ └── 2018_05_22_091255_create_permission_tables.php └── seeds │ ├── .gitkeep │ ├── ArticlesTableSeeder.php │ ├── CategoriesTableSeeder.php │ ├── CommentsTableSeeder.php │ ├── DatabaseSeeder.php │ ├── DiscussionsTableSeeder.php │ ├── LinksTableSeeder.php │ ├── PermissionTableSeeder.php │ ├── TagsTableSeeder.php │ ├── UsersTableSeeder.php │ └── VisitorsTableSeeder.php ├── entrypoint.sh ├── package.json ├── phpunit.xml ├── public ├── .gitignore ├── .htaccess ├── favicon.ico ├── images │ ├── default.png │ └── favicon.ico ├── index.php ├── robots.txt └── web.config ├── resources ├── js │ ├── App.vue │ ├── app.js │ ├── bootstrap.js │ ├── config │ │ ├── base.js │ │ ├── helper.js │ │ └── toastr.js │ ├── dashboard │ │ ├── Main.vue │ │ ├── components │ │ │ ├── CustomAction.vue │ │ │ ├── Form.vue │ │ │ ├── Modal.vue │ │ │ ├── Table.vue │ │ │ ├── TablePagination.vue │ │ │ ├── TablePaginationMixin.vue │ │ │ └── particals │ │ │ │ ├── FooterBar.vue │ │ │ │ ├── Navbar.vue │ │ │ │ └── Sidebar.vue │ │ ├── config │ │ │ └── menu.js │ │ ├── index.js │ │ ├── modules │ │ │ ├── article │ │ │ │ ├── Article.vue │ │ │ │ ├── Create.vue │ │ │ │ ├── Edit.vue │ │ │ │ ├── Form.vue │ │ │ │ ├── FormMixin.vue │ │ │ │ ├── index.js │ │ │ │ └── routes.js │ │ │ ├── category │ │ │ │ ├── Category.vue │ │ │ │ ├── Create.vue │ │ │ │ ├── Edit.vue │ │ │ │ ├── Form.vue │ │ │ │ ├── index.js │ │ │ │ └── routes.js │ │ │ ├── comment │ │ │ │ ├── Comment.vue │ │ │ │ ├── Edit.vue │ │ │ │ ├── index.js │ │ │ │ └── routes.js │ │ │ ├── discussion │ │ │ │ ├── Create.vue │ │ │ │ ├── Discussion.vue │ │ │ │ ├── Edit.vue │ │ │ │ ├── Form.vue │ │ │ │ ├── index.js │ │ │ │ └── routes.js │ │ │ ├── file │ │ │ │ ├── File.vue │ │ │ │ ├── index.js │ │ │ │ └── routes.js │ │ │ ├── home │ │ │ │ ├── Home.vue │ │ │ │ ├── index.js │ │ │ │ └── routes.js │ │ │ ├── link │ │ │ │ ├── Create.vue │ │ │ │ ├── Edit.vue │ │ │ │ ├── Form.vue │ │ │ │ ├── Link.vue │ │ │ │ ├── index.js │ │ │ │ └── routes.js │ │ │ ├── role │ │ │ │ ├── Create.vue │ │ │ │ ├── Edit.vue │ │ │ │ ├── Form.vue │ │ │ │ ├── Permission.vue │ │ │ │ ├── Role.vue │ │ │ │ ├── index.js │ │ │ │ └── routes.js │ │ │ ├── system │ │ │ │ ├── System.vue │ │ │ │ ├── index.js │ │ │ │ └── routes.js │ │ │ ├── tag │ │ │ │ ├── Create.vue │ │ │ │ ├── Edit.vue │ │ │ │ ├── Form.vue │ │ │ │ ├── Tag.vue │ │ │ │ ├── index.js │ │ │ │ └── routes.js │ │ │ ├── user │ │ │ │ ├── Create.vue │ │ │ │ ├── Edit.vue │ │ │ │ ├── Form.vue │ │ │ │ ├── User.vue │ │ │ │ ├── index.js │ │ │ │ └── routes.js │ │ │ └── visitor │ │ │ │ ├── Visitor.vue │ │ │ │ ├── index.js │ │ │ │ └── routes.js │ │ ├── routes.js │ │ └── runtime │ │ │ ├── constants │ │ │ └── permission.js │ │ │ ├── mixins │ │ │ └── index.js │ │ │ └── utils │ │ │ ├── index.js │ │ │ └── misc.js │ ├── home.js │ ├── home │ │ └── components │ │ │ ├── AvatarUpload.vue │ │ │ ├── Chartjs.vue │ │ │ ├── Comment.vue │ │ │ ├── Cropper.vue │ │ │ ├── Parse.vue │ │ │ ├── Textarea.vue │ │ │ ├── VoteButton.vue │ │ │ └── passport │ │ │ ├── AuthorizedClients.vue │ │ │ ├── Clients.vue │ │ │ └── PersonalAccessTokens.vue │ ├── lang │ │ ├── en │ │ │ ├── form.js │ │ │ ├── index.js │ │ │ ├── page.js │ │ │ ├── permission.js │ │ │ ├── sidebar.js │ │ │ └── table.js │ │ ├── es │ │ │ ├── form.js │ │ │ ├── index.js │ │ │ ├── page.js │ │ │ ├── permission.js │ │ │ ├── sidebar.js │ │ │ └── table.js │ │ ├── index.js │ │ ├── ru │ │ │ ├── form.js │ │ │ ├── index.js │ │ │ ├── page.js │ │ │ ├── permission.js │ │ │ ├── sidebar.js │ │ │ └── table.js │ │ └── zh_cn │ │ │ ├── form.js │ │ │ ├── index.js │ │ │ ├── page.js │ │ │ ├── permission.js │ │ │ ├── sidebar.js │ │ │ └── table.js │ ├── plugins │ │ └── http │ │ │ └── index.js │ ├── router │ │ ├── beforeEach.js │ │ └── index.js │ ├── vendor │ │ ├── github_emoji.js │ │ ├── highlight.min.js │ │ └── select2.min.js │ └── vuex │ │ ├── actions.js │ │ ├── mutations.js │ │ └── store.js ├── lang │ ├── en │ │ ├── auth.php │ │ ├── blog.php │ │ ├── pagination.php │ │ ├── passwords.php │ │ ├── permissions.php │ │ └── validation.php │ ├── es │ │ ├── auth.php │ │ ├── blog.php │ │ ├── pagination.php │ │ ├── passwords.php │ │ ├── permissions.php │ │ └── validation.php │ ├── ru │ │ ├── auth.php │ │ ├── blog.php │ │ ├── pagination.php │ │ ├── passwords.php │ │ ├── permissions.php │ │ └── validation.php │ └── zh_cn │ │ ├── auth.php │ │ ├── blog.php │ │ ├── pagination.php │ │ ├── passwords.php │ │ ├── permissions.php │ │ └── validation.php ├── sass │ ├── _box.scss │ ├── _comment.scss │ ├── _form.scss │ ├── _markdown.scss │ ├── _navbar.scss │ ├── _pagination.scss │ ├── _styles.scss │ ├── _toastr.scss │ ├── _togglebutton.scss │ ├── _variables.scss │ ├── app.scss │ ├── home.scss │ ├── public.scss │ ├── themes │ │ ├── default-theme.scss │ │ └── gray-theme.scss │ └── vendor │ │ ├── highlight.min.css │ │ ├── select2.min.css │ │ ├── simplemde.min.css │ │ └── toastr.min.css └── views │ ├── article │ ├── index.blade.php │ └── show.blade.php │ ├── auth │ ├── github_register.blade.php │ ├── login.blade.php │ ├── passwords │ │ ├── email.blade.php │ │ └── reset.blade.php │ └── register.blade.php │ ├── category │ ├── index.blade.php │ └── show.blade.php │ ├── dashboard │ └── index.blade.php │ ├── discussion │ ├── create.blade.php │ ├── edit.blade.php │ ├── index.blade.php │ └── show.blade.php │ ├── errors │ ├── 403.blade.php │ ├── 404.blade.php │ └── 503.blade.php │ ├── layouts │ └── app.blade.php │ ├── link │ └── index.blade.php │ ├── mail │ ├── followed │ │ └── user.blade.php │ ├── mention │ │ └── user.blade.php │ └── receive │ │ └── comment.blade.php │ ├── notifications │ ├── followed-user.blade.php │ ├── got-vote.blade.php │ ├── mentioned-user.blade.php │ └── received-comment.blade.php │ ├── pagination │ └── default.blade.php │ ├── particals │ ├── footer.blade.php │ ├── jumbotron.blade.php │ └── navbar.blade.php │ ├── search.blade.php │ ├── setting │ ├── binding.blade.php │ ├── index.blade.php │ ├── notification.blade.php │ └── particals │ │ └── sidebar.blade.php │ ├── tag │ ├── index.blade.php │ └── show.blade.php │ ├── user │ ├── comments.blade.php │ ├── discussions.blade.php │ ├── following.blade.php │ ├── index.blade.php │ ├── notifications.blade.php │ ├── particals │ │ ├── comments.blade.php │ │ ├── discussions.blade.php │ │ └── info.blade.php │ └── profile.blade.php │ ├── vendor │ └── notifications │ │ ├── email-plain.blade.php │ │ └── email.blade.php │ └── widgets │ └── article.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 │ └── views │ │ └── .gitignore └── logs │ └── .gitignore ├── tests ├── CreatesApplication.php ├── Feature │ ├── Api │ │ ├── ArticleApiTest.php │ │ └── UserApiTest.php │ └── ExampleTest.php ├── TestCase.php └── Unit │ └── ExampleTest.php ├── webpack.mix.js └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [["@babel/preset-env", { "modules": false }]], 3 | "plugins": ["@babel/plugin-syntax-dynamic-import"] 4 | } -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | **/.classpath 2 | **/.dockerignore 3 | **/.env 4 | **/.git 5 | **/.gitignore 6 | **/.project 7 | **/.settings 8 | **/.toolstarget 9 | **/.vs 10 | **/.vscode 11 | **/*.*proj.user 12 | **/*.dbmdl 13 | **/*.jfm 14 | **/charts 15 | **/docker-compose* 16 | **/Dockerfile* 17 | **/node_modules 18 | **/npm-debug.log 19 | **/obj 20 | **/secrets.dev.yaml 21 | **/values.dev.yaml 22 | README.md 23 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 4 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = false 10 | 11 | [*.{vue,js,scss}] 12 | charset = utf-8 13 | indent_style = space 14 | indent_size = 2 15 | end_of_line = lf 16 | insert_final_newline = true 17 | trim_trailing_whitespace = true 18 | 19 | [*.md] 20 | trim_trailing_whitespace = false 21 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | APP_NAME=PJ-Blog 2 | APP_ENV=local 3 | APP_KEY= 4 | APP_DEBUG=true 5 | APP_URL=http://localhost 6 | APP_SUPER_ADMIN=1 7 | 8 | LOG_CHANNEL=stack 9 | 10 | DB_CONNECTION=mysql 11 | DB_HOST=127.0.0.1 12 | DB_PORT=3306 13 | DB_DATABASE=laravel 14 | DB_USERNAME=root 15 | DB_PASSWORD= 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_MAILER=smtp 28 | MAIL_HOST=mailpit 29 | MAIL_PORT=1025 30 | MAIL_USERNAME=null 31 | MAIL_PASSWORD=null 32 | MAIL_ENCRYPTION=null 33 | MAIL_FROM_ADDRESS="hello@example.com" 34 | MAIL_FROM_NAME="${APP_NAME}" 35 | 36 | ADMIN_NAME= 37 | ADMIN_EMAIL= 38 | ADMIN_PASSWORD= 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 | GITHUB_CLIENT_ID= 54 | GITHUB_CLIENT_SECRET= 55 | GITHUB_REDIRECT= 56 | 57 | YOUDAO_APP_KEY= 58 | YOUDAO_APP_SECRET= 59 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | *.css linguist-vendored 3 | *.scss linguist-vendored 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /public/storage 3 | /vendor 4 | /.idea 5 | Homestead.json 6 | Homestead.yaml 7 | .env 8 | /public/css 9 | /public/js 10 | /public/fonts 11 | /public/mix-manifest.json 12 | npm-debug.log 13 | .phpstorm.meta.php 14 | _ide_helper.php 15 | /storage/oauth-private.key 16 | /storage/oauth-public.key 17 | /package-lock.json 18 | .vscode/* -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM php:7.4-fpm 2 | 3 | COPY . /usr/src/blog 4 | WORKDIR /usr/src/blog 5 | 6 | # install tools 7 | RUN apt-get -y update 8 | RUN apt-get -y install git 9 | RUN apt-get -y install vim 10 | RUN apt-get install zip unzip 11 | RUN apt-get -y install libxml2-dev 12 | 13 | # install PHP extenstions 14 | RUN docker-php-ext-install pdo 15 | RUN docker-php-ext-install pdo_mysql 16 | 17 | RUN docker-php-ext-install tokenizer 18 | RUN docker-php-ext-install xml 19 | 20 | #node js 21 | RUN curl -fsSL https://deb.nodesource.com/setup_16.x | bash - 22 | RUN apt-get install -y nodejs 23 | 24 | # install composer 25 | COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer 26 | 27 | # install app 28 | RUN composer install -vvv 29 | RUN npm install 30 | RUN composer update 31 | RUN npm run dev 32 | 33 | COPY entrypoint.sh /entrypoint.sh 34 | 35 | CMD ["/entrypoint.sh"] 36 | 37 | EXPOSE 8000 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Jiajian Chan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /app/Category.php: -------------------------------------------------------------------------------- 1 | hasMany(Article::Class); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /app/Comment.php: -------------------------------------------------------------------------------- 1 | morphTo(); 43 | } 44 | 45 | /** 46 | * Set the content Attribute. 47 | * 48 | * @param $value 49 | */ 50 | public function setContentAttribute($value) 51 | { 52 | $data = [ 53 | 'raw' => $value, 54 | 'html' => (new Markdowner)->convertMarkdownToHtml($value) 55 | ]; 56 | 57 | $this->attributes['content'] = json_encode($data); 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /app/Console/Commands/BlogInstall.php: -------------------------------------------------------------------------------- 1 | execShellWithPrettyPrint('php artisan key:generate'); 39 | $this->execShellWithPrettyPrint('php artisan migrate --seed'); 40 | $this->execShellWithPrettyPrint('php artisan passport:install'); 41 | $this->execShellWithPrettyPrint('php artisan storage:link'); 42 | } 43 | 44 | /** 45 | * Exec shell with pretty print. 46 | * 47 | * @param string $command 48 | * @return mixed 49 | */ 50 | public function execShellWithPrettyPrint($command) 51 | { 52 | $this->info('---'); 53 | $this->info($command); 54 | $output = shell_exec($command); 55 | $this->info($output); 56 | $this->info('---'); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /app/Console/Kernel.php: -------------------------------------------------------------------------------- 1 | command('inspire') 29 | // ->hourly(); 30 | } 31 | 32 | /** 33 | * Register the Closure based commands for the application. 34 | * 35 | * @return void 36 | */ 37 | protected function commands() 38 | { 39 | require base_path('routes/console.php'); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /app/Exceptions/UploadException.php: -------------------------------------------------------------------------------- 1 | response = new Response(response(), new Transform($manager)); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /app/Http/Controllers/Api/HomeController.php: -------------------------------------------------------------------------------- 1 | count(); 15 | $visitors = Visitor::query()->sum('clicks'); 16 | $articles = Article::query()->count(); 17 | $comments = Comment::query()->count(); 18 | 19 | $data = compact('users', 'visitors', 'articles', 'comments'); 20 | 21 | return $this->response->json($data); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /app/Http/Controllers/Api/MeController.php: -------------------------------------------------------------------------------- 1 | validate($request, [ 22 | 'id' => 'required|exists:comments,id', 23 | ]); 24 | 25 | $user = auth()->user(); 26 | 27 | $comment = Comment::findOrFail($request->id); 28 | 29 | ($type == 'up') ? User::upOrDownVote($user, $comment) : User::upOrDownVote($user, $comment, 'down'); 30 | 31 | return $this->response->withNoContent(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /app/Http/Controllers/Api/PermissionsController.php: -------------------------------------------------------------------------------- 1 | response->collection($permissions); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/Http/Controllers/Api/SystemController.php: -------------------------------------------------------------------------------- 1 | getPdo(); 15 | 16 | $version = $pdo->query('select version()')->fetchColumn(); 17 | 18 | $data = [ 19 | 'server' => $_SERVER['SERVER_SOFTWARE'], 20 | 'http_host' => $_SERVER['HTTP_HOST'], 21 | 'remote_host' => isset($_SERVER['REMOTE_HOST']) ? $_SERVER['REMOTE_HOST'] : $_SERVER['REMOTE_ADDR'], 22 | 'user_agent' => $_SERVER['HTTP_USER_AGENT'], 23 | 'php' => phpversion(), 24 | 'sapi_name' => php_sapi_name(), 25 | 'extensions' => implode(", ", get_loaded_extensions()), 26 | 'db_connection' => isset($_SERVER['DB_CONNECTION']) ? $_SERVER['DB_CONNECTION'] : 'Secret', 27 | 'db_database' => isset($_SERVER['DB_DATABASE']) ? $_SERVER['DB_DATABASE'] : 'Secret', 28 | 'db_version' => $version, 29 | ]; 30 | 31 | return $this->response->json($data); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /app/Http/Controllers/Api/VisitorController.php: -------------------------------------------------------------------------------- 1 | 14 | * 15 | * @param Request $request 16 | * 17 | * @return \Illuminate\Http\JsonResponse 18 | * @throws \Exception 19 | */ 20 | public function index(Request $request) 21 | { 22 | $vistors = Visitor::filter($request->all())->orderBy('created_at', 'desc')->paginate(10); 23 | 24 | return $this->response->collection($vistors); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/Http/Controllers/ArticleController.php: -------------------------------------------------------------------------------- 1 | orderBy(config('blog.article.sortColumn'), config('blog.article.sort')) 20 | ->paginate(config('blog.article.number')); 21 | 22 | return view('article.index', compact('articles')); 23 | } 24 | 25 | /** 26 | * Display the article resource by article slug. 27 | * 28 | * @author Huiwang <905130909@qq.com> 29 | * 30 | * @param Request $request 31 | * @param $slug 32 | * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View 33 | */ 34 | public function show(Request $request, $slug) 35 | { 36 | $article = Article::checkAuth()->where('slug', $slug)->firstOrFail(); 37 | 38 | $article->increment('view_count'); 39 | 40 | $ip = $request->getClientIp(); 41 | 42 | if ($ip == '::1') { 43 | $ip = '127.0.0.1'; 44 | } 45 | 46 | Visitor::log($article->id, $ip); 47 | 48 | return view('article.show', compact('article')); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /app/Http/Controllers/Auth/ForgotPasswordController.php: -------------------------------------------------------------------------------- 1 | middleware('guest'); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/Http/Controllers/Auth/LoginController.php: -------------------------------------------------------------------------------- 1 | middleware('guest', ['except' => 'logout']); 39 | } 40 | 41 | /** 42 | * Log the user out of the application. 43 | * 44 | * @param \Illuminate\Http\Request $request 45 | * @return \Illuminate\Http\Response 46 | */ 47 | public function logout(Request $request) 48 | { 49 | $this->guard()->logout(); 50 | 51 | $request->session()->flush(); 52 | 53 | $request->session()->regenerate(); 54 | 55 | return redirect('/login'); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /app/Http/Controllers/Auth/ResetPasswordController.php: -------------------------------------------------------------------------------- 1 | middleware('guest'); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /app/Http/Controllers/CategoryController.php: -------------------------------------------------------------------------------- 1 | get(); 17 | 18 | return view('category.index', compact('categories')); 19 | } 20 | 21 | /** 22 | * Display the category resource by category name. 23 | * 24 | * @param string $category 25 | * 26 | * @return mixed 27 | */ 28 | public function show($category) 29 | { 30 | $category = Category::query()->where('name', $category)->first(); 31 | 32 | if (!$category) { 33 | abort(404); 34 | } 35 | 36 | $articles = $category->articles; 37 | 38 | return view('category.show', compact('category', 'articles')); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /app/Http/Controllers/Controller.php: -------------------------------------------------------------------------------- 1 | get('q')); 30 | 31 | $articles = Article::query()->where('title', 'like', "%{$key}%") 32 | ->orWhere('content', 'like', "%{$key}%") 33 | ->orderBy('published_at', 'desc') 34 | ->get(); 35 | 36 | return view('search', compact('articles')); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /app/Http/Controllers/LinkController.php: -------------------------------------------------------------------------------- 1 | orderBy('created_at', 'desc')->paginate(10); 17 | 18 | return view('link.index', compact('links')); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/Http/Controllers/SettingController.php: -------------------------------------------------------------------------------- 1 | $request->get('email_notify_enabled') ? 'yes' : 'no', 41 | ]; 42 | 43 | User::query()->where('id', \Auth::id())->update($input); 44 | 45 | return redirect()->back(); 46 | } 47 | 48 | /** 49 | * Display the bindings page. 50 | * 51 | * @return \Illuminate\Http\Response 52 | */ 53 | public function binding() 54 | { 55 | return view('setting.binding'); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /app/Http/Controllers/TagController.php: -------------------------------------------------------------------------------- 1 | get(); 17 | 18 | return view('tag.index', compact('tags')); 19 | } 20 | 21 | /** 22 | * Display the articles and discussions by the tag. 23 | * 24 | * @param string $tag 25 | * 26 | * @return mixed 27 | */ 28 | public function show($tag) 29 | { 30 | $tag = Tag::query()->where('tag', $tag)->first(); 31 | 32 | if (!$tag) { 33 | abort(404); 34 | } 35 | 36 | $articles = $tag->articles; 37 | $discussions = $tag->discussions; 38 | 39 | return view('tag.show', compact('tag', 'articles', 'discussions')); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /app/Http/Middleware/Authenticate.php: -------------------------------------------------------------------------------- 1 | expectsJson()) { 18 | return route('login'); 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /app/Http/Middleware/CheckForMaintenanceMode.php: -------------------------------------------------------------------------------- 1 | is_admin) { 21 | abort(404); 22 | } 23 | 24 | return $next($request); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/Http/Middleware/PermissionMiddleware.php: -------------------------------------------------------------------------------- 1 | guest()) { 13 | throw UnauthorizedException::notLoggedIn(); 14 | } 15 | 16 | $permissions = is_array($permission) 17 | ? $permission 18 | : explode('|', $permission); 19 | 20 | foreach ($permissions as $permission) { 21 | if (app('auth')->user()->hasPermissionTo($permission) || app('auth')->user()->isSuperAdmin()) { 22 | return $next($request); 23 | } 24 | } 25 | 26 | throw UnauthorizedException::forPermissions($permissions); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /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 | |string|null 14 | */ 15 | protected $proxies; 16 | 17 | /** 18 | * The headers that should be used to detect proxies. 19 | * 20 | * @var int 21 | */ 22 | protected $headers = 23 | Request::HEADER_X_FORWARDED_FOR | 24 | Request::HEADER_X_FORWARDED_HOST | 25 | Request::HEADER_X_FORWARDED_PORT | 26 | Request::HEADER_X_FORWARDED_PROTO | 27 | Request::HEADER_X_FORWARDED_AWS_ELB; 28 | } 29 | -------------------------------------------------------------------------------- /app/Http/Middleware/VerifyCsrfToken.php: -------------------------------------------------------------------------------- 1 | 'required|min:3', 28 | 'subtitle' => 'required|min:3', 29 | 'content' => 'required', 30 | 'category_id' => 'required', 31 | 'published_at' => 'required', 32 | ]; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /app/Http/Requests/CategoryRequest.php: -------------------------------------------------------------------------------- 1 | 'required|min:2', 28 | 'path' => 'required', 29 | ]; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /app/Http/Requests/CommentRequest.php: -------------------------------------------------------------------------------- 1 | 'required' 28 | ]; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /app/Http/Requests/DiscussionRequest.php: -------------------------------------------------------------------------------- 1 | 'required|min:2', 28 | 'content' => 'required', 29 | 'tags' => 'required', 30 | ]; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/Http/Requests/ImageRequest.php: -------------------------------------------------------------------------------- 1 | 'image|mimes:jpeg,jpg,png,gif' 28 | ]; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /app/Http/Requests/LinkRequest.php: -------------------------------------------------------------------------------- 1 | 'required|min:2', 28 | 'link' => 'required|min:2' 29 | ]; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /app/Http/Requests/TagRequest.php: -------------------------------------------------------------------------------- 1 | 'required|unique:tags', 28 | 'title' => 'required', 29 | 'meta_description' => 'required' 30 | ]; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/Http/Requests/UserRequest.php: -------------------------------------------------------------------------------- 1 | 'required|unique:users', 28 | 'email' => 'required|email|unique:users', 29 | 'password_confirmation' => 'required', 30 | 'password' => 'required|confirmed', 31 | ]; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /app/Link.php: -------------------------------------------------------------------------------- 1 | 47 | * 48 | * @param $query 49 | * @return mixed 50 | */ 51 | public function scopeCheckAuth($query) 52 | { 53 | if (auth()->check() && auth()->user()->is_admin) { 54 | $query->withoutGlobalScope(StatusScope::class); 55 | } 56 | return $query; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /app/Model.php: -------------------------------------------------------------------------------- 1 | [input_key1, input_key2]]. 12 | * 13 | * @var array 14 | */ 15 | public $relations = []; 16 | 17 | public function keyword($keyword) 18 | { 19 | return $this->where('title', 'like', "%{$keyword}%")->orWhere('subtitle', 'like', "%{$keyword}%"); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/ModelFilters/CategoryFilter.php: -------------------------------------------------------------------------------- 1 | [input_key1, input_key2]]. 12 | * 13 | * @var array 14 | */ 15 | public $relations = []; 16 | 17 | public function keyword($keyword) 18 | { 19 | return $this->where('name', 'like', "%{$keyword}%"); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/ModelFilters/CommentFilter.php: -------------------------------------------------------------------------------- 1 | [input_key1, input_key2]]. 12 | * 13 | * @var array 14 | */ 15 | public $relations = ['user' => 'keyword']; 16 | 17 | public function commentableType($commentableType) 18 | { 19 | return $this->where('commentable_type', $commentableType); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/ModelFilters/DiscussionFilter.php: -------------------------------------------------------------------------------- 1 | [input_key1, input_key2]]. 10 | * 11 | * @var array 12 | */ 13 | public $relations = []; 14 | 15 | public function keyword($keyword) 16 | { 17 | return $this->where('title', 'like', "%{$keyword}%") 18 | ->orWhereHas('user', function ($query) use ($keyword) { 19 | $query->where('name', 'like', "%{$keyword}%"); 20 | }); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/ModelFilters/LinkFilter.php: -------------------------------------------------------------------------------- 1 | [input_key1, input_key2]]. 12 | * 13 | * @var array 14 | */ 15 | public $relations = []; 16 | 17 | public function keyword($keyword) 18 | { 19 | return $this->where('name', 'like', "%{$keyword}%"); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/ModelFilters/RoleFilter.php: -------------------------------------------------------------------------------- 1 | [input_key1, input_key2]]. 12 | * 13 | * @var array 14 | */ 15 | public $relations = []; 16 | 17 | public function keyword($keyword) 18 | { 19 | return $this->where('name', 'like', "%{$keyword}%"); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/ModelFilters/TagFilter.php: -------------------------------------------------------------------------------- 1 | [input_key1, input_key2]]. 12 | * 13 | * @var array 14 | */ 15 | public $relations = []; 16 | 17 | public function keyword($keyword) 18 | { 19 | return $this->where('tag', 'like', "%{$keyword}%")->orWhere('title', 'like', "%{$keyword}%"); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/ModelFilters/UserFilter.php: -------------------------------------------------------------------------------- 1 | [input_key1, input_key2]]. 10 | * 11 | * @var array 12 | */ 13 | public $relations = []; 14 | 15 | public function keyword($keyword) 16 | { 17 | return $this->where('name', 'like', "%{$keyword}%"); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /app/ModelFilters/VisitorFilter.php: -------------------------------------------------------------------------------- 1 | [input_key1, input_key2]]. 12 | * 13 | * @var array 14 | */ 15 | public $relations = []; 16 | 17 | public function keyword($keyword) 18 | { 19 | return $this->where('ip', 'like', "%{$keyword}%") 20 | ->orWhereHas('article', function ($query) use ($keyword) { 21 | $query->where('title', 'like', "%{$keyword}%"); 22 | }); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/Policies/ArticlePolicy.php: -------------------------------------------------------------------------------- 1 | check() && !$article->is_draft; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/Policies/CommentPolicy.php: -------------------------------------------------------------------------------- 1 | user_id === $user->id; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/Policies/DiscussionPolicy.php: -------------------------------------------------------------------------------- 1 | id === $discussion->user_id; 21 | } 22 | 23 | /** 24 | * Determine whether the user can delete the discussion. 25 | * 26 | * @param \App\User $user 27 | * @param \App\Discussion $discussion 28 | * @return mixed 29 | */ 30 | public function delete(User $user, Discussion $discussion) 31 | { 32 | return false; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /app/Policies/Policy.php: -------------------------------------------------------------------------------- 1 | is_admin) { 15 | return true; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /app/Policies/UserPolicy.php: -------------------------------------------------------------------------------- 1 | id === $user->id; 19 | } 20 | 21 | /** 22 | * Determine whether the current user can delete the user. 23 | * 24 | * @param \App\User $currentUser 25 | * @param \App\User $user 26 | * @return mixed 27 | */ 28 | public function delete(User $currentUser, User $user) 29 | { 30 | return false; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/Providers/AppServiceProvider.php: -------------------------------------------------------------------------------- 1 | Discussion::class, 28 | 'articles' => Article::class, 29 | ]); 30 | 31 | Schema::defaultStringLength(191); 32 | Paginator::useBootstrap(); 33 | } 34 | 35 | /** 36 | * Register any application services. 37 | * 38 | * @return void 39 | */ 40 | public function register() 41 | { 42 | $this->app->singleton('uploader', function ($app) { 43 | $config = config('filesystems.default', 'public'); 44 | 45 | if ($config == 'upyun') { 46 | return new UpyunManager(); 47 | } 48 | 49 | return new BaseManager(); 50 | }); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /app/Providers/AuthServiceProvider.php: -------------------------------------------------------------------------------- 1 | \App\Policies\UserPolicy::class, 19 | \App\Article::class => \App\Policies\ArticlePolicy::class, 20 | \App\Comment::class => \App\Policies\CommentPolicy::class, 21 | \App\Discussion::class => \App\Policies\DiscussionPolicy::class, 22 | ]; 23 | 24 | /** 25 | * Register any authentication / authorization services. 26 | * 27 | * @return void 28 | */ 29 | public function boot() 30 | { 31 | $this->registerPolicies(); 32 | 33 | Passport::routes(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /app/Providers/BroadcastServiceProvider.php: -------------------------------------------------------------------------------- 1 | [ 19 | SendEmailVerificationNotification::class, 20 | ], 21 | ]; 22 | 23 | /** 24 | * Register any events for your application. 25 | * 26 | * @return void 27 | */ 28 | public function boot() 29 | { 30 | parent::boot(); 31 | 32 | // 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /app/Scopes/DraftScope.php: -------------------------------------------------------------------------------- 1 | where('is_draft', 0); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/Scopes/StatusScope.php: -------------------------------------------------------------------------------- 1 | where('status', 1); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/Tag.php: -------------------------------------------------------------------------------- 1 | morphedByMany(Article::class, 'taggable'); 38 | } 39 | 40 | /** 41 | * Get all of the discussions that are assigned this tag. 42 | * 43 | * @return \Illuminate\Database\Eloquent\Relations\MorphToMany 44 | */ 45 | public function discussions() 46 | { 47 | return $this->morphedByMany(Discussion::class, 'taggable'); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /app/Tools/IP.php: -------------------------------------------------------------------------------- 1 | request = $request; 24 | } 25 | 26 | /** 27 | * Get the client ip. 28 | * 29 | * @return mixed|string 30 | */ 31 | public function get() 32 | { 33 | $ip = $this->request->getClientIp(); 34 | 35 | if($ip == '::1') { 36 | $ip = '127.0.0.1'; 37 | } 38 | 39 | return $ip; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /app/Tools/Markdowner.php: -------------------------------------------------------------------------------- 1 | htmlConverter = new HtmlConverter(); 26 | 27 | $this->markdownConverter = new Parsedown(); 28 | } 29 | 30 | /** 31 | * Convert Markdown To Html. 32 | * 33 | * @param $markdown 34 | * @return string 35 | */ 36 | public function convertMarkdownToHtml($markdown) 37 | { 38 | return $this->markdownConverter 39 | ->setBreaksEnabled(true) 40 | ->text($markdown); 41 | } 42 | 43 | /** 44 | * Convert Html To Markdown. 45 | * 46 | * @param $html 47 | * @return string 48 | */ 49 | public function convertHtmlToMarkdown($html) 50 | { 51 | return $this->htmlConverter->convert($html); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /app/Traits/BelongsToUser.php: -------------------------------------------------------------------------------- 1 | belongsTo(User::class); 17 | } 18 | 19 | public static function bootBelongsToUser() 20 | { 21 | static::saving(function ($model) { 22 | $model->user_id = $model->user_id ?? \Auth::id(); 23 | }); 24 | } 25 | } -------------------------------------------------------------------------------- /app/Traits/HasComments.php: -------------------------------------------------------------------------------- 1 | morphMany(Comment::class, 'commentable'); 17 | } 18 | } -------------------------------------------------------------------------------- /app/Traits/HasTags.php: -------------------------------------------------------------------------------- 1 | morphToMany(Tag::class, 'taggable'); 17 | } 18 | } -------------------------------------------------------------------------------- /app/Transformers/CategoryTransformer.php: -------------------------------------------------------------------------------- 1 | $category->id, 14 | 'name' => $category->name, 15 | 'path' => $category->path, 16 | 'description' => $category->description, 17 | 'status' => $category->status, 18 | 'created_at' => $category->created_at->toDateTimeString(), 19 | ]; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/Transformers/EmptyTransformer.php: -------------------------------------------------------------------------------- 1 | $link->id, 14 | 'name' => $link->name, 15 | 'image' => $link->image, 16 | 'link' => $link->link, 17 | 'status' => (bool) $link->status, 18 | 'created_at' => $link->created_at->toDateTimeString(), 19 | ]; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/Transformers/PermissionTransformer.php: -------------------------------------------------------------------------------- 1 | $permission->id, 14 | 'name' => $permission->name, 15 | 'label' => trans('permissions.' . $permission->name) 16 | ]; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /app/Transformers/RoleTransformer.php: -------------------------------------------------------------------------------- 1 | $role->id, 18 | 'name' => $role->name, 19 | 'guard_name' => $role->guard_name, 20 | 'permission_ids'=> $role->permissions->pluck('id'), 21 | 'created_at' => $role->created_at->toDateTimeString(), 22 | ]; 23 | } 24 | 25 | /** 26 | * Include Category 27 | * 28 | * @param Role $role 29 | * @return \League\Fractal\Resource\Collection 30 | */ 31 | public function includePermissions(Role $role) 32 | { 33 | if ($permissions = $role->permissions) { 34 | return $this->collection($permissions, new PermissionTransformer); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /app/Transformers/TagTransformer.php: -------------------------------------------------------------------------------- 1 | $tag->id, 14 | 'tag' => $tag->tag, 15 | 'title' => $tag->title, 16 | 'meta_description' => $tag->meta_description, 17 | 'status' => $tag->status, 18 | 'created_at' => $tag->created_at->toDateTimeString(), 19 | ]; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/Transformers/UserTransformer.php: -------------------------------------------------------------------------------- 1 | $user->id, 19 | 'avatar' => $user->avatar, 20 | 'name' => $user->name, 21 | 'status' => $user->status, 22 | 'email' => $user->email, 23 | 'nickname' => $user->nickname, 24 | 'is_admin' => $user->is_admin, 25 | 'github_name' => $user->github_name, 26 | 'website' => $user->website, 27 | 'description' => $user->description, 28 | 'created_at' => $user->created_at->toDateTimeString(), 29 | ]; 30 | } 31 | 32 | /** 33 | * Include Role 34 | * 35 | * @param User $user 36 | * @return \League\Fractal\Resource\Collection 37 | */ 38 | public function includeRoles(User $user) 39 | { 40 | if ($roles = $user->roles) { 41 | return $this->collection($roles, new RoleTransformer); 42 | } 43 | } 44 | 45 | /** 46 | * Include Permission 47 | * 48 | * @param User $user 49 | * @return \League\Fractal\Resource\Collection 50 | */ 51 | public function includePermissions(User $user) 52 | { 53 | if ($permissions = $user->permissions) { 54 | return $this->collection($permissions, new PermissionTransformer); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /app/Transformers/VisitorTransformer.php: -------------------------------------------------------------------------------- 1 | $visitor->id, 14 | 'article' => [ 'title' => isset($visitor->article) ? $visitor->article->title : 'null' ], 15 | 'ip' => $visitor->ip, 16 | 'country' => $visitor->country, 17 | 'clicks' => $visitor->clicks, 18 | 'created_at' => $visitor->created_at->toDateTimeString(), 19 | ]; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/Visitor.php: -------------------------------------------------------------------------------- 1 | belongsTo(Article::class); 26 | } 27 | 28 | /** 29 | * 记录访问记录. 30 | * 31 | * @author Huiwang <905130909@qq.com> 32 | * 33 | * @param $articleId 34 | * @param $ip 35 | * 36 | * @return Visitor|Model|null|object 37 | */ 38 | public static function log($articleId, $ip) 39 | { 40 | $log = self::query()->where('article_id', $articleId)->where('ip', $ip)->first(); 41 | if ($log) { 42 | $log->increment('clicks'); 43 | } else { 44 | $data = [ 45 | 'ip' => $ip, 46 | 'article_id' => $articleId, 47 | 'clicks' => 1, 48 | ]; 49 | $log = self::create($data); 50 | } 51 | 52 | return $log; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /bootstrap/cache/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /config/compile.php: -------------------------------------------------------------------------------- 1 | [ 17 | // 18 | ], 19 | 20 | /* 21 | |-------------------------------------------------------------------------- 22 | | Compiled File Providers 23 | |-------------------------------------------------------------------------- 24 | | 25 | | Here you may list service providers which define a "compiles" function 26 | | that returns additional files that should be compiled, providing an 27 | | easy way to get common files from any packages you are utilizing. 28 | | 29 | */ 30 | 31 | 'providers' => [ 32 | // 33 | ], 34 | 35 | ]; 36 | -------------------------------------------------------------------------------- /config/cors.php: -------------------------------------------------------------------------------- 1 | ['api/*'], 19 | 20 | 'allowed_methods' => ['*'], 21 | 22 | 'allowed_origins' => ['*'], 23 | 24 | 'allowed_origins_patterns' => [], 25 | 26 | 'allowed_headers' => ['*'], 27 | 28 | 'exposed_headers' => [], 29 | 30 | 'max_age' => 0, 31 | 32 | 'supports_credentials' => false, 33 | 34 | ]; -------------------------------------------------------------------------------- /config/eloquentfilter.php: -------------------------------------------------------------------------------- 1 | 'App\\ModelFilters\\', 15 | 16 | /* 17 | |-------------------------------------------------------------------------- 18 | | Custom generator stub 19 | |-------------------------------------------------------------------------- 20 | | 21 | | If you want to override the default stub this package provides 22 | | you can enter the path to your own at this point 23 | | 24 | */ 25 | // 'generator' => [ 26 | // 'stub' => app_path('stubs/modelfilter.stub') 27 | // ] 28 | 29 | /* 30 | |-------------------------------------------------------------------------- 31 | | Default Paginator Limit For `paginateFilter` and `simplePaginateFilter` 32 | |-------------------------------------------------------------------------- 33 | | 34 | | Set paginate limit 35 | | 36 | */ 37 | 'paginate_limit' => env('PAGINATION_LIMIT_DEFAULT',15) 38 | 39 | ]; 40 | -------------------------------------------------------------------------------- /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 | ]; -------------------------------------------------------------------------------- /config/image.php: -------------------------------------------------------------------------------- 1 | 'gd' 19 | 20 | ); 21 | -------------------------------------------------------------------------------- /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 | ]; -------------------------------------------------------------------------------- /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 | ]; -------------------------------------------------------------------------------- /config/vote.php: -------------------------------------------------------------------------------- 1 | 'votes', 6 | 7 | 'user_foreign_key' => 'user_id', 8 | 9 | 'vote_model' => \Jcc\LaravelVote\Vote::class, 10 | ]; 11 | -------------------------------------------------------------------------------- /database/.gitignore: -------------------------------------------------------------------------------- 1 | *.sqlite 2 | -------------------------------------------------------------------------------- /database/migrations/.gitkeep: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /database/migrations/2014_10_12_000000_create_users_table.php: -------------------------------------------------------------------------------- 1 | bigIncrements('id'); 18 | $table->string('name')->unique(); 19 | $table->string('nickname')->nullable(); 20 | $table->text('avatar')->nullable(); 21 | $table->string('email')->unique(); 22 | $table->string('confirm_code', 64)->unique()->nullable(); 23 | $table->tinyInteger('status')->default(false); 24 | $table->boolean('is_admin')->default(false); 25 | $table->string('password'); 26 | $table->string('github_id')->nullable(); 27 | $table->string('github_name')->nullable(); 28 | $table->string('github_url')->nullable(); 29 | $table->string('weibo_name')->nullable(); 30 | $table->string('weibo_link')->nullable(); 31 | $table->string('website')->nullable(); 32 | $table->string('description')->nullable(); 33 | $table->enum('email_notify_enabled', ['yes', 'no'])->default('yes')->index(); 34 | $table->rememberToken(); 35 | $table->timestamps(); 36 | $table->softDeletes(); 37 | }); 38 | } 39 | 40 | /** 41 | * Reverse the migrations. 42 | * 43 | * @return void 44 | */ 45 | public function down() 46 | { 47 | Schema::drop('users'); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /database/migrations/2014_10_12_100000_create_password_resets_table.php: -------------------------------------------------------------------------------- 1 | string('email')->index(); 18 | $table->string('token')->index(); 19 | $table->timestamp('created_at')->nullable(); 20 | }); 21 | } 22 | 23 | /** 24 | * Reverse the migrations. 25 | * 26 | * @return void 27 | */ 28 | public function down() 29 | { 30 | Schema::drop('password_resets'); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /database/migrations/2016_09_02_065857_create_articles_table.php: -------------------------------------------------------------------------------- 1 | bigIncrements('id'); 18 | $table->unsignedBigInteger('category_id'); 19 | $table->unsignedBigInteger('user_id'); 20 | $table->unsignedBigInteger('last_user_id'); 21 | $table->string('slug')->unique(); 22 | $table->string('title'); 23 | $table->string('subtitle'); 24 | // $table->json('content'); 25 | $table->longText('content'); 26 | $table->string('page_image')->nullable(); 27 | $table->string('meta_description')->nullable(); 28 | $table->boolean('is_original')->default(false); 29 | $table->boolean('is_draft')->default(false); 30 | $table->integer('view_count')->unsigned()->default(0)->index(); 31 | $table->timestamp('published_at')->nullable(); 32 | $table->timestamps(); 33 | $table->softDeletes(); 34 | }); 35 | } 36 | 37 | /** 38 | * Reverse the migrations. 39 | * 40 | * @return void 41 | */ 42 | public function down() 43 | { 44 | Schema::dropIfExists('articles'); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /database/migrations/2016_09_02_065920_create_tags_table.php: -------------------------------------------------------------------------------- 1 | bigIncrements('id'); 18 | $table->string('tag')->unique(); 19 | $table->string('title'); 20 | $table->string('meta_description'); 21 | $table->timestamps(); 22 | $table->softDeletes(); 23 | }); 24 | } 25 | 26 | /** 27 | * Reverse the migrations. 28 | * 29 | * @return void 30 | */ 31 | public function down() 32 | { 33 | Schema::dropIfExists('tags'); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /database/migrations/2016_09_02_065952_create_visitors_table.php: -------------------------------------------------------------------------------- 1 | bigIncrements('id'); 18 | $table->unsignedBigInteger('article_id'); 19 | $table->foreign('article_id')->references('id')->on('articles')->onDelete('cascade'); 20 | $table->string('ip', 32); 21 | $table->string('country')->nullable(); 22 | $table->integer('clicks')->unsigned()->default(1); 23 | $table->timestamps(); 24 | }); 25 | } 26 | 27 | /** 28 | * Reverse the migrations. 29 | * 30 | * @return void 31 | */ 32 | public function down() 33 | { 34 | Schema::dropIfExists('visitors'); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /database/migrations/2016_09_02_070119_create_categories_table.php: -------------------------------------------------------------------------------- 1 | bigIncrements('id'); 18 | $table->unsignedBigInteger('parent_id')->default(0); 19 | $table->string('name'); 20 | $table->string('path'); 21 | $table->string('description')->nullable(); 22 | $table->string('image_url')->nullable(); 23 | $table->timestamps(); 24 | }); 25 | } 26 | 27 | /** 28 | * Reverse the migrations. 29 | * 30 | * @return void 31 | */ 32 | public function down() 33 | { 34 | Schema::dropIfExists('categories'); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /database/migrations/2016_09_02_070132_create_discussions_table.php: -------------------------------------------------------------------------------- 1 | bigIncrements('id'); 18 | $table->unsignedBigInteger('user_id'); 19 | $table->unsignedBigInteger('last_user_id'); 20 | $table->string('title'); 21 | // $table->json('content'); 22 | $table->text('content'); 23 | $table->tinyInteger('status')->default(false); 24 | $table->timestamps(); 25 | $table->softDeletes(); 26 | }); 27 | } 28 | 29 | /** 30 | * Reverse the migrations. 31 | * 32 | * @return void 33 | */ 34 | public function down() 35 | { 36 | Schema::dropIfExists('discussions'); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /database/migrations/2016_09_02_070151_create_comments_table.php: -------------------------------------------------------------------------------- 1 | bigIncrements('id'); 18 | $table->unsignedBigInteger('user_id'); 19 | $table->unsignedBigInteger('commentable_id'); 20 | $table->char('commentable_type'); 21 | // $table->json('content'); 22 | $table->text('content'); 23 | $table->timestamps(); 24 | $table->softDeletes(); 25 | }); 26 | } 27 | 28 | /** 29 | * Reverse the migrations. 30 | * 31 | * @return void 32 | */ 33 | public function down() 34 | { 35 | Schema::dropIfExists('comments'); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /database/migrations/2016_09_13_022056_create_links_table.php: -------------------------------------------------------------------------------- 1 | bigIncrements('id'); 18 | $table->string('name')->index(); 19 | $table->string('link')->index(); 20 | $table->text('image')->nullable(); 21 | $table->boolean('status')->default(true); 22 | $table->timestamps(); 23 | $table->softDeletes(); 24 | }); 25 | } 26 | 27 | /** 28 | * Reverse the migrations. 29 | * 30 | * @return void 31 | */ 32 | public function down() 33 | { 34 | Schema::dropIfExists('links'); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /database/migrations/2016_11_11_163610_create_taggables_table.php: -------------------------------------------------------------------------------- 1 | unsignedBigInteger('tag_id')->index(); 18 | $table->unsignedBigInteger('taggable_id')->index(); 19 | $table->string('taggable_type')->index(); 20 | }); 21 | } 22 | 23 | /** 24 | * Reverse the migrations. 25 | * 26 | * @return void 27 | */ 28 | public function down() 29 | { 30 | Schema::dropIfExists('taggables'); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /database/migrations/2016_12_11_153312_create_followers_table.php: -------------------------------------------------------------------------------- 1 | bigIncrements('id'); 18 | $table->unsignedBigInteger('user_id'); 19 | $table->unsignedBigInteger('follow_id'); 20 | $table->timestamps(); 21 | }); 22 | } 23 | 24 | /** 25 | * Reverse the migrations. 26 | * 27 | * @return void 28 | */ 29 | public function down() 30 | { 31 | Schema::dropIfExists('followers'); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /database/migrations/2016_12_12_171655_create_notifications_table.php: -------------------------------------------------------------------------------- 1 | uuid('id')->primary(); 17 | $table->string('type'); 18 | $table->morphs('notifiable'); 19 | $table->text('data'); 20 | $table->timestamp('read_at')->nullable(); 21 | $table->timestamps(); 22 | }); 23 | } 24 | 25 | /** 26 | * Reverse the migrations. 27 | * 28 | * @return void 29 | */ 30 | public function down() 31 | { 32 | Schema::dropIfExists('notifications'); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /database/migrations/2016_12_12_205419_create_failed_jobs_table.php: -------------------------------------------------------------------------------- 1 | string('uuid')->after('id')->nullable()->unique(); 18 | $table->text('connection'); 19 | $table->text('queue'); 20 | $table->longText('payload'); 21 | $table->longText('exception'); 22 | $table->timestamp('failed_at')->useCurrent(); 23 | }); 24 | } 25 | 26 | /** 27 | * Reverse the migrations. 28 | * 29 | * @return void 30 | */ 31 | public function down() 32 | { 33 | Schema::dropIfExists('failed_jobs'); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /database/seeds/.gitkeep: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /database/seeds/ArticlesTableSeeder.php: -------------------------------------------------------------------------------- 1 | create(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /database/seeds/CategoriesTableSeeder.php: -------------------------------------------------------------------------------- 1 | create(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /database/seeds/CommentsTableSeeder.php: -------------------------------------------------------------------------------- 1 | create(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /database/seeds/DatabaseSeeder.php: -------------------------------------------------------------------------------- 1 | call(UsersTableSeeder::class); 17 | $this->call(CategoriesTableSeeder::class); 18 | $this->call(ArticlesTableSeeder::class); 19 | $this->call(DiscussionsTableSeeder::class); 20 | $this->call(CommentsTableSeeder::class); 21 | $this->call(TagsTableSeeder::class); 22 | $this->call(LinksTableSeeder::class); 23 | $this->call(VisitorsTableSeeder::class); 24 | $this->call(PermissionTableSeeder::class); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /database/seeds/DiscussionsTableSeeder.php: -------------------------------------------------------------------------------- 1 | create(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /database/seeds/LinksTableSeeder.php: -------------------------------------------------------------------------------- 1 | create(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /database/seeds/TagsTableSeeder.php: -------------------------------------------------------------------------------- 1 | create(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /database/seeds/UsersTableSeeder.php: -------------------------------------------------------------------------------- 1 | config('blog.admin_name'), 22 | 'email' => config('blog.admin_email'), 23 | 'password' => Hash::make(config('blog.admin_password')), 24 | 'status' => true, 25 | 'is_admin' => true, 26 | 'confirm_code' => Str::random(64), 27 | 'created_at' => Carbon::now(), 28 | 'updated_at' => Carbon::now() 29 | ] 30 | ]; 31 | 32 | DB::table('users')->insert($users); 33 | 34 | factory(User::class, 10)->create(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /database/seeds/VisitorsTableSeeder.php: -------------------------------------------------------------------------------- 1 | create(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # run migration and app 4 | php artisan blog:install 5 | php artisan serve --host 0.0.0.0 6 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | ./tests/Unit 9 | 10 | 11 | 12 | ./tests/Feature 13 | 14 | 15 | 16 | 17 | ./app 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /public/.gitignore: -------------------------------------------------------------------------------- 1 | /uploads/avatar 2 | /uploads/links -------------------------------------------------------------------------------- /public/.htaccess: -------------------------------------------------------------------------------- 1 | 2 | 3 | Options -MultiViews 4 | 5 | 6 | RewriteEngine On 7 | 8 | # Redirect Trailing Slashes If Not A Folder... 9 | RewriteCond %{REQUEST_FILENAME} !-d 10 | RewriteRule ^(.*)/$ /$1 [L,R=301] 11 | 12 | # Handle Front Controller... 13 | RewriteCond %{REQUEST_FILENAME} !-d 14 | RewriteCond %{REQUEST_FILENAME} !-f 15 | RewriteRule ^ index.php [L] 16 | 17 | # Handle Authorization Header 18 | RewriteCond %{HTTP:Authorization} . 19 | RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] 20 | 21 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ronaldtech051/Laravel-Blog/9f425c503c4960c39da49494347ce4c293b18e73/public/favicon.ico -------------------------------------------------------------------------------- /public/images/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ronaldtech051/Laravel-Blog/9f425c503c4960c39da49494347ce4c293b18e73/public/images/default.png -------------------------------------------------------------------------------- /public/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ronaldtech051/Laravel-Blog/9f425c503c4960c39da49494347ce4c293b18e73/public/images/favicon.ico -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /resources/js/App.vue: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /resources/js/bootstrap.js: -------------------------------------------------------------------------------- 1 | 2 | window._ = require('lodash'); 3 | 4 | /** 5 | * We'll load jQuery and the Bootstrap jQuery plugin which provides support 6 | * for JavaScript based Bootstrap features such as modals and tabs. This 7 | * code may be modified to fit the specific needs of your application. 8 | */ 9 | 10 | try { 11 | window.Popper = require('popper.js').default; 12 | window.$ = window.jQuery = require('jquery'); 13 | 14 | require('bootstrap'); 15 | } catch (e) {} 16 | 17 | window.swal = require('sweetalert2'); 18 | 19 | /** 20 | * Echo exposes an expressive API for subscribing to channels and listening 21 | * for events that are broadcast by Laravel. Echo and event broadcasting 22 | * allows your team to easily build robust real-time web applications. 23 | */ 24 | 25 | // import Echo from "laravel-echo" 26 | 27 | // window.Echo = new Echo({ 28 | // broadcaster: 'pusher', 29 | // key: 'your-pusher-key' 30 | // }); 31 | -------------------------------------------------------------------------------- /resources/js/config/base.js: -------------------------------------------------------------------------------- 1 | export const apiUrl = '/api/' 2 | -------------------------------------------------------------------------------- /resources/js/config/helper.js: -------------------------------------------------------------------------------- 1 | export function stack_error(response) { 2 | if (typeof response.data == 'string') { 3 | toastr.error(response.status + ' ' + response.statusText) 4 | } else { 5 | let data = response.data.errors 6 | let content = ''; 7 | 8 | Object.keys(data).map(function(key, index) { 9 | let value = data[key]; 10 | 11 | content += '' + value[0] + '
'; 12 | }); 13 | 14 | swal({ 15 | title: "Error Text!", 16 | type: 'error', 17 | html: content 18 | }); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /resources/js/config/toastr.js: -------------------------------------------------------------------------------- 1 | export default { 2 | positionClass: "toast-bottom-right", 3 | showDuration: "300", 4 | hideDuration: "1000", 5 | timeOut: "5000", 6 | extendedTimeOut: "1000", 7 | showEasing: "swing", 8 | hideEasing: "linear", 9 | showMethod: "fadeIn", 10 | hideMethod: "fadeOut" 11 | } 12 | -------------------------------------------------------------------------------- /resources/js/dashboard/components/Form.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 29 | -------------------------------------------------------------------------------- /resources/js/dashboard/components/TablePagination.vue: -------------------------------------------------------------------------------- 1 | 29 | 41 | 42 | 54 | -------------------------------------------------------------------------------- /resources/js/dashboard/components/TablePaginationMixin.vue: -------------------------------------------------------------------------------- 1 | 66 | -------------------------------------------------------------------------------- /resources/js/dashboard/components/particals/FooterBar.vue: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /resources/js/dashboard/components/particals/Navbar.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 20 | -------------------------------------------------------------------------------- /resources/js/dashboard/index.js: -------------------------------------------------------------------------------- 1 | export { default as routes } from './routes' 2 | -------------------------------------------------------------------------------- /resources/js/dashboard/modules/article/Create.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 19 | -------------------------------------------------------------------------------- /resources/js/dashboard/modules/article/Edit.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 30 | -------------------------------------------------------------------------------- /resources/js/dashboard/modules/article/index.js: -------------------------------------------------------------------------------- 1 | export { default as routes } from './routes' 2 | -------------------------------------------------------------------------------- /resources/js/dashboard/modules/article/routes.js: -------------------------------------------------------------------------------- 1 | export default [{ 2 | path: 'articles', 3 | component: () => import('js/App.vue'), 4 | children: [{ 5 | path: '/', 6 | name: 'dashboard.article', 7 | component: () => import('./Article') 8 | }, { 9 | path: 'create', 10 | name: 'dashboard.article.create', 11 | component: () => import('./Create') 12 | }, { 13 | path: ':id/edit', 14 | name: 'dashboard.article.edit', 15 | component: () => import('./Edit') 16 | }] 17 | }] 18 | -------------------------------------------------------------------------------- /resources/js/dashboard/modules/category/Create.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 19 | -------------------------------------------------------------------------------- /resources/js/dashboard/modules/category/Edit.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 35 | -------------------------------------------------------------------------------- /resources/js/dashboard/modules/category/index.js: -------------------------------------------------------------------------------- 1 | export { default as routes } from './routes' 2 | -------------------------------------------------------------------------------- /resources/js/dashboard/modules/category/routes.js: -------------------------------------------------------------------------------- 1 | export default [{ 2 | path: 'categories', 3 | component: () => import('js/App.vue'), 4 | children: [{ 5 | path: '/', 6 | name: 'dashboard.category', 7 | component: () => import('./Category') 8 | }, { 9 | path: 'create', 10 | name: 'dashboard.category.create', 11 | component: () => import('./Create') 12 | }, { 13 | path: ':id/edit', 14 | name: 'dashboard.category.edit', 15 | component: () => import('./Edit') 16 | }] 17 | }] 18 | -------------------------------------------------------------------------------- /resources/js/dashboard/modules/comment/index.js: -------------------------------------------------------------------------------- 1 | export { default as routes } from './routes' 2 | -------------------------------------------------------------------------------- /resources/js/dashboard/modules/comment/routes.js: -------------------------------------------------------------------------------- 1 | export default [{ 2 | path: 'comments', 3 | component: () => import('js/App.vue'), 4 | children: [{ 5 | path: '/', 6 | name: 'dashboard.comment', 7 | component: () => import('./Comment') 8 | }, 9 | { 10 | path: ':id/edit', 11 | name: 'dashboard.comment.edit', 12 | component: () => import('./Edit') 13 | }] 14 | }] 15 | -------------------------------------------------------------------------------- /resources/js/dashboard/modules/discussion/Create.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 19 | -------------------------------------------------------------------------------- /resources/js/dashboard/modules/discussion/Edit.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 35 | -------------------------------------------------------------------------------- /resources/js/dashboard/modules/discussion/index.js: -------------------------------------------------------------------------------- 1 | export { default as routes } from './routes' 2 | -------------------------------------------------------------------------------- /resources/js/dashboard/modules/discussion/routes.js: -------------------------------------------------------------------------------- 1 | export default [{ 2 | path: 'discussions', 3 | component: () => import('js/App.vue'), 4 | children: [{ 5 | path: '/', 6 | name: 'dashboard.discussion', 7 | component: () => import('./Discussion') 8 | }, { 9 | path: 'create', 10 | name: 'dashboard.discussion.create', 11 | component: () => import('./Create') 12 | }, { 13 | path: ':id/edit', 14 | name: 'dashboard.discussion.edit', 15 | component: () => import('./Edit') 16 | }] 17 | }] 18 | -------------------------------------------------------------------------------- /resources/js/dashboard/modules/file/index.js: -------------------------------------------------------------------------------- 1 | export { default as routes } from './routes' 2 | -------------------------------------------------------------------------------- /resources/js/dashboard/modules/file/routes.js: -------------------------------------------------------------------------------- 1 | export default [{ 2 | path: 'files', 3 | name: 'dashboard.file', 4 | component: () => import('./File') 5 | }] 6 | -------------------------------------------------------------------------------- /resources/js/dashboard/modules/home/index.js: -------------------------------------------------------------------------------- 1 | export { default as routes } from './routes' 2 | -------------------------------------------------------------------------------- /resources/js/dashboard/modules/home/routes.js: -------------------------------------------------------------------------------- 1 | export default [{ 2 | path: '/', 3 | redirect: { name: 'dashboard.home' }, 4 | }, { 5 | name: 'dashboard.home', 6 | path: 'home', 7 | component: () => import('./Home'), 8 | }] 9 | -------------------------------------------------------------------------------- /resources/js/dashboard/modules/link/Create.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 19 | -------------------------------------------------------------------------------- /resources/js/dashboard/modules/link/Edit.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 35 | -------------------------------------------------------------------------------- /resources/js/dashboard/modules/link/index.js: -------------------------------------------------------------------------------- 1 | export { default as routes } from './routes' 2 | -------------------------------------------------------------------------------- /resources/js/dashboard/modules/link/routes.js: -------------------------------------------------------------------------------- 1 | export default [{ 2 | path: 'links', 3 | component: () => import('js/App.vue'), 4 | children: [{ 5 | path: '/', 6 | name: 'dashboard.link', 7 | component: () => import('./Link') 8 | }, { 9 | path: 'create', 10 | name: 'dashboard.link.create', 11 | component: () => import('./Create') 12 | }, { 13 | path: ':id/edit', 14 | name: 'dashboard.link.edit', 15 | component: () => import('./Edit') 16 | }] 17 | }] 18 | -------------------------------------------------------------------------------- /resources/js/dashboard/modules/role/Create.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 19 | -------------------------------------------------------------------------------- /resources/js/dashboard/modules/role/Edit.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 35 | -------------------------------------------------------------------------------- /resources/js/dashboard/modules/role/index.js: -------------------------------------------------------------------------------- 1 | export { default as routes } from './routes' 2 | -------------------------------------------------------------------------------- /resources/js/dashboard/modules/role/routes.js: -------------------------------------------------------------------------------- 1 | export default [{ 2 | path: 'roles', 3 | component: () => import('js/App.vue'), 4 | children: [{ 5 | path: '/', 6 | name: 'dashboard.role', 7 | component: () => import('./Role') 8 | }, { 9 | path: 'create', 10 | name: 'dashboard.role.create', 11 | component: () => import('./Create') 12 | }, { 13 | path: ':id/edit', 14 | name: 'dashboard.role.edit', 15 | component: () => import('./Edit') 16 | }, { 17 | path: ':id/permissions', 18 | name: 'dashboard.role.permission', 19 | component: () => import('./Permission') 20 | }] 21 | }] 22 | -------------------------------------------------------------------------------- /resources/js/dashboard/modules/system/index.js: -------------------------------------------------------------------------------- 1 | export { default as routes } from './routes' 2 | -------------------------------------------------------------------------------- /resources/js/dashboard/modules/system/routes.js: -------------------------------------------------------------------------------- 1 | export default [{ 2 | path: 'system', 3 | name: 'dashboard.system', 4 | component: () => import('./System') 5 | }] 6 | -------------------------------------------------------------------------------- /resources/js/dashboard/modules/tag/Create.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 19 | -------------------------------------------------------------------------------- /resources/js/dashboard/modules/tag/Edit.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 35 | -------------------------------------------------------------------------------- /resources/js/dashboard/modules/tag/index.js: -------------------------------------------------------------------------------- 1 | export { default as routes } from './routes' 2 | -------------------------------------------------------------------------------- /resources/js/dashboard/modules/tag/routes.js: -------------------------------------------------------------------------------- 1 | export default [{ 2 | path: 'tags', 3 | component: () => import('js/App.vue'), 4 | children: [{ 5 | path: '/', 6 | name: 'dashboard.tag', 7 | component: () => import('./Tag') 8 | }, { 9 | path: 'create', 10 | name: 'dashboard.tag.create', 11 | component: () => import('./Create') 12 | }, { 13 | path: ':id/edit', 14 | name: 'dashboard.tag.edit', 15 | component: () => import('./Edit') 16 | }] 17 | }] 18 | -------------------------------------------------------------------------------- /resources/js/dashboard/modules/user/Create.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 19 | -------------------------------------------------------------------------------- /resources/js/dashboard/modules/user/Edit.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 35 | -------------------------------------------------------------------------------- /resources/js/dashboard/modules/user/index.js: -------------------------------------------------------------------------------- 1 | export { default as routes } from './routes' 2 | -------------------------------------------------------------------------------- /resources/js/dashboard/modules/user/routes.js: -------------------------------------------------------------------------------- 1 | export default [{ 2 | path: 'users', 3 | component: () => import ('js/App.vue'), 4 | children: [{ 5 | path: '/', 6 | name: 'dashboard.user', 7 | component: () => 8 | import ('./User') 9 | }, { 10 | path: 'create', 11 | name: 'dashboard.user.create', 12 | component: () => 13 | import ('./Create') 14 | }, { 15 | path: ':id/edit', 16 | name: 'dashboard.user.edit', 17 | component: () => 18 | import ('./Edit') 19 | }] 20 | }] 21 | -------------------------------------------------------------------------------- /resources/js/dashboard/modules/visitor/Visitor.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 42 | -------------------------------------------------------------------------------- /resources/js/dashboard/modules/visitor/index.js: -------------------------------------------------------------------------------- 1 | export { default as routes } from './routes' 2 | -------------------------------------------------------------------------------- /resources/js/dashboard/modules/visitor/routes.js: -------------------------------------------------------------------------------- 1 | export default [{ 2 | path: 'visitors', 3 | name: 'dashboard.visitor', 4 | component: () => import('./Visitor') 5 | }] 6 | -------------------------------------------------------------------------------- /resources/js/dashboard/routes.js: -------------------------------------------------------------------------------- 1 | import { routes as article } from './modules/article/index' 2 | import { routes as category } from './modules/category/index' 3 | import { routes as comment } from './modules/comment/index' 4 | import { routes as discussion } from './modules/discussion/index' 5 | import { routes as file } from './modules/file/index' 6 | import { routes as home } from './modules/home/index' 7 | import { routes as link } from './modules/link/index' 8 | import { routes as system } from './modules/system/index' 9 | import { routes as tag } from './modules/tag/index' 10 | import { routes as user } from './modules/user/index' 11 | import { routes as visitor } from './modules/visitor/index' 12 | import { routes as role } from './modules/role/index' 13 | 14 | export default [{ 15 | path: '/dashboard', 16 | component: () => import ('./Main'), 17 | beforeEnter: requireAuth, 18 | children: [ 19 | ...home, 20 | ...user, 21 | ...article, 22 | ...discussion, 23 | ...category, 24 | ...comment, 25 | ...tag, 26 | ...link, 27 | ...file, 28 | ...visitor, 29 | ...role, 30 | ...system, 31 | ], 32 | }] 33 | 34 | function requireAuth(to, from, next) { 35 | if (window.User) { 36 | return next() 37 | } else { 38 | return next('/') 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /resources/js/dashboard/runtime/constants/permission.js: -------------------------------------------------------------------------------- 1 | export default { 2 | // User 3 | LIST_USER: 'list_user', 4 | CREATE_USER: 'create_user', 5 | UPDATE_USER: 'update_user', 6 | DESTROY_USER: 'destroy_user', 7 | 8 | // Article 9 | LIST_ARTICLE: 'list_article', 10 | CREATE_ARTICLE: 'create_article', 11 | UPDATE_ARTICLE: 'update_article', 12 | DESTROY_ARTICLE: 'destroy_article', 13 | 14 | // Discussion 15 | LIST_DISCUSSION: 'list_discussion', 16 | CREATE_DISCUSSION: 'create_discussion', 17 | UPDATE_DISCUSSION: 'update_discussion', 18 | DESTROY_DISCUSSION: 'destroy_discussion', 19 | 20 | // Comment 21 | LIST_COMMENT: 'list_comment', 22 | UPDATE_COMMENT: 'update_comment', 23 | DESTROY_COMMENT: 'destroy_comment', 24 | 25 | // File 26 | LIST_FILE: 'list_file', 27 | CREATE_FOLDER: 'create_folder', 28 | UPLOAD_FILE: 'upload_file', 29 | DESTROY_FILE: 'destroy_file', 30 | 31 | // Tag 32 | LIST_TAG: 'list_tag', 33 | CREATE_TAG: 'create_tag', 34 | UPDATE_TAG: 'update_tag', 35 | DESTROY_TAG: 'destroy_tag', 36 | 37 | // Category 38 | LIST_CATEGORY: 'list_category', 39 | CREATE_CATEGORY: 'create_category', 40 | UPDATE_CATEGORY: 'update_category', 41 | DESTROY_CATEGORY: 'destroy_category', 42 | 43 | // Link 44 | LIST_LINK: 'list_link', 45 | CREATE_LINK: 'create_link', 46 | UPDATE_LINK: 'update_link', 47 | DESTROY_LINK: 'destroy_link', 48 | 49 | // Role 50 | LIST_ROLE: 'list_role', 51 | CREATE_ROLE: 'create_role', 52 | UPDATE_ROLE: 'update_role', 53 | UPDATE_ROLE_PERMISSIONS: 'update_role_permissions', 54 | DESTROY_ROLE: 'destroy_role', 55 | 56 | // Visitor 57 | LIST_VISITOR: 'list_visitor', 58 | 59 | // System 60 | LIST_SYSTEM_INFO: 'list_system_info', 61 | } 62 | -------------------------------------------------------------------------------- /resources/js/dashboard/runtime/mixins/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import { 3 | checkPerm 4 | } from 'dashboard/runtime/utils' 5 | 6 | Vue.mixin({ 7 | methods: { 8 | 9 | /** 10 | * @desc Check the user if has the permission 11 | * 12 | * @param {string} permission 13 | * 14 | * @returns {boolean} 15 | */ 16 | checkPermission(permission) { 17 | let data = window.Permissions 18 | 19 | if (window.isSuperAdmin) { 20 | return true 21 | } 22 | 23 | return checkPerm(data, permission) 24 | }, 25 | 26 | /** 27 | * @desc Check the user if has the permissions 28 | * 29 | * @param {string} permissions 30 | * 31 | * @returns {boolean} 32 | */ 33 | checkPermissions(permissions) { 34 | let i = 0, 35 | data = window.Permissions 36 | 37 | if (window.isSuperAdmin) { 38 | return true 39 | } 40 | 41 | permissions.forEach((item) => { 42 | if (item.permission) { 43 | i = checkPerm(data, item.permission) ? i + 1 : i 44 | } 45 | }) 46 | 47 | return i > 0 48 | } 49 | } 50 | }) 51 | -------------------------------------------------------------------------------- /resources/js/dashboard/runtime/utils/index.js: -------------------------------------------------------------------------------- 1 | export * from './misc' 2 | -------------------------------------------------------------------------------- /resources/js/dashboard/runtime/utils/misc.js: -------------------------------------------------------------------------------- 1 | import permission from 'dashboard/runtime/constants/permission' 2 | 3 | /** 4 | * @desc 权限检查 5 | * 6 | * @param {object} permissions - permissions 7 | * @param {string} perm - permission name 8 | * 9 | * @returns {boolean} - return 10 | */ 11 | 12 | export const checkPerm = (permissions, perm) => { 13 | if (!permissions) { 14 | return false 15 | } 16 | 17 | return ((permissions).indexOf(permission[perm]) >= 0) 18 | } 19 | -------------------------------------------------------------------------------- /resources/js/home.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import VueI18n from 'vue-i18n'; 3 | import locales from 'lang/index'; 4 | import httpPlugin from 'plugins/http/index'; 5 | 6 | try { 7 | window.Popper = require('popper.js').default; 8 | window.$ = window.jQuery = require('jquery'); 9 | 10 | require('bootstrap'); 11 | } catch (e) {} 12 | 13 | require('social-share.js/dist/js/social-share.min.js'); 14 | require('vendor/select2.min.js'); 15 | window.marked = require('marked'); 16 | window.hljs = require('vendor/highlight.min.js'); 17 | window.toastr = require('toastr/build/toastr.min.js'); 18 | 19 | Vue.use(VueI18n); 20 | Vue.use(httpPlugin); 21 | 22 | Vue.config.lang = window.Language; 23 | 24 | const i18n = new VueI18n({ 25 | locale: Vue.config.lang, 26 | messages: locales 27 | }) 28 | 29 | Vue.component('comment', require('home/components/Comment.vue').default); 30 | 31 | Vue.component('parse', require('home/components/Parse.vue').default); 32 | 33 | Vue.component('parse-textarea', require('home/components/Textarea.vue').default); 34 | 35 | Vue.component('avatar', require('home/components/AvatarUpload.vue').default); 36 | 37 | new Vue({ 38 | i18n: i18n, 39 | }).$mount('#app'); 40 | -------------------------------------------------------------------------------- /resources/js/home/components/Chartjs.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 54 | 55 | 60 | -------------------------------------------------------------------------------- /resources/js/home/components/Parse.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 40 | -------------------------------------------------------------------------------- /resources/js/home/components/Textarea.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 15 | -------------------------------------------------------------------------------- /resources/js/lang/en/index.js: -------------------------------------------------------------------------------- 1 | import sidebar from './sidebar' 2 | import page from './page' 3 | import table from './table' 4 | import form from './form' 5 | import permission from './permission' 6 | 7 | export default { 8 | sidebar, 9 | page, 10 | table, 11 | form, 12 | permission 13 | } 14 | -------------------------------------------------------------------------------- /resources/js/lang/en/page.js: -------------------------------------------------------------------------------- 1 | export default { 2 | users: 'Users', 3 | visitors: 'Visitors', 4 | articles: 'Articles', 5 | roles: 'Roles', 6 | comments: 'Comments', 7 | discussions: 'Discussions', 8 | files: 'Files', 9 | tags: 'Tags', 10 | categories: 'Categories', 11 | links: 'Links', 12 | systems: 'Systems', 13 | user_num: 'Users', 14 | view_num: 'Views', 15 | article_num: 'Articles', 16 | comment_num: 'Comments', 17 | all: 'All', 18 | admin: 'Admin', 19 | create: 'Create', 20 | system: 'System', 21 | database: 'Database', 22 | key: 'Setting', 23 | value: 'Value', 24 | server: 'Web Server', 25 | domain: 'Domain', 26 | version: 'Version', 27 | extension: 'Extension', 28 | driver: 'Driver', 29 | nothing: 'No Content' 30 | } 31 | -------------------------------------------------------------------------------- /resources/js/lang/en/permission.js: -------------------------------------------------------------------------------- 1 | export default { 2 | user: 'User Permissions', 3 | article: 'Article Permissions', 4 | discussion: 'Discussion Permissions', 5 | comment: 'Comment Permissions', 6 | file: 'File Permissions', 7 | tag: 'Tag Permissions', 8 | category: 'Category Permissions', 9 | link: 'Link Permissions', 10 | role: 'Role Permissions', 11 | visitor: 'Visitor Permissions', 12 | system: 'System Permissions', 13 | } 14 | -------------------------------------------------------------------------------- /resources/js/lang/en/sidebar.js: -------------------------------------------------------------------------------- 1 | export default { 2 | dashboard: 'Dashboard', 3 | user: 'Users', 4 | article: 'Articles', 5 | discussion: 'Discussion', 6 | comment: 'Comments', 7 | tag: 'Tags', 8 | file: 'Files', 9 | category: 'Categories', 10 | link: 'Links', 11 | visitor: 'Visitors', 12 | role: 'Roles', 13 | system: 'Systems', 14 | modules: { 15 | base: 'Base Module', 16 | content: 'Content Module', 17 | system: 'System Module' 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /resources/js/lang/en/table.js: -------------------------------------------------------------------------------- 1 | export default { 2 | id: 'ID', 3 | avatar: 'Avatar', 4 | username: 'User Name', 5 | email: 'E-Mail Address', 6 | status: 'Status', 7 | title: 'Title', 8 | guard_name: 'Guard', 9 | subtitle: 'Sub Title', 10 | created_at: 'Created At', 11 | published_at: 'Published At', 12 | comment_type: 'Commentable Type', 13 | comment_title: 'Commentable Title', 14 | tag: 'Tag', 15 | meta_description: 'Meta Description', 16 | name: 'Name', 17 | type: 'Type', 18 | date: 'Date Time', 19 | size: 'Size', 20 | action: 'Actions', 21 | path: 'Path', 22 | image: 'Image', 23 | link: 'Link', 24 | enabled: 'Enabled', 25 | article_title: 'Article Title', 26 | click_num: 'Clicks Num', 27 | comment_count: 'Comments', 28 | ip: 'IP', 29 | new_folder: 'New Folder', 30 | vote_count: 'Votes', 31 | upload: 'Uplaod' 32 | } 33 | -------------------------------------------------------------------------------- /resources/js/lang/es/index.js: -------------------------------------------------------------------------------- 1 | import sidebar from './sidebar' 2 | import page from './page' 3 | import table from './table' 4 | import form from './form' 5 | import permission from './permission' 6 | 7 | export default { 8 | sidebar, 9 | page, 10 | table, 11 | form, 12 | permission 13 | } 14 | -------------------------------------------------------------------------------- /resources/js/lang/es/page.js: -------------------------------------------------------------------------------- 1 | export default { 2 | users: 'Usuarios', 3 | visitors: 'Visitantes', 4 | articles: 'Artículos', 5 | roles: 'Roles', 6 | comments: 'Comentarios', 7 | discussions: 'Discusiones', 8 | files: 'Archivos', 9 | tags: 'Etiquetas', 10 | categories: 'Categorías', 11 | links: 'Enlaces', 12 | systems: 'Sistemas', 13 | user_num: 'Usuarios', 14 | view_num: 'Puntos de vista', 15 | article_num: 'Artículos', 16 | comment_num: 'Comentarios', 17 | all: 'Todas', 18 | admin: 'Admin', 19 | create: 'Crear', 20 | system: 'Sistema', 21 | database: 'Base de datos', 22 | key: 'Ajuste', 23 | value: 'Valor', 24 | server: 'Servidor web', 25 | domain: 'Dominio', 26 | version: 'Versión', 27 | extension: 'Extensión', 28 | driver: 'Conductor', 29 | nothing: 'Sin contenido' 30 | } 31 | -------------------------------------------------------------------------------- /resources/js/lang/es/permission.js: -------------------------------------------------------------------------------- 1 | export default { 2 | user: 'Permisos de usuario', 3 | article: 'Permisos de artículos', 4 | discussion: 'Permisos de discusión', 5 | comment: 'Permisos de comentarios', 6 | file: 'Permisos de archivo', 7 | tag: 'Permisos de etiqueta', 8 | category: 'Permisos de categoría', 9 | link: 'Permisos de enlace', 10 | role: 'Permisos de roles', 11 | visitor: 'Permisos de visitante', 12 | system: 'Permisos del sistema', 13 | } 14 | -------------------------------------------------------------------------------- /resources/js/lang/es/sidebar.js: -------------------------------------------------------------------------------- 1 | export default { 2 | dashboard: 'Tablero', 3 | user: 'Usuarios', 4 | article: 'Artículos', 5 | discussion: 'Discusión', 6 | comment: 'Comentarios', 7 | tag: 'Etiquetas', 8 | file: 'Archivos', 9 | category: 'Categorías', 10 | link: 'Enlaces', 11 | visitor: 'Visitantes', 12 | role: 'Roles', 13 | system: 'Sistemas', 14 | modules: { 15 | base: 'Módulo base', 16 | content: 'Módulo de contenido', 17 | system: 'Módulo del sistema' 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /resources/js/lang/es/table.js: -------------------------------------------------------------------------------- 1 | export default { 2 | id: 'ID', 3 | avatar: 'Avatar', 4 | username: 'Nombre de usuario', 5 | email: 'Dirección de correo electrónico', 6 | status: 'Estado', 7 | title: 'Título', 8 | guard_name: 'Guardia', 9 | subtitle: 'Subtítulo', 10 | created_at: 'Fecha de creacion', 11 | published_at: 'Publicado en', 12 | comment_type: 'Tipo', 13 | comment_title: 'Título de comentario', 14 | tag: 'Etiqueta', 15 | meta_description: 'Descripcion corta', 16 | name: 'Nombre', 17 | type: 'Tipo', 18 | date: 'Fecha y hora', 19 | size: 'Talla', 20 | action: 'Acciones', 21 | path: 'Camino', 22 | image: 'Imagen', 23 | link: 'Enlace', 24 | enabled: 'Habilitado', 25 | article_title: 'Título del artículo', 26 | click_num: 'Numero de Clicks ', 27 | comment_count: 'Comentarios', 28 | ip: 'IP', 29 | new_folder: 'Nueva carpeta', 30 | vote_count: 'Votos', 31 | upload: 'Uplaod' 32 | } 33 | -------------------------------------------------------------------------------- /resources/js/lang/index.js: -------------------------------------------------------------------------------- 1 | import en from './en/index' 2 | import ru from './ru/index' 3 | import zh_cn from './zh_cn/index' 4 | import es from './es/index' 5 | 6 | export default { 7 | en, 8 | ru, 9 | zh_cn, 10 | es 11 | } 12 | -------------------------------------------------------------------------------- /resources/js/lang/ru/index.js: -------------------------------------------------------------------------------- 1 | import sidebar from './sidebar' 2 | import page from './page' 3 | import table from './table' 4 | import form from './form' 5 | import permission from './permission' 6 | 7 | export default { 8 | sidebar, 9 | page, 10 | table, 11 | form, 12 | permission 13 | } 14 | -------------------------------------------------------------------------------- /resources/js/lang/ru/page.js: -------------------------------------------------------------------------------- 1 | export default { 2 | users: 'Пользователей', 3 | visitors: 'Посетителей', 4 | articles: 'Статей', 5 | roles: 'Роли', 6 | comments: 'Комментариев', 7 | discussions: 'Обсуждений', 8 | files: 'Файлов', 9 | tags: 'Тегов', 10 | categories: 'Категорий', 11 | links: 'Ссылок', 12 | systems: 'Систем', 13 | user_num: 'Пользователей', 14 | view_num: 'Просмотров', 15 | article_num: 'Статей', 16 | comment_num: 'Комментариев', 17 | all: 'Все', 18 | admin: 'Админ', 19 | create: 'Создать', 20 | system: 'Система', 21 | database: 'База данных', 22 | key: 'Конфигурация', 23 | value: 'Значение', 24 | server: 'Веб Сервер', 25 | domain: 'Домен', 26 | version: 'Версия', 27 | extension: 'Расширение', 28 | driver: 'Драйвер', 29 | nothing: 'Нет Контента' 30 | } 31 | -------------------------------------------------------------------------------- /resources/js/lang/ru/permission.js: -------------------------------------------------------------------------------- 1 | export default { 2 | user: 'Пользовательские разрешения', 3 | article: 'Разрешения для статьи', 4 | discussion: 'Разрешения для обсуждения', 5 | comment: 'Комментарий Разрешения', 6 | file: 'Разрешения для файлов', 7 | tag: 'Разрешения для тегов', 8 | category: 'Разрешения категории', 9 | link: 'Разрешение ссылок', 10 | role: 'Разрешения на роль', 11 | visitor: 'Разрешения для посетителей', 12 | system: 'Системные разрешения', 13 | } 14 | -------------------------------------------------------------------------------- /resources/js/lang/ru/sidebar.js: -------------------------------------------------------------------------------- 1 | export default { 2 | dashboard: 'Дашборд', 3 | user: 'Пользователи', 4 | article: 'Статьи', 5 | discussion: 'Обсуждения', 6 | comment: 'Комментарии', 7 | tag: 'Теги', 8 | file: 'Файлы', 9 | category: 'Категории', 10 | link: 'Ссылки', 11 | visitor: 'Посетители', 12 | role: 'Роли', 13 | system: 'Система', 14 | modules: { 15 | base: 'Базовый модуль', 16 | content: 'Модуль контента', 17 | system: 'Системный модуль' 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /resources/js/lang/ru/table.js: -------------------------------------------------------------------------------- 1 | export default { 2 | id: 'ID', 3 | avatar: 'Аватар', 4 | username: 'Имя пользователя', 5 | email: 'E-Mail адрес', 6 | status: 'Статус', 7 | title: 'Заголовок', 8 | guard_name: 'Oхрана', 9 | subtitle: 'Подзаголовок', 10 | created_at: 'Создано', 11 | published_at: 'Опубликовано', 12 | comment_type: 'Commentable Type', 13 | comment_title: 'Commentable Title', 14 | tag: 'Теги', 15 | meta_description: 'Meta описание', 16 | name: 'Имя', 17 | type: 'Тип', 18 | date: 'Время', 19 | size: 'Размер', 20 | action: 'Действия', 21 | path: 'Путь', 22 | image: 'Рисунок', 23 | link: 'Ссылка', 24 | enabled: 'Включено', 25 | article_title: 'Заголовок статьи', 26 | click_num: 'Кол-во кликов', 27 | comment_count: 'Комментарии', 28 | ip: 'IP', 29 | new_folder: 'Новая папка', 30 | vote_count: 'Голосов', 31 | upload: 'Загрузка' 32 | } 33 | -------------------------------------------------------------------------------- /resources/js/lang/zh_cn/index.js: -------------------------------------------------------------------------------- 1 | import sidebar from './sidebar' 2 | import page from './page' 3 | import table from './table' 4 | import form from './form' 5 | import permission from './permission' 6 | 7 | export default { 8 | sidebar, 9 | page, 10 | table, 11 | form, 12 | permission 13 | } 14 | -------------------------------------------------------------------------------- /resources/js/lang/zh_cn/page.js: -------------------------------------------------------------------------------- 1 | export default { 2 | users: '用户列表', 3 | visitors: '访问列表', 4 | articles: '文章列表', 5 | roles: '角色列表', 6 | comments: '评论列表', 7 | discussions: '讨论列表', 8 | files: '文件列表', 9 | tags: '标签列表', 10 | categories: '分类列表', 11 | links: '友链列表', 12 | systems: '系统设置', 13 | user_num: '用户数', 14 | view_num: '访问数', 15 | article_num: '文章数', 16 | comment_num: '评论数', 17 | all: '全部', 18 | admin: '管理员', 19 | create: '创建', 20 | system: '系统', 21 | database: '数据库', 22 | key: '设置', 23 | value: '值', 24 | server: '网站服务器', 25 | domain: '域名', 26 | version: '版本', 27 | extension: '扩展', 28 | driver: '驱动', 29 | nothing: 'No Content' 30 | } 31 | -------------------------------------------------------------------------------- /resources/js/lang/zh_cn/permission.js: -------------------------------------------------------------------------------- 1 | export default { 2 | user: '用户模块', 3 | article: '文章模块', 4 | discussion: '讨论模块', 5 | comment: '评论模块', 6 | file: '文件模块', 7 | tag: '标签模块', 8 | category: '分类模块', 9 | link: '友链模块', 10 | role: '角色模块', 11 | visitor: '访问模块', 12 | system: '系统模块', 13 | } 14 | -------------------------------------------------------------------------------- /resources/js/lang/zh_cn/sidebar.js: -------------------------------------------------------------------------------- 1 | export default { 2 | dashboard: '面板', 3 | user: '用户管理', 4 | article: '文章管理', 5 | discussion: '讨论管理', 6 | comment: '评论管理', 7 | tag: '标签管理', 8 | file: '文件管理', 9 | category: '分类管理', 10 | link: '友链管理', 11 | visitor: '访问列表', 12 | role: '角色列表', 13 | system: '系统配置', 14 | modules: { 15 | base: '基础模块', 16 | content: '内容模块', 17 | system: '系统模块' 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /resources/js/lang/zh_cn/table.js: -------------------------------------------------------------------------------- 1 | export default { 2 | id: 'ID', 3 | avatar: '头像', 4 | username: '用户名', 5 | email: '邮箱地址', 6 | status: '状态', 7 | title: '标题', 8 | guard_name: '应用范围', 9 | subtitle: '副标题', 10 | created_at: '创建时间', 11 | published_at: '发布时间', 12 | comment_type: '评论类型', 13 | comment_title: '评论标题', 14 | tag: '标签', 15 | meta_description: '描述', 16 | name: '名字', 17 | type: '类型', 18 | date: '日期', 19 | size: '大小', 20 | action: '操作', 21 | path: '路径', 22 | image: '图片', 23 | link: '链接', 24 | enabled: '是否启用', 25 | article_title: '文章标题', 26 | click_num: '点击次数', 27 | comment_count: '评论数', 28 | ip: 'IP', 29 | new_folder: '创建文件夹', 30 | vote_count: '投票数', 31 | upload: '上传图片' 32 | } 33 | -------------------------------------------------------------------------------- /resources/js/plugins/http/index.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | import { apiUrl } from 'config/base' 3 | 4 | /** 5 | * Create Axios 6 | */ 7 | export const http = axios.create({ 8 | baseURL: apiUrl, 9 | }) 10 | 11 | /** 12 | * We'll load the axios HTTP library which allows us to easily issue requests 13 | * to our Laravel back-end. This library automatically handles sending the 14 | * CSRF token as a header based on the value of the "XSRF" token cookie. 15 | */ 16 | http.defaults.headers.common = { 17 | 'X-CSRF-TOKEN': window.Laravel.csrfToken, 18 | 'X-Requested-With': 'XMLHttpRequest' 19 | }; 20 | 21 | /** 22 | * Handle all error messages. 23 | */ 24 | http.interceptors.response.use(function(response) { 25 | return response; 26 | }, function(error) { 27 | const { response } = error 28 | 29 | if ([401].indexOf(response.status) >= 0) { 30 | if (response.status == 401 && response.data.error.message != 'Unauthorized') { 31 | return Promise.reject(response); 32 | } 33 | window.location = '/login'; 34 | } 35 | 36 | if ([403].indexOf(response.status) >= 0) { 37 | toastr.error(response.data.message) 38 | } 39 | 40 | return Promise.reject(error); 41 | }); 42 | 43 | export default function install(Vue) { 44 | Object.defineProperty(Vue.prototype, '$http', { 45 | get() { 46 | return http 47 | }, 48 | }) 49 | } 50 | -------------------------------------------------------------------------------- /resources/js/router/beforeEach.js: -------------------------------------------------------------------------------- 1 | // import vuex from '../vuex' 2 | 3 | // const needAuth = route => route.meta.auth === true; 4 | 5 | const beforeEach = (to, from, next) => { 6 | // if (to.name == 'auth.login' || to.name == 'auth.account.login') { 7 | // $('body').removeClass('bg-default').addClass('bg-white') 8 | // } else { 9 | // $('body').removeClass('bg-white').addClass('bg-default') 10 | // } 11 | 12 | // vuex.dispatch('checkUserToken') 13 | // .then((token) => { 14 | // if (to.path.indexOf('dashboard') > 0) { 15 | // return next({ name: 'home' }) 16 | // } 17 | 18 | // return next() 19 | // }).catch((err) => { 20 | // if (needAuth(to)) { 21 | // // No token, or it is invalid 22 | // return next({ name: 'auth.account.login' }) // redirect to login 23 | // } 24 | // next() 25 | // }); 26 | next(); 27 | }; 28 | 29 | export default beforeEach 30 | -------------------------------------------------------------------------------- /resources/js/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Router from 'vue-router' 3 | import beforeEach from './beforeEach' 4 | import { routes as dashboard } from '../dashboard/index' 5 | 6 | Vue.use(Router); 7 | 8 | const AppRoute = { 9 | path: '/', 10 | component: () => import('../App.vue'), 11 | children: [...dashboard], 12 | }; 13 | 14 | const routes = [AppRoute]; 15 | 16 | const router = new Router({ 17 | routes, 18 | linkActiveClass: 'active', 19 | linkExactActiveClass: 'active', 20 | mode: 'history', 21 | }); 22 | 23 | router.beforeEach(beforeEach); 24 | 25 | export default router 26 | -------------------------------------------------------------------------------- /resources/js/vuex/actions.js: -------------------------------------------------------------------------------- 1 | export const toggle = ({ commit }) => commit('toggle') 2 | -------------------------------------------------------------------------------- /resources/js/vuex/mutations.js: -------------------------------------------------------------------------------- 1 | export const toggle = state => { 2 | return state.sidebar.opened = !state.sidebar.opened 3 | } 4 | -------------------------------------------------------------------------------- /resources/js/vuex/store.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import Vuex from 'vuex'; 3 | import * as actions from './actions.js'; 4 | import * as mutations from './mutations.js'; 5 | 6 | Vue.use(Vuex); 7 | 8 | const state = { 9 | sidebar: { 10 | opened: false 11 | } 12 | }; 13 | 14 | export default new Vuex.Store({ 15 | state, 16 | actions, 17 | mutations 18 | }); 19 | -------------------------------------------------------------------------------- /resources/lang/en/auth.php: -------------------------------------------------------------------------------- 1 | 'These credentials do not match our records.', 17 | 'throttle' => 'Too many login attempts. Please try again in :seconds seconds.', 18 | 19 | ]; 20 | -------------------------------------------------------------------------------- /resources/lang/en/pagination.php: -------------------------------------------------------------------------------- 1 | '« Previous', 17 | 'next' => 'Next »', 18 | 19 | ]; 20 | -------------------------------------------------------------------------------- /resources/lang/en/passwords.php: -------------------------------------------------------------------------------- 1 | 'Passwords must be at least six characters and match the confirmation.', 17 | 'reset' => 'Your password has been reset!', 18 | 'sent' => 'We have e-mailed your password reset link!', 19 | 'token' => 'This password reset token is invalid.', 20 | 'user' => "We can't find a user with that e-mail address.", 21 | 'check_old_password' => 'The password must be the same of current password.', 22 | 23 | ]; 24 | -------------------------------------------------------------------------------- /resources/lang/es/auth.php: -------------------------------------------------------------------------------- 1 | 'Estas credenciales no coinciden con nuestros registros', 17 | 'throttle' => 'Demasiados intentos de inicio de sesión. Inténtalo de nuevo en: segundos segundos. ', 18 | 19 | ]; 20 | -------------------------------------------------------------------------------- /resources/lang/es/pagination.php: -------------------------------------------------------------------------------- 1 | '« Anterior', 16 | 'next' => 'Siguiente »', 17 | ]; 18 | -------------------------------------------------------------------------------- /resources/lang/es/passwords.php: -------------------------------------------------------------------------------- 1 | '¡Tu contraseña ha sido restablecida!', 16 | 'sent' => '¡Te hemos enviado por correo el enlace para restablecer tu contraseña!', 17 | 'throttled' => 'Por favor espera antes de intentar de nuevo.', 18 | 'token' => 'El token de recuperación de contraseña es inválido.', 19 | 'user' => 'No podemos encontrar ningún usuario con ese correo electrónico.', 20 | 21 | 22 | 23 | 24 | 'password' => 'Las contraseñas deben tener al menos seis caracteres y coincidir con la confirmación', 25 | 26 | 27 | 28 | 'check_old_password' => 'La contraseña debe ser la misma que la contraseña actual.', 29 | 30 | ]; 31 | -------------------------------------------------------------------------------- /resources/lang/ru/auth.php: -------------------------------------------------------------------------------- 1 | 'Имя пользователя и пароль не совпадают.', 17 | 'throttle' => 'Слишком много попыток входа. Пожалуйста, попробуйте еще раз через :seconds секунд.', 18 | ]; 19 | -------------------------------------------------------------------------------- /resources/lang/ru/pagination.php: -------------------------------------------------------------------------------- 1 | '« Назад', 16 | 'next' => 'Вперёд »', 17 | ]; 18 | -------------------------------------------------------------------------------- /resources/lang/ru/passwords.php: -------------------------------------------------------------------------------- 1 | 'Пароль должен быть не менее шести символов и совпадать с подтверждением.', 16 | 'reset' => 'Ваш пароль был сброшен!', 17 | 'sent' => 'Ссылка на сброс пароля была отправлена!', 18 | 'token' => 'Ошибочный код сброса пароля.', 19 | 'user' => 'Не удалось найти пользователя с указанным электронным адресом.', 20 | ]; 21 | -------------------------------------------------------------------------------- /resources/lang/zh_cn/auth.php: -------------------------------------------------------------------------------- 1 | '用户名/密码不匹配.', 17 | 'throttle' => '登录尝试次数过多。 请在以下时间后重试 :seconds 秒.', 18 | 19 | ]; 20 | -------------------------------------------------------------------------------- /resources/lang/zh_cn/pagination.php: -------------------------------------------------------------------------------- 1 | '« 上一页', 17 | 'next' => '下一页 »', 18 | 19 | ]; 20 | -------------------------------------------------------------------------------- /resources/lang/zh_cn/passwords.php: -------------------------------------------------------------------------------- 1 | '密码必须至少为六个字符,并与确认密码相匹配.', 17 | 'reset' => '您的密码已重置!', 18 | 'sent' => '我们已通过电子邮件发送您的密码重置链接!', 19 | 'token' => '此密码重置令牌无效.', 20 | 'user' => "我们找不到具有该电子邮件地址的用户.", 21 | 'check_old_password' => '旧密码必须与原密码一致', 22 | 23 | ]; 24 | -------------------------------------------------------------------------------- /resources/sass/_box.scss: -------------------------------------------------------------------------------- 1 | .box { 2 | clear: both; 3 | margin-bottom: 25px; 4 | margin-top: 0; 5 | padding: 0; 6 | width: 100%; 7 | } 8 | .box-title { 9 | -moz-border-bottom-colors: none; 10 | -moz-border-left-colors: none; 11 | -moz-border-right-colors: none; 12 | -moz-border-top-colors: none; 13 | background-color: #fff; 14 | border-color: #e7eaec; 15 | border-image: none; 16 | border-style: solid solid none; 17 | border-width: 2px 0 0; 18 | color: inherit; 19 | margin-bottom: 0; 20 | padding: 10px 15px; 21 | min-height: 48px; 22 | } 23 | .box-default { 24 | border-color: #e7eaec; 25 | } 26 | .box-success { 27 | border-color: #3498db; 28 | } 29 | .box-success { 30 | border-color: #1abc9c; 31 | } 32 | .box-warning { 33 | border-color: #f1c40f; 34 | } 35 | .box-danger { 36 | border-color: #e74c3c; 37 | } 38 | .box-content { 39 | clear: both; 40 | background-color: #fff; 41 | color: inherit; 42 | padding: 15px 20px 20px 20px; 43 | border-color: #e7eaec; 44 | border-image: none; 45 | border-style: solid solid none; 46 | border-width: 1px 0; 47 | } 48 | .box-radius { 49 | .box-title { 50 | border-top-left-radius: 5px; 51 | border-top-right-radius: 5px; 52 | } 53 | .box-content { 54 | border-bottom-left-radius: 5px; 55 | border-bottom-right-radius: 5px; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /resources/sass/_comment.scss: -------------------------------------------------------------------------------- 1 | .comment { 2 | .heading { 3 | padding: 10px 20px; 4 | background: #ECF0F1; 5 | 6 | a { 7 | color: #7F8C8D; 8 | } 9 | } 10 | .box-body { 11 | border: 1px solid #ECF0F1; 12 | border-radius: 5px; 13 | background-color: #fff; 14 | color: #7F8C8D; 15 | } 16 | .media { 17 | padding-top: 20px; 18 | } 19 | .media-left:hover img, 20 | .media-right:hover img { 21 | -webkit-transform: rotateZ(360deg); 22 | -moz-transform: rotateZ(360deg); 23 | transform: rotateZ(360deg); 24 | } 25 | .media-left img { 26 | width: 64px; 27 | height: 64px; 28 | -webkit-transition: transition .6s ease-in; 29 | -moz-transition: transition .6s ease-in; 30 | transition: transform .6s ease-in; 31 | } 32 | .comment-editor { 33 | margin-top: 40px; 34 | } 35 | .footing { 36 | padding: 10px 20px; 37 | border-top: 1px dashed #e1e1e1; 38 | } 39 | .downvoted { 40 | background: #fff; 41 | opacity: .3; 42 | } 43 | .downvoted:hover { 44 | opacity: 1; 45 | } 46 | 47 | i { 48 | margin-right: 5px; 49 | } 50 | .operate { 51 | font-size: 17px; 52 | a { 53 | margin-right: 5px; 54 | text-decoration: none; 55 | } 56 | } 57 | .none { 58 | color: #c5c5c5; 59 | font-size: 16px; 60 | } 61 | } 62 | 63 | @media screen and (max-width: 767px) { 64 | .comment .media-left { 65 | display: none; 66 | } 67 | .own-avatar { 68 | display: none; 69 | } 70 | } 71 | 72 | .comment-body { 73 | padding: 30px 50px; 74 | color: #34495e; 75 | display: grid; 76 | 77 | a { 78 | color: #1abc9c; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /resources/sass/_form.scss: -------------------------------------------------------------------------------- 1 | .form-control, .form-control:focus, input{ 2 | border-width: 1px; 3 | -webkit-box-shadow: none; 4 | box-shadow: none; 5 | outline: 0; 6 | 7 | &::placeholder { 8 | color: #95a5a6; 9 | } 10 | } 11 | 12 | .col-form-label { 13 | text-align: right; 14 | } 15 | 16 | legend { 17 | border: none; 18 | } 19 | 20 | .well { 21 | border: none; 22 | box-shadow: none; 23 | min-height: 20px; 24 | padding: 19px; 25 | margin-bottom: 20px; 26 | background-color: #ecf0f1; 27 | border-radius: 4px; 28 | } 29 | -------------------------------------------------------------------------------- /resources/sass/_navbar.scss: -------------------------------------------------------------------------------- 1 | @media (min-width: 768px) { 2 | .navbar-nav > li > a {; 3 | padding-top: 17px; 4 | padding-bottom: 14px; 5 | } 6 | } 7 | 8 | .navbar-collapse { 9 | border: none; 10 | } 11 | 12 | .navbar-nav .dropdown-toggle { 13 | color: #fff; 14 | } 15 | 16 | .navbar-nav .notification i { 17 | color: #fff; 18 | } 19 | 20 | .notification { 21 | i { 22 | position: relative; 23 | font-size: 1.2rem; 24 | vertical-align: bottom; 25 | 26 | .new { 27 | position: absolute; 28 | top: -5px; 29 | right: -5px; 30 | width: 10px; 31 | height: 10px; 32 | border-radius: 50%; 33 | background-color: #d9534f; 34 | display: none; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /resources/sass/_toastr.scss: -------------------------------------------------------------------------------- 1 | .toast-success { 2 | background-color: #1abc9c; 3 | } 4 | .toast-error { 5 | background-color: #e74c3c; 6 | } 7 | .toast-info { 8 | background-color: #597289; 9 | } 10 | .toast-warning { 11 | background-color: #f1c40f; 12 | } 13 | #toast-container > div { 14 | opacity: 0.9; 15 | -ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=90); 16 | filter: alpha(opacity=90); 17 | } -------------------------------------------------------------------------------- /resources/sass/app.scss: -------------------------------------------------------------------------------- 1 | 2 | // Public 3 | @import "public"; 4 | 5 | //Simplemde 6 | @import url("vendor/simplemde.min.css"); 7 | 8 | // Markdown 9 | @import "markdown"; 10 | @import url("vendor/highlight.min.css"); 11 | 12 | @import "form"; 13 | @import "navbar"; 14 | @import "box"; 15 | @import "toastr"; 16 | @import "togglebutton"; 17 | 18 | body { 19 | background-color: #f9f9fb; 20 | color: #636b6f !important; 21 | } 22 | 23 | .navbar-toggler { 24 | color: $wet-asphalt; 25 | } 26 | 27 | .btn i { 28 | color: #fff; 29 | } 30 | 31 | .width-5-percent { 32 | width: 5%; 33 | } 34 | 35 | .width-10-percent { 36 | width: 10%; 37 | } 38 | 39 | .multiselect__content { 40 | z-index: 2; 41 | } 42 | 43 | .avatar { 44 | width: 50px; 45 | margin: 0 auto; 46 | } 47 | 48 | .editor-toolbar.fullscreen { 49 | z-index: 1000 !important; 50 | } 51 | 52 | .CodeMirror-fullscreen { 53 | z-index: 1000 !important; 54 | } 55 | 56 | .table-hover tbody tr:hover { 57 | background-color: #f9f9fb !important; 58 | } 59 | 60 | .text-upper { 61 | text-transform: uppercase; 62 | letter-spacing: .1rem; 63 | } 64 | -------------------------------------------------------------------------------- /resources/sass/home.scss: -------------------------------------------------------------------------------- 1 | 2 | // Public 3 | @import "public"; 4 | 5 | // Share.js 6 | @import "~social-share.js/src/css/share.scss"; 7 | 8 | // Select 2 9 | @import url("vendor/select2.min.css"); 10 | 11 | // Markdown 12 | @import "markdown"; 13 | @import url("vendor/highlight.min.css"); 14 | 15 | @import "form"; 16 | @import "navbar"; 17 | @import "pagination"; 18 | @import "togglebutton"; 19 | @import "toastr"; 20 | @import "comment"; 21 | @import "styles"; 22 | -------------------------------------------------------------------------------- /resources/sass/public.scss: -------------------------------------------------------------------------------- 1 | // Font-awesome 2 | @import '~@fortawesome/fontawesome-free/scss/fontawesome'; 3 | @import '~@fortawesome/fontawesome-free/scss/brands'; 4 | @import '~@fortawesome/fontawesome-free/scss/regular'; 5 | @import '~@fortawesome/fontawesome-free/scss/solid'; 6 | 7 | // Variables 8 | @import "variables"; 9 | 10 | // Bootstrap 11 | @import "~bootstrap/scss/bootstrap"; 12 | 13 | // Sweetalert 14 | @import "~sweetalert2/src/sweetalert2.scss"; 15 | 16 | // Toastr 17 | @import url("vendor/toastr.min.css"); 18 | -------------------------------------------------------------------------------- /resources/sass/themes/default-theme.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ronaldtech051/Laravel-Blog/9f425c503c4960c39da49494347ce4c293b18e73/resources/sass/themes/default-theme.scss -------------------------------------------------------------------------------- /resources/sass/vendor/highlight.min.css: -------------------------------------------------------------------------------- 1 | .hljs{display:block;overflow-x:auto;padding:0.5em;color:#abb2bf;background:#282c34}.hljs-comment,.hljs-quote{color:#5c6370;font-style:italic}.hljs-doctag,.hljs-keyword,.hljs-formula{color:#c678dd}.hljs-section,.hljs-name,.hljs-selector-tag,.hljs-deletion,.hljs-subst{color:#e06c75}.hljs-literal{color:#56b6c2}.hljs-string,.hljs-regexp,.hljs-addition,.hljs-attribute,.hljs-meta-string{color:#98c379}.hljs-built_in,.hljs-class .hljs-title{color:#e6c07b}.hljs-attr,.hljs-variable,.hljs-template-variable,.hljs-type,.hljs-selector-class,.hljs-selector-attr,.hljs-selector-pseudo,.hljs-number{color:#d19a66}.hljs-symbol,.hljs-bullet,.hljs-link,.hljs-meta,.hljs-selector-id,.hljs-title{color:#61aeee}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:bold}.hljs-link{text-decoration:underline} -------------------------------------------------------------------------------- /resources/views/article/index.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.app') 2 | 3 | @section('content') 4 | @component('particals.jumbotron') 5 |

{{ config('blog.article.title') }}

6 | 7 |
{{ config('blog.article.description') }}
8 | @endcomponent 9 | 10 | @include('widgets.article') 11 | 12 | {{ $articles->links('pagination.default') }} 13 | 14 | @endsection -------------------------------------------------------------------------------- /resources/views/category/index.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.app') 2 | 3 | @section('content') 4 | @component('particals.jumbotron') 5 |

{{ lang('Categories') }}

6 | 7 |
{{ lang('Categories Meta') }}
8 | @endcomponent 9 | 10 |
11 |
12 |
13 |
    14 | @forelse($categories as $category) 15 |
  • 16 | {{ $category->articles->count() }} 17 | {{ $category->name }} 18 |
  • 19 | @empty 20 |
  • {{ lang('Nothing') }}
  • 21 | @endforelse 22 |
23 |
24 |
25 |
26 | @endsection -------------------------------------------------------------------------------- /resources/views/category/show.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.app') 2 | 3 | @section('content') 4 | @component('particals.jumbotron') 5 |

{{ $category->name }}

6 | 7 |
{{ lang('Category Meta') }}
8 | @endcomponent 9 | 10 |
11 |
12 |
13 |
    14 | @forelse($articles as $article) 15 |
  • 16 | {{ $article->comments->count() }} 17 | {{ $article->title }} 18 |
  • 19 | @empty 20 |
  • {{ lang('Nothing') }}
  • 21 | @endforelse 22 |
23 |
24 |
25 |
26 | @endsection -------------------------------------------------------------------------------- /resources/views/dashboard/index.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | {{ config('app.name') }} Dashboard 12 | 13 | 14 | 15 | 16 | 17 | 20 | 21 | 34 | 35 | 36 |
37 | 38 | 39 | 40 | @if(config('blog.google.open')) 41 | 50 | @endif 51 | 52 | 53 | -------------------------------------------------------------------------------- /resources/views/errors/403.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 403 Forbidden. 5 | 6 | 7 | 8 | 39 | 40 | 41 |
42 |
43 |
403 Forbidden.
44 |
45 |
46 | 47 | 48 | -------------------------------------------------------------------------------- /resources/views/errors/404.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 404 Not Found. 5 | 6 | 7 | 8 | 39 | 40 | 41 |
42 |
43 |
404 Not Found.
44 |
45 |
46 | 47 | 48 | -------------------------------------------------------------------------------- /resources/views/errors/503.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Be right back. 5 | 6 | 7 | 8 | 39 | 40 | 41 |
42 |
43 |
Be right back.
44 |
45 |
46 | 47 | 48 | -------------------------------------------------------------------------------- /resources/views/link/index.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.app') 2 | 3 | @section('content') 4 | @component('particals.jumbotron') 5 |

{{ lang('Links') }}

6 | @endcomponent 7 | 8 |
9 |
10 |
11 | 18 |
19 |
20 |
21 | @endsection 22 | -------------------------------------------------------------------------------- /resources/views/mail/followed/user.blade.php: -------------------------------------------------------------------------------- 1 | @component('mail::message') 2 | **{{ lang('Dear') }} {{ $username }}:** 3 | 4 | {{ $message }} 5 | 6 | {{ lang('View') }} 7 | 8 | Thanks,
9 | {{ config('app.name') }} 10 | @endcomponent 11 | -------------------------------------------------------------------------------- /resources/views/mail/mention/user.blade.php: -------------------------------------------------------------------------------- 1 | @component('mail::message') 2 | **{{ lang('Dear') }} {{ $username }}:** 3 | 4 | {{ $message }} 5 | 6 | {{ $content }} 7 | 8 | @component('mail::button', ['url' => $url]) 9 | {{ lang('View') }} 10 | @endcomponent 11 | 12 | Thanks,
13 | {{ config('app.name') }} 14 | @endcomponent 15 | -------------------------------------------------------------------------------- /resources/views/mail/receive/comment.blade.php: -------------------------------------------------------------------------------- 1 | @component('mail::message') 2 | **{{ lang('Dear') }} {{ $username }}:** 3 | 4 | {{ $message }} 5 | 6 | {{ $content }} 7 | 8 | @component('mail::button', ['url' => $url]) 9 | {{ lang('View') }} 10 | @endcomponent 11 | 12 | Thanks,
13 | {{ config('app.name') }} 14 | @endcomponent 15 | -------------------------------------------------------------------------------- /resources/views/notifications/followed-user.blade.php: -------------------------------------------------------------------------------- 1 | data['id']); 3 | ?> 4 | 5 |
  • 6 | @if ($user) 7 | {{ $user->name }} {{ lang('Followed') }} 8 | @else 9 | {{ lang('User') }} {{ lang('Deleted') }} 10 | @endif 11 |
  • 12 | -------------------------------------------------------------------------------- /resources/views/notifications/got-vote.blade.php: -------------------------------------------------------------------------------- 1 | data['comment_id']); 3 | $user = App\User::find($notification->data['issuer_id']); 4 | 5 | $commentable_id = $notification->data['commentable_id']; 6 | 7 | if ($comment && $comment->commentable) { 8 | switch($comment->commentable_type) { 9 | case 'articles': 10 | $article = App\Article::find($commentable_id); 11 | $url = url($article->slug); 12 | break; 13 | case 'discussions': 14 | $discussion = App\Discussion::find($commentable_id); 15 | $url = url('discussion', ['id' => $discussion->id]); 16 | break; 17 | } 18 | } 19 | 20 | if($notification->data['vote_type'] == 'up_vote') 21 | { 22 | $iconRead = 'fas fa-thumbs-up-alt'; 23 | $iconNotRead = 'fas fa-thumbs-up'; 24 | $action = lang('Likes'); // Likes your comment 25 | } 26 | else 27 | { 28 | $iconRead = 'fas fa-thumbs-down-alt'; 29 | $iconNotRead = 'fas fa-thumbs-down'; 30 | $action = lang('Dislikes'); // Dislikes your comment 31 | } 32 | 33 | ?> 34 |
  • 35 | @if ($comment && $comment->commentable && $user) 36 | 37 | {{ $user->name }} {{ $action }} 38 | {{ $comment->commentable->title }} 39 | @else 40 | {{ lang('Deleted') }} 41 | @endif 42 |
  • -------------------------------------------------------------------------------- /resources/views/notifications/mentioned-user.blade.php: -------------------------------------------------------------------------------- 1 | data['id']); 3 | $type = $notification->data['commentable_type'] === 'articles' ? lang('Article') : lang('Discussion'); 4 | $commentable_id = $notification->data['commentable_id']; 5 | 6 | if ($comment && $comment->commentable) { 7 | switch($comment->commentable_type) { 8 | case 'articles': 9 | $article = App\Article::find($commentable_id); 10 | $url = url($article->slug); 11 | break; 12 | case 'discussions': 13 | $discussion = App\Discussion::find($commentable_id); 14 | $url = url('discussion', ['id' => $discussion->id]); 15 | break; 16 | } 17 | } else { 18 | $message = lang('Be Banned Comment'); 19 | } 20 | 21 | ?> 22 | 23 |
  • 24 | @if ($comment && $comment->commentable) 25 | {{ $comment->user->name }} 26 | {{ lang('Mentioned') }} {{ lang('In') }} 27 | {{ $comment->commentable->title }} 28 | @elseif ($comment && !$comment->commentable) 29 | {{ strtolower($type) }} {{ $message }} 30 | @else 31 | {{ strtolower($type) }} {{ lang('Deleted') }} 32 | @endif 33 |
  • 34 | -------------------------------------------------------------------------------- /resources/views/notifications/received-comment.blade.php: -------------------------------------------------------------------------------- 1 | data['id']); 3 | $type = $notification->data['commentable_type'] === 'articles' ? lang('Articles') : lang('Discussions'); 4 | $commentable_id = $notification->data['commentable_id']; 5 | 6 | if ($comment && $comment->commentable) { 7 | switch($comment->commentable_type) { 8 | case 'articles': 9 | $article = App\Article::find($commentable_id); 10 | $url = url($article->slug); 11 | break; 12 | case 'discussions': 13 | $discussion = App\Discussion::find($commentable_id); 14 | $url = url('discussion', ['id' => $discussion->id]); 15 | break; 16 | } 17 | } else { 18 | $message = lang('Be Banned Comment'); 19 | } 20 | 21 | ?> 22 | 23 |
  • 24 | @if ($comment && $comment->commentable) 25 | 26 | {{ $comment->user->name }} 27 | {{ lang('Commented') }} {{ $type }} 28 | {{ $comment->commentable->title }} 29 | @elseif ($comment && !$comment->commentable) 30 | {{ strtolower($type) }} {{ $message }} 31 | @else 32 | {{ strtolower($type) }} {{ lang('Deleted') }} 33 | @endif 34 |
  • 35 | -------------------------------------------------------------------------------- /resources/views/particals/footer.blade.php: -------------------------------------------------------------------------------- 1 | 36 | -------------------------------------------------------------------------------- /resources/views/particals/jumbotron.blade.php: -------------------------------------------------------------------------------- 1 |
    2 |
    3 |
    4 |
    5 | {{ $slot }} 6 |
    7 |
    8 |
    9 |
    -------------------------------------------------------------------------------- /resources/views/search.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.app') 2 | 3 | @section('content') 4 | @component('particals.jumbotron') 5 |

    {{ request()->get('q') }}

    6 | 7 |
    what you want to search.
    8 | @endcomponent 9 | 10 | @include('widgets.article') 11 | 12 | @endsection -------------------------------------------------------------------------------- /resources/views/setting/binding.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.app') 2 | 3 | @section('content') 4 |
    5 |
    6 |
    7 | @include('setting.particals.sidebar') 8 |
    9 | 10 |
    11 |
    12 |
    {{ lang('Account Binding') }}
    13 | 14 |
    15 |
    16 |
    17 | 18 |
    19 | @if(!Auth::user()->github_id && config('services.github.client_id')) 20 | 21 | Github 22 | 23 | @else 24 | 27 | @endif 28 |
    29 |
    30 |
    31 |
    32 |
    33 |
    34 |
    35 |
    36 | @endsection -------------------------------------------------------------------------------- /resources/views/setting/particals/sidebar.blade.php: -------------------------------------------------------------------------------- 1 |
    2 |
    {{ lang('Settings') }}
    3 | 4 |
    5 | 6 | {{ lang('Account Setting') }} 7 | 8 | @if(config('blog.mail_notification')) 9 | 10 | {{ lang('Notification Setting') }} 11 | 12 | @endif 13 | 14 | {{ lang('Account Binding') }} 15 | 16 |
    17 |
    -------------------------------------------------------------------------------- /resources/views/tag/index.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.app') 2 | 3 | @section('content') 4 | @component('particals.jumbotron') 5 |

    {{ lang('Tags') }}

    6 | 7 |
    {{ lang('Tags Meta') }}
    8 | @endcomponent 9 | 10 |
    11 |
    12 | @forelse($tags as $tag) 13 |
    14 |
    15 |
    16 |
    {{ $tag->tag }}
    17 |
    18 |
    19 | {{ $tag->meta_description }} 20 |
    21 |
    22 |
    23 | @empty 24 |

    {{ lang('Nothing') }}

    25 | @endforelse 26 |
    27 |
    28 | @endsection 29 | -------------------------------------------------------------------------------- /resources/views/user/comments.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.app') 2 | 3 | @section('content') 4 | @include('user.particals.info') 5 | 6 |
    7 |
    8 |
    9 |
    10 |
    {{ lang('Your Comments') }} ( {{ $comments->count() }} )
    11 | 12 | @include('user.particals.comments') 13 | 14 |
    15 |
    16 |
    17 |
    18 | @endsection -------------------------------------------------------------------------------- /resources/views/user/discussions.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.app') 2 | 3 | @section('content') 4 | @include('user.particals.info') 5 | 6 |
    7 |
    8 |
    9 |
    10 |
    {{ lang('Your Discussions') }} ( {{ $discussions->count() }} )
    11 | 12 | @include('user.particals.discussions') 13 | 14 |
    15 |
    16 |
    17 |
    18 | @endsection -------------------------------------------------------------------------------- /resources/views/user/following.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.app') 2 | 3 | @section('content') 4 | @include('user.particals.info') 5 | 6 |
    7 |
    8 |
    9 |
    10 |
    {{ lang('Your Followings') }} ( {{ $followings->count() }} )
    11 | 27 |
    28 |
    29 |
    30 |
    31 | @endsection -------------------------------------------------------------------------------- /resources/views/user/index.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.app') 2 | 3 | @section('content') 4 | @include('user.particals.info') 5 |
    6 |
    7 |
    8 |
    9 |
    {{ lang('Recent Discussions') }}
    10 | 11 | @include('user.particals.discussions') 12 | 13 |
    14 |
    15 |
    16 |
    17 |
    {{ lang('Recent Comments') }}
    18 | 19 | @include('user.particals.comments') 20 | 21 |
    22 |
    23 |
    24 |
    25 | @endsection -------------------------------------------------------------------------------- /resources/views/user/notifications.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.app') 2 | 3 | @section('content') 4 |
    5 |
    6 |
    7 |
    8 |
    9 | 10 | {{ Auth::user()->unreadNotifications->count() }} 11 | {{ lang('New Notification') }} 12 | 13 | 15 | {{ lang('Mark As Read') }} 16 | 17 |
    18 | {{ csrf_field() }} 19 |
    20 |
    21 |
    22 |
      23 | @foreach(Auth::user()->notifications as $notification) 24 | @include('notifications.'. snake_case(class_basename($notification->type), '-')) 25 | @endforeach 26 |
    27 |
    28 |
    29 |
    30 |
    31 |
    32 | @endsection -------------------------------------------------------------------------------- /resources/views/user/particals/comments.blade.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/views/user/particals/discussions.blade.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/views/vendor/notifications/email-plain.blade.php: -------------------------------------------------------------------------------- 1 | id === (int) $id; 16 | }); -------------------------------------------------------------------------------- /routes/console.php: -------------------------------------------------------------------------------- 1 | comment(Inspiring::quote()); 18 | }); 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 -------------------------------------------------------------------------------- /storage/framework/cache/data/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /storage/framework/sessions/.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 | } -------------------------------------------------------------------------------- /tests/Feature/Api/ArticleApiTest.php: -------------------------------------------------------------------------------- 1 | actingAsAdmin()->get('api/article'); 13 | 14 | $response->assertStatus(200); 15 | $response->assertJsonStructure([ 16 | 'data' => ['*' => ['id', 'title', 'subtitle', 'user', 'slug', 'content', 'page_image', 'meta_description', 'is_original', 'is_draft', 'visitors', 'published_at', 'published_time']], 17 | 'meta' => ['pagination' => []], 18 | ]); 19 | } 20 | 21 | /** @test */ 22 | public function it_shows_a_article() 23 | { 24 | $article = factory(\App\Article::class, 1)->create()->first(); 25 | $response = $this->actingAsAdmin()->get(route('api.article.edit', $article->id)); 26 | 27 | $response->assertStatus(200); 28 | } 29 | 30 | /** @test */ 31 | public function it_store_a_article() 32 | { 33 | $article = factory(\App\Article::class)->make(); 34 | 35 | $data = array_merge($article->toArray(), [ 'tags' => '[1, 2]' ]); 36 | 37 | $response = $this->actingAsAdmin()->post(route('api.article.store', $data)); 38 | 39 | $response->assertStatus(204); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /tests/Feature/Api/UserApiTest.php: -------------------------------------------------------------------------------- 1 | actingAsAdmin(); 13 | $response = $this->get('/api/user'); 14 | 15 | $response->assertStatus(200); 16 | $response->assertJsonStructure([ 17 | 'data' => ['*' => ['id', 'name', 'avatar', 'status', 'email', 'nickname', 'is_admin', 'github_name', 'website', 'description', 'created_at']], 18 | 'meta' => ['pagination' => []], 19 | ]); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /tests/Feature/ExampleTest.php: -------------------------------------------------------------------------------- 1 | get('/'); 18 | 19 | $response->assertStatus(200); 20 | } 21 | } -------------------------------------------------------------------------------- /tests/TestCase.php: -------------------------------------------------------------------------------- 1 | create(), 17 | ['user', 'article'] 18 | ); 19 | 20 | return $this; 21 | } 22 | } -------------------------------------------------------------------------------- /tests/Unit/ExampleTest.php: -------------------------------------------------------------------------------- 1 | assertTrue(true); 17 | } 18 | } --------------------------------------------------------------------------------