From 58152e6982c33edf4aed09cfd9bc4b9538ce766f Mon Sep 17 00:00:00 2001 From: Monish Khatri Date: Thu, 29 Dec 2022 12:22:58 +0530 Subject: [PATCH] Attach Security Headers to Laravel Application --- .gitignore | 1 + INSTALLATION.md | 28 +- README.md | 25 +- composer.json | 30 +- composer.lock | 20 + src/BlogServiceProvider.php | 74 - src/Builders/Builder.php | 30 + src/Builders/ClearSiteDataBuilder.php | 38 + src/Builders/ContentSecurityPolicyBuilder.php | 382 ++++ .../ExpectCertificateTransparencyBuilder.php | 65 + src/Builders/PermissionsPolicyBuilder.php | 76 + .../StrictTransportSecurityBuilder.php | 42 + src/Console/InstallCommand.php | 67 +- src/Console/InstallSecurityHeadersStack.php | 24 + src/Console/InstallsBladeStack.php | 93 - src/SecureHeaders.php | 275 +++ src/SecurityHeadersServiceProvider.php | 40 + stubs/Events/BlogApprovedRejected.php | 37 - stubs/Http/Controllers/BlogController.php | 444 ----- stubs/Http/Controllers/CommentController.php | 82 - stubs/Http/Controllers/TagController.php | 38 - ...uage.php => SecurityHeadersMiddleware.php} | 15 +- stubs/Http/Requests/StoreBlogRequest.php | 54 - stubs/Http/Resources/BlogCollection.php | 25 - stubs/Http/Resources/BlogResource.php | 28 - stubs/Jobs/SendEmailJob.php | 45 - stubs/Listeners/NotifyUserWithBlogStatus.php | 41 - stubs/Mail/SendMailable.php | 40 - stubs/Models/Blog.php | 109 - stubs/Models/Comment.php | 51 - stubs/Models/Tag.php | 25 - stubs/Notifications/BlogPublishRequest.php | 62 - stubs/Policies/BlogPolicy.php | 95 - stubs/View/Components/AlertMessage.php | 50 - stubs/config/blog-application.php | 7 - stubs/config/security-headers.php | 693 +++++++ stubs/database/.gitignore | 1 - .../2022_07_13_054933_create_blogs_table.php | 42 - ...ter_user_table_add_blog_related_column.php | 34 - ..._26_090330_create_blogs_comments_table.php | 36 - .../2022_08_11_124913_create_tags_table.php | 32 - ...022_08_11_125433_create_blog_tag_table.php | 32 - stubs/database/seeders/BlogSeeder.php | 22 - stubs/database/seeders/TagSeeder.php | 28 - stubs/lang/en/blog.php | 73 - stubs/lang/en/comment.php | 18 - stubs/lang/en/validation.php | 170 -- stubs/lang/fr/blog.php | 73 - stubs/lang/fr/comment.php | 18 - stubs/lang/fr/validation.php | 169 -- stubs/lang/hi/blog.php | 73 - stubs/lang/hi/comment.php | 18 - stubs/lang/hi/validation.php | 168 -- stubs/resources/css/app.css | 1758 ----------------- stubs/resources/views/blog/add.blade.php | 74 - .../views/blog/commentsDisplay.blade.php | 47 - stubs/resources/views/blog/edit.blade.php | 76 - stubs/resources/views/blog/index.blade.php | 283 --- stubs/resources/views/blog/tags.blade.php | 18 - .../resources/views/blog/trash_bin.blade.php | 141 -- stubs/resources/views/blog/view.blade.php | 132 -- .../components/application-logo.blade.php | 1 - stubs/resources/views/dashboard.blade.php | 20 - .../views/emails/blog_action.blade.php | 15 - .../views/emails/comment_action.blade.php | 17 - stubs/resources/views/layouts/app.blade.php | 43 - .../resources/views/layouts/footer.blade.php | 28 - stubs/resources/views/layouts/guest.blade.php | 21 - .../views/layouts/navigation.blade.php | 125 -- stubs/routes/web.php | 68 - 70 files changed, 1746 insertions(+), 5379 deletions(-) create mode 100644 .gitignore create mode 100644 composer.lock delete mode 100644 src/BlogServiceProvider.php create mode 100644 src/Builders/Builder.php create mode 100644 src/Builders/ClearSiteDataBuilder.php create mode 100644 src/Builders/ContentSecurityPolicyBuilder.php create mode 100644 src/Builders/ExpectCertificateTransparencyBuilder.php create mode 100644 src/Builders/PermissionsPolicyBuilder.php create mode 100644 src/Builders/StrictTransportSecurityBuilder.php create mode 100644 src/Console/InstallSecurityHeadersStack.php delete mode 100644 src/Console/InstallsBladeStack.php create mode 100755 src/SecureHeaders.php create mode 100644 src/SecurityHeadersServiceProvider.php delete mode 100755 stubs/Events/BlogApprovedRejected.php delete mode 100755 stubs/Http/Controllers/BlogController.php delete mode 100755 stubs/Http/Controllers/CommentController.php delete mode 100755 stubs/Http/Controllers/TagController.php rename stubs/Http/Middleware/{ChangeSiteLanguage.php => SecurityHeadersMiddleware.php} (58%) delete mode 100755 stubs/Http/Requests/StoreBlogRequest.php delete mode 100755 stubs/Http/Resources/BlogCollection.php delete mode 100755 stubs/Http/Resources/BlogResource.php delete mode 100755 stubs/Jobs/SendEmailJob.php delete mode 100755 stubs/Listeners/NotifyUserWithBlogStatus.php delete mode 100755 stubs/Mail/SendMailable.php delete mode 100755 stubs/Models/Blog.php delete mode 100755 stubs/Models/Comment.php delete mode 100755 stubs/Models/Tag.php delete mode 100755 stubs/Notifications/BlogPublishRequest.php delete mode 100755 stubs/Policies/BlogPolicy.php delete mode 100755 stubs/View/Components/AlertMessage.php delete mode 100644 stubs/config/blog-application.php create mode 100644 stubs/config/security-headers.php delete mode 100755 stubs/database/.gitignore delete mode 100755 stubs/database/migrations/2022_07_13_054933_create_blogs_table.php delete mode 100755 stubs/database/migrations/2022_07_20_102233_alter_user_table_add_blog_related_column.php delete mode 100755 stubs/database/migrations/2022_07_26_090330_create_blogs_comments_table.php delete mode 100755 stubs/database/migrations/2022_08_11_124913_create_tags_table.php delete mode 100755 stubs/database/migrations/2022_08_11_125433_create_blog_tag_table.php delete mode 100644 stubs/database/seeders/BlogSeeder.php delete mode 100755 stubs/database/seeders/TagSeeder.php delete mode 100755 stubs/lang/en/blog.php delete mode 100755 stubs/lang/en/comment.php delete mode 100644 stubs/lang/en/validation.php delete mode 100755 stubs/lang/fr/blog.php delete mode 100755 stubs/lang/fr/comment.php delete mode 100644 stubs/lang/fr/validation.php delete mode 100755 stubs/lang/hi/blog.php delete mode 100755 stubs/lang/hi/comment.php delete mode 100755 stubs/lang/hi/validation.php delete mode 100755 stubs/resources/css/app.css delete mode 100755 stubs/resources/views/blog/add.blade.php delete mode 100755 stubs/resources/views/blog/commentsDisplay.blade.php delete mode 100755 stubs/resources/views/blog/edit.blade.php delete mode 100755 stubs/resources/views/blog/index.blade.php delete mode 100755 stubs/resources/views/blog/tags.blade.php delete mode 100755 stubs/resources/views/blog/trash_bin.blade.php delete mode 100755 stubs/resources/views/blog/view.blade.php delete mode 100644 stubs/resources/views/components/application-logo.blade.php delete mode 100644 stubs/resources/views/dashboard.blade.php delete mode 100755 stubs/resources/views/emails/blog_action.blade.php delete mode 100755 stubs/resources/views/emails/comment_action.blade.php delete mode 100644 stubs/resources/views/layouts/app.blade.php delete mode 100644 stubs/resources/views/layouts/footer.blade.php delete mode 100644 stubs/resources/views/layouts/guest.blade.php delete mode 100644 stubs/resources/views/layouts/navigation.blade.php delete mode 100644 stubs/routes/web.php diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a725465 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +vendor/ \ No newline at end of file diff --git a/INSTALLATION.md b/INSTALLATION.md index d30fcd4..d736b95 100644 --- a/INSTALLATION.md +++ b/INSTALLATION.md @@ -1,25 +1,23 @@ -## [Blog Application Installation Guide](https://packagist.org/packages/monish-khatri/blog-application) +## [Laravel Security Headers Installation Guide](https://packagist.org/packages/monish-khatri/security-headers)

- - Total Downloads + + Total Downloads - - Latest Stable Version + + Latest Stable Version - - License + + License - - License + + License

-### Follow the below steps to install blog application +### Follow the below steps to install security header package - Install the package using - - `composer require monish-khatri/blog-application` + - `composer require monish-khatri/security-headers` - Run below command to publish package classes - - `php artisan blog:install` -- Finally, Run the migrations to create package tables - - `php artisan migrate` + - `php artisan security-headers:install` - You can publish the package config file & change site logo and favicon with email preference - - `php artisan vendor:publish --provider="MonishKhatri\Blog\BlogServiceProvider" --tag="config"` + - `php artisan vendor:publish --provider="MonishKhatri\SecurityHeaders\SecurityHeadersServiceProvider" --tag="config"` diff --git a/README.md b/README.md index af8d525..5aa0440 100644 --- a/README.md +++ b/README.md @@ -1,23 +1,24 @@

Laravel 9

- - Total Downloads + + Total Downloads - - Latest Stable Version + + Latest Stable Version - - License + + License - - License + + License

## Introduction -Blog Application provides a minimal and simple starting point for building a Laravel application . Styled with Tailwind, Blog Application publishes Blog,Comment,Tag controllers,views,requests & many more things to your application that can be easily customized based on your own application's needs. +Package provides a minimal and simple integration to attach security headers for building a secure Laravel application. +This package publishes config file to your application that can be easily customized based on your own application's needs. ## Code of Conduct @@ -26,12 +27,12 @@ In order to ensure that the Laravel community is welcoming to all, please review ## Installation guide -You can setup the Blog Application by following given steps in [Installation guide](INSTALLATION.md). +You can setup the Security Headers by following given steps in [Installation guide](INSTALLATION.md). ## Contributing Pull requests and feedback are very welcome :) -on GitHub at https://github.com/monish-khatri/laravel-blog-application +on GitHub at https://github.com/monish-khatri/security-headers ## License -Laravel Blog Application is open-sourced software licensed under the [MIT license](LICENSE.md). +Laravel Security Headers is open-sourced software licensed under the [MIT license](LICENSE.md). diff --git a/composer.json b/composer.json index a636b35..23aeeda 100644 --- a/composer.json +++ b/composer.json @@ -1,11 +1,23 @@ { - "name": "monish-khatri/blog-application", - "description": "Blog Application using Laravel 9", + "name": "monish-khatri/security-headers", + "description": "Attach OWASP security related headers to HTTP response.", "type": "library", "license": "MIT", + "keywords": [ + "laravel", + "header", + "https", + "hsts", + "csp", + "except-ct", + "feature-policy", + "clear-site-data", + "referrer-policy", + "content-security-policy" + ], "autoload": { "psr-4": { - "MonishKhatri\\Blog\\": "src/" + "MonishKhatri\\SecurityHeaders\\": "src/" } }, "authors": [ @@ -16,19 +28,13 @@ ], "minimum-stability": "dev", "require": { - "php": "^8.0.2", - "kyslik/column-sortable": "^6.4", - "laravel/breeze": "^1.13", - "laravel/ui": "^4.1" + "php": "^8.0.2" }, "extra": { "laravel": { "providers": [ - "MonishKhatri\\Blog\\BlogServiceProvider" - ], - "aliases": { - "Blog": "App\\Models\\Blog" - } + "MonishKhatri\\SecurityHeaders\\SecurityHeadersServiceProvider" + ] } } } diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000..16c1a1e --- /dev/null +++ b/composer.lock @@ -0,0 +1,20 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "3bf60fff3e5e0e11b33948ac3c66fe6a", + "packages": [], + "packages-dev": [], + "aliases": [], + "minimum-stability": "dev", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": "^8.0.2" + }, + "platform-dev": [], + "plugin-api-version": "2.3.0" +} diff --git a/src/BlogServiceProvider.php b/src/BlogServiceProvider.php deleted file mode 100644 index c2eb53c..0000000 --- a/src/BlogServiceProvider.php +++ /dev/null @@ -1,74 +0,0 @@ - BlogPolicy::class, - ]; - - protected $defer = false; - - /** - * Register any application services. - * - * @return void - */ - public function register() - { - // - } - - /** - * Bootstrap any application services. - * - * @return void - */ - public function boot(Kernel $kernel) - { - $this->loadRoutesFrom(__DIR__ . '/../stubs/routes/web.php'); - $this->loadMigrationsFrom(__DIR__ . '/../stubs/database/migrations'); - - // Merge and publish config file - $this->mergeConfigFrom(__DIR__ . '/../stubs/config/blog-application.php', 'blog-application'); - $this->publishes([ - __DIR__ . '/../stubs/config/blog-application.php' => config_path('blog-application.php'), - ], 'config'); - - $router = $this->app->make(Router::class); - $router->aliasMiddleware('change_site_language', ChangeSiteLanguage::class); - $this->commands([ - Console\InstallCommand::class, - ]); - $this->registerPolicies(); - - Gate::define('isOwner', function (User $user, Blog $blog) { - return $user->id === $blog->user_id; - }); - - /* define a admin user role */ - Gate::define('isAdmin', function ($user) { - return $user->role == 'admin'; - }); - - /* define a user role */ - Gate::define('isUser', function ($user) { - return $user->role == 'user'; - }); - } -} diff --git a/src/Builders/Builder.php b/src/Builders/Builder.php new file mode 100644 index 0000000..4d8e293 --- /dev/null +++ b/src/Builders/Builder.php @@ -0,0 +1,30 @@ + + */ + protected $config = []; + + /** + * Builder constructor. + * + * @param array $config + */ + public function __construct(array $config = []) + { + $this->config = $config; + } + + /** + * Get result. + * + * @return string + */ + abstract public function get(): string; +} diff --git a/src/Builders/ClearSiteDataBuilder.php b/src/Builders/ClearSiteDataBuilder.php new file mode 100644 index 0000000..f6dd6ed --- /dev/null +++ b/src/Builders/ClearSiteDataBuilder.php @@ -0,0 +1,38 @@ + + */ + protected $whitelist = [ + 'cache' => true, + 'cookies' => true, + 'storage' => true, + 'executionContexts' => true, + ]; + + /** + * {@inheritDoc} + */ + public function get(): string + { + if ($this->config['all'] ?? false) { + return '"*"'; + } + + $targets = array_intersect_key($this->config, $this->whitelist); + + $needs = array_filter($targets); + + $directives = array_map(function (string $directive) { + return sprintf('"%s"', $directive); + }, array_keys($needs)); + + return implode(', ', $directives); + } +} diff --git a/src/Builders/ContentSecurityPolicyBuilder.php b/src/Builders/ContentSecurityPolicyBuilder.php new file mode 100644 index 0000000..cadf172 --- /dev/null +++ b/src/Builders/ContentSecurityPolicyBuilder.php @@ -0,0 +1,382 @@ + + */ + protected $whitelist = [ + 'base-uri' => true, + 'child-src' => true, + 'connect-src' => true, + 'default-src' => true, + 'font-src' => true, + 'form-action' => true, + 'frame-ancestors' => true, + 'frame-src' => true, + 'img-src' => true, + 'manifest-src' => true, + 'media-src' => true, + 'navigate-to' => true, + 'object-src' => true, + 'prefetch-src' => true, + 'script-src' => true, + 'script-src-attr' => true, + 'script-src-elem' => true, + 'style-src' => true, + 'style-src-attr' => true, + 'style-src-elem' => true, + 'worker-src' => true, + ]; + + /** + * {@inheritDoc} + */ + public function get(): string + { + $builds = [ + $this->directives(), + $this->pluginTypes(), + $this->sandbox(), + $this->requireTrustedTypesFor(), + $this->trustedTypes(), + $this->blockAllMixedContent(), + $this->upgradeInsecureRequests(), + $this->reportTo(), + $this->reportUri(), + ]; + + return $this->implode(array_filter($builds), '; '); + } + + /** + * Build directives. + * + * @return string + */ + protected function directives(): string + { + $result = []; + + foreach ($this->config as $name => $config) { + if (!($this->whitelist[$name] ?? false)) { + continue; + } + + if (empty($val = $this->directive($config))) { + continue; + } + + $result[] = sprintf('%s %s', $name, $val); + } + + return $this->implode($result, '; '); + } + + /** + * Build directive. + * + * @param array $config + * @return string + */ + protected function directive(array $config): string + { + if ($config['none'] ?? false) { + return "'none'"; + } + + $sources = array_merge( + $this->keywords($config), + $this->schemes($config['schemes'] ?? []), + $this->hashes($config['hashes'] ?? []), + $this->nonces($config['nonces'] ?? []), + $config['allow'] ?? [] + ); + + $filtered = array_filter($sources); + + return $this->implode($filtered); + } + + /** + * Build directive keywords. + * + * @param array $config + * @return array + */ + protected function keywords(array $config): array + { + $whitelist = [ + 'self' => true, + 'unsafe-inline' => true, + 'unsafe-eval' => true, + 'unsafe-hashes' => true, + 'strict-dynamic' => true, + 'report-sample' => true, + 'unsafe-allow-redirects' => true, + ]; + + $passes = $this->filter($config, $whitelist); + + return array_map(function (string $keyword) { + return sprintf("'%s'", $keyword); + }, $passes); + } + + /** + * Build directive schemes. + * + * @param array $schemes + * @return array + */ + protected function schemes(array $schemes): array + { + return array_map(function (string $scheme) { + $trimmed = trim($scheme); + + if (substr($trimmed, -1) === ':') { + return $trimmed; + } + + return sprintf('%s:', $trimmed); + }, $schemes); + } + + /** + * Build directive nonces. + * + * @param array $nonces + * @return array + */ + protected function nonces(array $nonces): array + { + return array_map(function (string $nonce) { + $trimmed = trim($nonce); + + if (base64_decode($trimmed, true) === false) { + return ''; + } + + return sprintf("'nonce-%s'", $trimmed); + }, $nonces); + } + + /** + * Build directive hashes. + * + * @param array> $groups + * @return array + */ + protected function hashes(array $groups): array + { + $result = []; + + foreach ($groups as $hash => $items) { + if (!in_array($hash, ['sha256', 'sha384', 'sha512'], true)) { + continue; + } + + foreach ($items as $item) { + $trimmed = trim($item); + + if (base64_decode($trimmed, true) === false) { + continue; + } + + $result[] = sprintf("'%s-%s'", $hash, $trimmed); + } + } + + return $result; + } + + /** + * Build plugin-types directive. + * + * @return string + */ + protected function pluginTypes(): string + { + $pluginTypes = $this->config['plugin-types'] ?? []; + + $passes = array_filter($pluginTypes, function (string $mime) { + return preg_match('/^[a-z\-]+\/[a-z\-]+$/i', $mime); + }); + + if (!empty($passes)) { + array_unshift($passes, 'plugin-types'); + } + + return $this->implode($passes); + } + + /** + * Build sandbox directive. + * + * @return string + */ + protected function sandbox(): string + { + $sandbox = $this->config['sandbox'] ?? []; + + if (!($sandbox['enable'] ?? false)) { + return ''; + } + + $whitelist = [ + 'allow-downloads-without-user-activation' => true, + 'allow-forms' => true, + 'allow-modals' => true, + 'allow-orientation-lock' => true, + 'allow-pointer-lock' => true, + 'allow-popups' => true, + 'allow-popups-to-escape-sandbox' => true, + 'allow-presentation' => true, + 'allow-same-origin' => true, + 'allow-scripts' => true, + 'allow-storage-access-by-user-activation' => true, + 'allow-top-navigation' => true, + 'allow-top-navigation-by-user-activation' => true, + ]; + + $passes = $this->filter($sandbox, $whitelist); + + array_unshift($passes, 'sandbox'); + + return $this->implode($passes); + } + + /** + * Build require-trusted-types-for directive. + * + * @return string + */ + protected function requireTrustedTypesFor(): string + { + $config = $this->config['require-trusted-types-for'] ?? []; + + if (!($config['script'] ?? false)) { + return ''; + } + + return "require-trusted-types-for 'script'"; + } + + /** + * Build trusted-types directive. + * + * @return string + */ + protected function trustedTypes(): string + { + $trustedTypes = $this->config['trusted-types'] ?? []; + + if (!($trustedTypes['enable'] ?? false)) { + return ''; + } + + $policies = array_map('trim', $trustedTypes['policies'] ?? []); + + if ($trustedTypes['default'] ?? false) { + $policies[] = 'default'; + } + + if ($trustedTypes['allow-duplicates'] ?? false) { + $policies[] = "'allow-duplicates'"; + } + + array_unshift($policies, 'trusted-types'); + + return $this->implode($policies); + } + + /** + * Build block-all-mixed-content directive. + * + * @return string + */ + protected function blockAllMixedContent(): string + { + if (!($this->config['block-all-mixed-content'] ?? false)) { + return ''; + } + + return 'block-all-mixed-content'; + } + + /** + * Build upgrade-insecure-requests directive. + * + * @return string + */ + protected function upgradeInsecureRequests(): string + { + if (!($this->config['upgrade-insecure-requests'] ?? false)) { + return ''; + } + + return 'upgrade-insecure-requests'; + } + + /** + * Build report-to directive. + * + * @return string + */ + protected function reportTo(): string + { + if (empty($this->config['report-to'])) { + return ''; + } + + return sprintf('report-to %s', $this->config['report-to']); + } + + /** + * Build report-uri directive. + * + * @return string + */ + protected function reportUri(): string + { + if (empty($this->config['report-uri'])) { + return ''; + } + + $uri = $this->implode($this->config['report-uri']); + + return sprintf('report-uri %s', $uri); + } + + /** + * Using key to filter config and return keys. + * + * @param array $config + * @param array $available + * @return array + */ + protected function filter(array $config, array $available): array + { + $targets = array_intersect_key($config, $available); + + $needs = array_filter($targets); + + return array_keys($needs); + } + + /** + * Implode strings using glue. + * + * @param array $payload + * @param string $glue + * @return string + */ + protected function implode(array $payload, string $glue = ' '): string + { + return implode($glue, $payload); + } +} diff --git a/src/Builders/ExpectCertificateTransparencyBuilder.php b/src/Builders/ExpectCertificateTransparencyBuilder.php new file mode 100644 index 0000000..1049edb --- /dev/null +++ b/src/Builders/ExpectCertificateTransparencyBuilder.php @@ -0,0 +1,65 @@ +maxAge(); + + if ($this->config['enforce'] ?? false) { + $directives[] = 'enforce'; + } + + if (!empty($this->config['report-uri'])) { + $directives[] = $this->reportUri(); + } + + return implode(', ', array_filter($directives)); + } + + /** + * Get max-age directive. + * + * @return string + */ + protected function maxAge(): string + { + $origin = $this->config['max-age'] ?? $this->max; + + // convert to int + $age = intval($origin); + + // prevent negative value + $val = max($age, 0); + + return sprintf('max-age=%d', $val); + } + + /** + * Get report-uri directive. + * + * @return string + */ + protected function reportUri(): string + { + $uri = filter_var($this->config['report-uri'], FILTER_VALIDATE_URL); + + if ($uri === false) { + return ''; + } + + return sprintf('report-uri="%s"', $uri); + } +} diff --git a/src/Builders/PermissionsPolicyBuilder.php b/src/Builders/PermissionsPolicyBuilder.php new file mode 100644 index 0000000..fa79927 --- /dev/null +++ b/src/Builders/PermissionsPolicyBuilder.php @@ -0,0 +1,76 @@ +config as $name => $config) { + if ($name === 'enable') { + continue; + } + + if (empty($val = $this->directive($config))) { + continue; + } + + $result[] = sprintf('%s=%s', $name, $val); + } + + return implode(', ', $result); + } + + /** + * Parse specific policy value. + * + * @param array $config + * @return string + */ + protected function directive(array $config): string + { + if ($config['none'] ?? false) { + return '()'; + } elseif ($config['*'] ?? false) { + return '*'; + } + + $origins = $this->origins($config['origins'] ?? []); + + if ($config['self'] ?? false) { + array_unshift($origins, 'self'); + } + + return sprintf('(%s)', implode(' ', $origins)); + } + + /** + * Get valid origins. + * + * @param array $origins + * @return array + */ + protected function origins(array $origins): array + { + // prevent user leave spaces by mistake + $trimmed = array_map('trim', $origins); + + // filter array using FILTER_VALIDATE_URL + $filters = filter_var_array($trimmed, FILTER_VALIDATE_URL); + + // get valid value + $passes = array_filter($filters); + + // ensure indexes are numerically + $urls = array_values($passes); + + return array_map(function (string $url) { + return sprintf('"%s"', $url); + }, $urls); + } +} diff --git a/src/Builders/StrictTransportSecurityBuilder.php b/src/Builders/StrictTransportSecurityBuilder.php new file mode 100644 index 0000000..abc529a --- /dev/null +++ b/src/Builders/StrictTransportSecurityBuilder.php @@ -0,0 +1,42 @@ +maxAge(); + + if ($this->config['include-sub-domains'] ?? false) { + $directives[] = 'includeSubDomains'; + } + + if ($this->config['preload'] ?? false) { + $directives[] = 'preload'; + } + + return implode('; ', $directives); + } + + /** + * Get max-age directive. + * + * @return string + */ + protected function maxAge(): string + { + $origin = $this->config['max-age'] ?? 31536000; + + // convert to int + $age = intval($origin); + + // prevent negative value + $val = max($age, 0); + + return sprintf('max-age=%d', $val); + } +} diff --git a/src/Console/InstallCommand.php b/src/Console/InstallCommand.php index a7ac6ae..a8b0f6d 100644 --- a/src/Console/InstallCommand.php +++ b/src/Console/InstallCommand.php @@ -1,29 +1,27 @@ installBladeStack(); - } - - /** - * Install the middleware to a group in the application Http Kernel. - * - * @param string $after - * @param string $name - * @param string $group - * @return void - */ - protected function installMiddlewareAfter($after, $name, $group = 'web') - { - $httpKernel = file_get_contents(app_path('Http/Kernel.php')); - - $middlewareGroups = Str::before(Str::after($httpKernel, '$middlewareGroups = ['), '];'); - $middlewareGroup = Str::before(Str::after($middlewareGroups, "'$group' => ["), '],'); - - if (! Str::contains($middlewareGroup, $name)) { - $modifiedMiddlewareGroup = str_replace( - $after.',', - $after.','.PHP_EOL.' '.$name.',', - $middlewareGroup, - ); - - file_put_contents(app_path('Http/Kernel.php'), str_replace( - $middlewareGroups, - str_replace($middlewareGroup, $modifiedMiddlewareGroup, $middlewareGroups), - $httpKernel - )); - } - } - - /** - * Run the given commands. - * - * @param array $commands - * @return void - */ - protected function runCommands($commands) - { - $process = Process::fromShellCommandline(implode(' && ', $commands), null, null, null, null); - - if ('\\' !== DIRECTORY_SEPARATOR && file_exists('/dev/tty') && is_readable('/dev/tty')) { - try { - $process->setTty(true); - } catch (RuntimeException $e) { - $this->output->writeln(' WARN '.$e->getMessage().PHP_EOL); - } - } - - $process->run(function ($type, $line) { - $this->output->write(' '.$line); - }); + return $this->installSecurityHeadersStack(); } } diff --git a/src/Console/InstallSecurityHeadersStack.php b/src/Console/InstallSecurityHeadersStack.php new file mode 100644 index 0000000..344c8ae --- /dev/null +++ b/src/Console/InstallSecurityHeadersStack.php @@ -0,0 +1,24 @@ +ensureDirectoryExists(app_path('Http/Middleware')); + (new Filesystem)->copyDirectory(__DIR__.'/../../stubs/Http/Middleware', app_path('Http/Middleware')); + + + $this->line(''); + $this->components->info('Security Headers scaffolding installed successfully.'); + } +} diff --git a/src/Console/InstallsBladeStack.php b/src/Console/InstallsBladeStack.php deleted file mode 100644 index 489a43e..0000000 --- a/src/Console/InstallsBladeStack.php +++ /dev/null @@ -1,93 +0,0 @@ -runCommands(['php artisan breeze:install']); - - // Controllers... - (new Filesystem)->ensureDirectoryExists(app_path('Http/Controllers')); - (new Filesystem)->copyDirectory(__DIR__.'/../../stubs/Http/Controllers', app_path('Http/Controllers')); - - // Middleware... - (new Filesystem)->ensureDirectoryExists(app_path('Http/Middleware')); - (new Filesystem)->copyDirectory(__DIR__.'/../../stubs/Http/Middleware', app_path('Http/Middleware')); - - // Requests... - (new Filesystem)->ensureDirectoryExists(app_path('Http/Requests')); - (new Filesystem)->copyDirectory(__DIR__.'/../../stubs/Http/Requests', app_path('Http/Requests')); - - // Resources... - (new Filesystem)->ensureDirectoryExists(app_path('Http/Resources')); - (new Filesystem)->copyDirectory(__DIR__.'/../../stubs/Http/Resources', app_path('Http/Resources')); - - // Events... - (new Filesystem)->ensureDirectoryExists(app_path('Events')); - (new Filesystem)->copyDirectory(__DIR__.'/../../stubs/Events', app_path('Events')); - - // Jobs... - (new Filesystem)->ensureDirectoryExists(app_path('Jobs')); - (new Filesystem)->copyDirectory(__DIR__.'/../../stubs/Jobs', app_path('Jobs')); - - // Listeners... - (new Filesystem)->ensureDirectoryExists(app_path('Listeners')); - (new Filesystem)->copyDirectory(__DIR__.'/../../stubs/Listeners', app_path('Listeners')); - - // Mail... - (new Filesystem)->ensureDirectoryExists(app_path('Mail')); - (new Filesystem)->copyDirectory(__DIR__.'/../../stubs/Mail', app_path('Mail')); - - // Models... - (new Filesystem)->ensureDirectoryExists(app_path('Models')); - (new Filesystem)->copyDirectory(__DIR__.'/../../stubs/Models', app_path('Models')); - - // Notifications... - (new Filesystem)->ensureDirectoryExists(app_path('Notifications')); - (new Filesystem)->copyDirectory(__DIR__.'/../../stubs/Notifications', app_path('Notifications')); - - // Policies... - (new Filesystem)->ensureDirectoryExists(app_path('Policies')); - (new Filesystem)->copyDirectory(__DIR__.'/../../stubs/Policies', app_path('Policies')); - - // Langs... - (new Filesystem)->ensureDirectoryExists(\App::langPath()); - (new Filesystem)->copyDirectory(__DIR__.'/../../stubs/lang', \App::langPath()); - - // migrations... - (new Filesystem)->ensureDirectoryExists(database_path('migrations')); - (new Filesystem)->copyDirectory(__DIR__.'/../../stubs/database/migrations', database_path('migrations')); - // seeders... - (new Filesystem)->ensureDirectoryExists(database_path('seeders')); - (new Filesystem)->copyDirectory(__DIR__.'/../../stubs/database/seeders', database_path('seeders')); - - // Views... - (new Filesystem)->ensureDirectoryExists(resource_path('views')); - (new Filesystem)->copyDirectory(__DIR__.'/../../stubs/resources/views', resource_path('views')); - - // Css... - (new Filesystem)->ensureDirectoryExists(resource_path('css')); - (new Filesystem)->copyDirectory(__DIR__.'/../../stubs/resources/css', resource_path('css')); - - // Components... - (new Filesystem)->ensureDirectoryExists(app_path('View/Components')); - (new Filesystem)->copyDirectory(__DIR__.'/../../stubs/View/Components', app_path('View/Components')); - - // Routes... - (new Filesystem)->ensureDirectoryExists(base_path('routes')); - (new Filesystem)->copyDirectory(__DIR__.'/../../stubs/routes', base_path('routes')); - - $this->line(''); - $this->components->info('Blog scaffolding installed successfully.'); - } -} diff --git a/src/SecureHeaders.php b/src/SecureHeaders.php new file mode 100755 index 0000000..3a48b0a --- /dev/null +++ b/src/SecureHeaders.php @@ -0,0 +1,275 @@ + + */ + protected $config = []; + + /** + * Determate header had sent or not. + * + * @var bool + */ + protected $sent = false; + + /** + * Nonces for `script-src` and `style-src`. + * + * @var array> + */ + protected static $nonces = [ + 'script' => [], + + 'style' => [], + ]; + + /** + * Constructor. + * + * @param array $config + */ + public function __construct(array $config = []) + { + $this->config = $config; + } + + /** + * Destructor. + */ + public function __destruct() + { + if ($this->sent) { + self::removeNonce(); + } + } + + /** + * Load data from file. + * + * @param string $file + * @return SecureHeaders + */ + public static function fromFile($file) + { + if (!is_file($file)) { + throw new InvalidArgumentException( + sprintf('%s does not exist.', $file) + ); + } + + $config = require $file; + + return new self($config); + } + + /** + * Send HTTP headers. + * + * @return void + */ + public function send() + { + if (headers_sent($file, $line)) { + throw new RuntimeException( + sprintf('Headers already sent in %s on line %d.', $file, $line) + ); + } + + foreach ($this->headers() as $key => $value) { + header(sprintf('%s: %s', $key, $value), true); + } + + $this->sent = true; + } + + /** + * Get HTTP headers. + * + * @return array + */ + public function headers(): array + { + $headers = array_merge( + $this->csp(), + $this->permissionsPolicy(), + $this->hsts(), + $this->expectCT(), + $this->clearSiteData(), + $this->miscellaneous() + ); + + $this->sent = true; + + return array_filter($headers); + } + + /** + * Get CSP header. + * + * @return array + */ + protected function csp(): array + { + $config = $this->config['csp'] ?? []; + + if (!($config['enable'] ?? false)) { + return []; + } + + $config['script-src']['nonces'] = self::$nonces['script']; + + $config['style-src']['nonces'] = self::$nonces['style']; + + $key = ($config['report-only'] ?? false) + ? 'Content-Security-Policy-Report-Only' + : 'Content-Security-Policy'; + + $builder = new ContentSecurityPolicyBuilder($config); + + return [$key => $builder->get()]; + } + + /** + * Get Permissions Policy header. + * + * @return array + */ + protected function permissionsPolicy(): array + { + $config = $this->config['permissions-policy'] ?? []; + + if (!($config['enable'] ?? false)) { + return []; + } + + $builder = new PermissionsPolicyBuilder($config); + + return ['Permissions-Policy' => $builder->get()]; + } + + /** + * Get HSTS header. + * + * @return array + */ + protected function hsts(): array + { + $config = $this->config['hsts'] ?? []; + + if (!($config['enable'] ?? false)) { + return []; + } + + $builder = new StrictTransportSecurityBuilder($config); + + return ['Strict-Transport-Security' => $builder->get()]; + } + + /** + * Generate Expect-CT header. + * + * @return array + */ + protected function expectCT(): array + { + $config = $this->config['expect-ct'] ?? []; + + if (!($config['enable'] ?? false)) { + return []; + } + + $builder = new ExpectCertificateTransparencyBuilder($config); + + return ['Expect-CT' => $builder->get()]; + } + + /** + * Generate Clear-Site-Data header. + * + * @return array + */ + protected function clearSiteData(): array + { + $config = $this->config['clear-site-data'] ?? []; + + if (!($config['enable'] ?? false)) { + return []; + } + + $builder = new ClearSiteDataBuilder($config); + + return ['Clear-Site-Data' => $builder->get()]; + } + + /** + * Get miscellaneous headers. + * + * @return array + */ + protected function miscellaneous(): array + { + return array_filter([ + 'X-Content-Type-Options' => $this->config['x-content-type-options'], + 'X-Download-Options' => $this->config['x-download-options'], + 'X-Frame-Options' => $this->config['x-frame-options'], + 'X-Permitted-Cross-Domain-Policies' => $this->config['x-permitted-cross-domain-policies'], + 'X-Powered-By' => $this->config['x-powered-by'] ?? ($this->config['x-power-by'] ?? ''), + 'X-XSS-Protection' => $this->config['x-xss-protection'], + 'Referrer-Policy' => $this->config['referrer-policy'], + 'Server' => $this->config['server'], + 'Cross-Origin-Embedder-Policy' => $this->config['cross-origin-embedder-policy'] ?? '', + 'Cross-Origin-Opener-Policy' => $this->config['cross-origin-opener-policy'] ?? '', + 'Cross-Origin-Resource-Policy' => $this->config['cross-origin-resource-policy'] ?? '', + ]); + } + + /** + * Generate random nonce value for current request. + * + * @param string $target + * @return string + * + * @throws Exception + */ + public static function nonce(string $target = 'script'): string + { + $nonce = base64_encode(bin2hex(random_bytes(8))); + + self::$nonces[$target][] = $nonce; + + return $nonce; + } + + /** + * Remove specific nonce value or flush all nonce for the given target. + * + * @param string|null $target + * @param string|null $nonce + * @return void + */ + public static function removeNonce(string $target = null, string $nonce = null) + { + if ($target === null) { + self::$nonces['script'] = self::$nonces['style'] = []; + } elseif (isset(self::$nonces[$target])) { + if ($nonce === null) { + self::$nonces[$target] = []; + } elseif (false !== ($idx = array_search($nonce, self::$nonces[$target]))) { + unset(self::$nonces[$target][$idx]); + } + } + } +} diff --git a/src/SecurityHeadersServiceProvider.php b/src/SecurityHeadersServiceProvider.php new file mode 100644 index 0000000..6487a87 --- /dev/null +++ b/src/SecurityHeadersServiceProvider.php @@ -0,0 +1,40 @@ +publishes([ + __DIR__ . '/../stubs/config/security-headers.php' => config_path('security-headers.php'), + ], 'config'); + + $this->commands([ + Console\InstallCommand::class, + ]); + + $this->registerPolicies(); + } +} diff --git a/stubs/Events/BlogApprovedRejected.php b/stubs/Events/BlogApprovedRejected.php deleted file mode 100755 index 0479bcc..0000000 --- a/stubs/Events/BlogApprovedRejected.php +++ /dev/null @@ -1,37 +0,0 @@ -blog = $blog; - } - - /** - * Get the channels the event should broadcast on. - * - * @return \Illuminate\Broadcasting\Channel|array - */ - public function broadcastOn() - { - return new PrivateChannel('channel-name'); - } -} diff --git a/stubs/Http/Controllers/BlogController.php b/stubs/Http/Controllers/BlogController.php deleted file mode 100755 index 29ecd9a..0000000 --- a/stubs/Http/Controllers/BlogController.php +++ /dev/null @@ -1,444 +0,0 @@ -orderBy('id', 'desc') - ->where(['user_id' => Auth::id()]); - if (Gate::allows('isAdmin')) { - $query = Blog::sortable() - ->orderBy('id', 'desc') - ->whereNot('status', Blog::STATUS_DRAFT); - } - $blogs = $query->paginate(5)->withQueryString(); - - return view('blog.index', [ - 'blogs' => $blogs, - 'published' => false, - ]); - } - - /** - * Display a listing of the published blog. - * - * @return \App\Models\Blog - */ - public function published() - { - $blogs = Cache::remember('publishedBlog', now()->addSeconds(60), function () { - return Blog::with(['user','tags','totalComments'])->sortable() - ->orderBy('id', 'desc') - ->where([ - 'is_published' => true, - 'status' => Blog::STATUS_APPROVE - ]) - ->paginate(5) - ->withQueryString(); - }); - - return view('blog.index', [ - 'blogs' => $blogs, - 'published' => true, - ]); - } - - /** - * Show the form for creating a new resource. - * - * @return \Illuminate\Http\Response - */ - public function create() - { - $tagsObject = new TagController(); - $tags = $tagsObject->get(); - - return view('blog.add', compact('tags')); - } - - /** - * Store a newly created resource in storage. - * - * @param \Illuminate\Http\Request $request - * @return bool - */ - public function store(StoreBlogRequest $request) - { - // Retrieve the validated input data... - $validated = $request->validated(); - $blogs = new Blog(); - $blogs->title = $validated['title']; - $blogs->slug = Str::slug($blogs->title , "-"); - $blogs->description = $validated['description']; - $blogs->is_published = (bool)$request->is_published ?? false; - $blogs->user_id = Auth::id(); - $blogs->status = $this->blogStatus($blogs); - if ($image = $request->file('image')) { - $destinationPath = storage_path('app/public/blog/'); - $blogImage = $blogs->slug . "." . $image->getClientOriginalExtension(); - $image->move($destinationPath, $blogImage); - $blogs->image = $blogImage; - } - $result = $blogs->save(); - if ($request->filled('tags')) { - $tags = new TagController(); - $relatedTags = $tags->store($request->input('tags')); - - $blogs->tags()->sync($relatedTags); - } - - if ($result) { - return redirect()->route('blogs.index')->with([ - 'success' => __('blog.create_success_message'), - 'type'=>'success' - ]); - } else { - return redirect()->route('blogs.add')->with([ - 'error' => __('blog.error_message'), - 'type'=>'danger' - ]); - } - } - - /** - * Display the specified resource. - * - * @param int $id - * @return \App\Models\Blog - */ - public function show($id) - { - $blogs = Blog::with('comments')->where('slug', $id)->firstOrFail(); - $permission = Gate::inspect('view', $blogs); - if (! $permission->allowed()) { - return redirect()->route('blogs.index')->with(['success' => $permission->message(),'type'=>'danger']); - } - $counter = $this->currentlyViewByUsers($id); - - return view('blog.view', [ - 'blog' => $blogs, - 'counter' => $counter, - ]); - } - - /** - * Show the form for editing the specified resource. - * - * @param int $id - * @return array - */ - public function edit($id) - { - $tagsObject = new TagController(); - $tags = $tagsObject->get(); - - $blogs = Blog::where('slug', $id)->firstOrFail(); - $permission = Gate::inspect('update', $blogs); - if (! $permission->allowed()) { - return redirect()->route('blogs.index')->with(['success' => $permission->message(),'type'=>'danger']); - } - - return view('blog.edit', [ - 'blog' => $blogs, - 'tags' => $tags, - ]); - } - - /** - * Update the specified resource in storage. - * - * @param \Illuminate\Http\Request $request - * @param int $id - * @return array - */ - public function update(Request $request, $id) - { - $blogs = Blog::where('slug', $id)->firstOrFail(); - $permission = Gate::inspect('update', $blogs); - if (! $permission->allowed()) { - return redirect()->route('blogs.index')->with(['success' => $permission->message(),'type'=>'danger']); - } - $isPatch = $request->isMethod('PATCH'); - if (! $isPatch) { - $messages = [ - 'required' => 'Required', - ]; - $validated = Validator::make($request->all(), [ - 'title' => 'required|between:3,50', - 'description' => 'required|min:20|max:250', - 'image' => 'image|mimes:jpeg,png,jpg,gif,svg|max:2048', - ], $messages)->validate(); - $blogs->title = $validated['title']; - $blogs->slug = Str::slug($blogs->title , "-"); - $blogs->description = $validated['description']; - $blogs->user_id = Auth::id(); - if ($image = $request->file('image')) { - $destinationPath = storage_path('app/public/blog/'); - $blogImage = $blogs->slug . "." . $image->getClientOriginalExtension(); - $image->move($destinationPath, $blogImage); - $blogs->image = $blogImage; - if (! empty($request->old_image) && $request->old_image != $blogImage) { - unlink(storage_path('app/public/blog/').$request->old_image); - } - } - if ($request->filled('tags')) { - $tags = new TagController(); - $relatedTags = $tags->store($request->input('tags')); - $blogs->tags()->sync($relatedTags); - } - } - $blogs->is_published = (bool)$request->is_published ?? false; - $blogs->status = $this->blogStatus($blogs); - $result = $blogs->save(); - - if ($isPatch) { - return true; - } - if ($result) { - return redirect()->route('blogs.index')->with([ - 'success' => __('blog.update_success_message'), - 'type'=>'success' - ]); - } else { - return redirect()->route('blogs.edit')->with([ - 'error' => __('blog.error_message'), - 'type'=>'danger' - ]); - } - } - - /** - * Move the specified resource from storage to trashbin. - * - * @param int $id - * @return bool - */ - public function destroy($id) - { - $blogs = Blog::where('slug', $id)->firstOrFail(); - - if (! Gate::allows('isOwner', $blogs)) { - redirect()->route('blogs.index')->with(['success' => __('blog.permission_denied_error'),'type'=>'danger']); - return true; - } - $blogs->delete(); - - redirect()->route('blogs.index')->with(['success' => __('blog.delete_success_message'),'type'=>'success']); - return true; - } - - /** - * Remove the specified resource from storage. - * - * @param int $id - * @return bool - */ - public function forceDestroy($id) - { - $blogs = Blog::withTrashed()->where('slug', $id)->firstOrFail(); - - $permission = Gate::inspect('forceDelete', $blogs); - - if (! $permission->allowed()) { - redirect()->route('blogs.index')->with(['success' => __('blog.permission_denied_error'),'type'=>'danger']); - return true; - } - - if (! empty($blogs->image)) { - unlink(storage_path('app/public/blog/').$blogs->image); - } - - $blogs->forceDelete(); - - redirect()->route('blogs.trash_bin')->with([ - 'success' => __('blog.delete_success_message'), - 'type'=>'success' - ]); - - return true; - } - - /** - * restore specific post - * - * @return \App\Models\Blog - */ - public function trashBin() - { - $blogs = Blog::sortable()->onlyTrashed()->where(['user_id' => Auth::id()])->paginate(5); - - return view('blog.trash_bin', [ - 'blogs' => $blogs, - 'published' => false, - ]); - } - - /** - * restore specific post - * - * @return bool - */ - public function restore($id) - { - $blogs = Blog::withTrashed()->where('slug', $id)->firstOrFail(); - $permission = Gate::inspect('restore', $blogs); - - if (! $permission->allowed()) { - redirect()->route('blogs.index')->with(['success' => __('blog.permission_denied_error'),'type'=>'danger']); - return true; - } - - $blogs->restore(); - - redirect()->route('blogs.trash_bin')->with([ - 'success' => __('blog.restore_success_message'), - 'type'=>'success' - ]); - - return true; - } - - /** - * Restore all post - * - * @return bool - */ - public function restoreAll() - { - $blogs = Blog::onlyTrashed()->where(['user_id' => Auth::id()]); - $blogs->restore(); - - redirect()->route('blogs.index')->with([ - 'success' => __('blog.restore_success_message'), - 'type'=>'success' - ]); - return true; - } - - /** - * Function will return the status for published/unpublished blog - * - * @param bool published blog is $published or Not - * @param bool $blogStatus pervious status of the blog - * - * @return string - */ - public function blogStatus($blog) - { - if ($blog->is_published) { - $status = Blog::STATUS_PENDING; - $users = User::where('role', 'admin')->get(); - if (config('blog-application.send_mail_and_notification')) { - $users->each->notify(new BlogPublishRequest($blog)); - } - } elseif (! $blog->is_published || empty($blog->status)) { - $status = Blog::STATUS_DRAFT; - } - - return $status; - } - - /** - * Function description - * - * @param int variable Description $variable comment about this variable - * - * @return array - */ - public function updateStatus(Request $request, $id) - { - $validator = Validator::make($request->all(), [ - 'status' => 'required|string', - 'reject_reason' => 'required_if:status,==,rejected|nullable', - ]); - if ($validator->fails()) { - return response()->json(['errors'=>$validator->errors()->all()]); - } - $blogs = Blog::where('slug', $id)->firstOrFail(); - $permission = Gate::inspect('update', $blogs); - if (! $permission->allowed()) { - return response()->json(['success' => $permission->message(),'type'=>'danger']); - } - if ($request->status == Blog::STATUS_REJECTED) { - $blogs->status = Blog::STATUS_REJECTED; - $blogs->reject_reason = $request->reject_reason; - $blogs->is_published = false; - } elseif ($request->status == Blog::STATUS_APPROVE) { - $blogs->status = Blog::STATUS_APPROVE; - $blogs->published_at = now(); - } - $blogs->action_by = Auth::id(); - $result = $blogs->save(); - if ($result) { - if (config('blog-application.send_mail_and_notification')) { - event(new BlogApprovedRejected($response['blogs'])); - } - return true; - } - - return false; - } - - /** - * Function will give the total user which are reading blog at the moment - * - * @param string $id Blog Slug - * - * @return int - */ - public function currentlyViewByUsers($id) - { - $sessionId = session()->getId(); - $counterKey = "blog-post-{$id}-counter"; - $usersKey = "blog-post-{$id}-users"; - - $users = Cache::get($usersKey, []); - $usersUpdate = []; - $diffrence = 0; - $now = now(); - foreach ($users as $session => $lastVisit) { - if ($now->diffInMinutes($lastVisit) >= 1) { - $diffrence--; - } else { - $usersUpdate[$session] = $lastVisit; - } - } - - if (! array_key_exists($sessionId, $users) - || $now->diffInMinutes($users[$sessionId]) >= 1 - ) { - $diffrence++; - } - - $usersUpdate[$sessionId] = $now; - Cache::forever($usersKey, $usersUpdate); - - if (!Cache::has($counterKey)) { - Cache::forever($counterKey, 1); - } else { - Cache::increment($counterKey, $diffrence); - } - return Cache::get($counterKey); - } -} diff --git a/stubs/Http/Controllers/CommentController.php b/stubs/Http/Controllers/CommentController.php deleted file mode 100755 index f516e0b..0000000 --- a/stubs/Http/Controllers/CommentController.php +++ /dev/null @@ -1,82 +0,0 @@ - 'Required', - ]; - $attributes = [ - 'body_'.$request->parent_id => 'body', - ]; - $validated = Validator::make($request->all(), [ - 'body_'.$request->parent_id => 'required', - ], $messages, $attributes)->validate(); - - $comment = new Comment; - $comment->body = $validated['body_'.$request->parent_id]; - $comment->parent_id = $request->parent_id ?? null; - $comment->blog_id = $request->blog_id; - $comment->user_id = Auth::id(); - $result = $comment->save(); - if ($result) { - // if you want to Send mail after sometime use delay function with carbon - $userFrom = User::find($comment->user_id); - $blog = Blog::find($comment->blog_id); - if (config('blog-application.send_mail_and_notification')) { - dispatch(new SendEmailJob($userFrom, $blog->user, $blog, $comment)); - } - } - - return back(); - } - - /** - * Remove the specified resource from storage. - * - * @param int $id - * @return int - */ - public function destroy($id) - { - $comments = Comment::find($id); - $comments->deleteNestedComments(); - $comments->delete(); - - return $id; - } - - - /** - * Remove the specified resource from storage. - * - * @param int $id - * @return int - */ - public function pinComment($id) - { - $type = request()->type == 'pin' ? true : false; - $comments = Comment::find($id); - $comments->pinned = $type; - $comments->save(); - return true; - } -} diff --git a/stubs/Http/Controllers/TagController.php b/stubs/Http/Controllers/TagController.php deleted file mode 100755 index c95de89..0000000 --- a/stubs/Http/Controllers/TagController.php +++ /dev/null @@ -1,38 +0,0 @@ - $tag]); - $tagIds[] = $firstTag->id; - } - return $tagIds; - } - - /** - * get all resource in stored in database. - * - * @return array - */ - public function get() - { - return Tag::get()->pluck('name', 'id'); - } -} diff --git a/stubs/Http/Middleware/ChangeSiteLanguage.php b/stubs/Http/Middleware/SecurityHeadersMiddleware.php similarity index 58% rename from stubs/Http/Middleware/ChangeSiteLanguage.php rename to stubs/Http/Middleware/SecurityHeadersMiddleware.php index 7ea37e2..23351cc 100755 --- a/stubs/Http/Middleware/ChangeSiteLanguage.php +++ b/stubs/Http/Middleware/SecurityHeadersMiddleware.php @@ -4,23 +4,28 @@ use Closure; use Illuminate\Http\Request; -use Illuminate\Support\Facades\App; +use MonishKhatri\SecurityHeaders\SecureHeaders; -class ChangeSiteLanguage +class SecurityHeadersMiddleware { /** * Handle an incoming request. * * @param \Illuminate\Http\Request $request * @param \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse) $next + * * @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse */ public function handle(Request $request, Closure $next) { - if (session()->has('locale')) { - App::setLocale(session()->get('locale')); + $response = $next($request); + + $headers = (new SecureHeaders(config('security-headers', [])))->headers(); + + foreach ($headers as $key => $value) { + $response->headers->set($key, $value, true); } - return $next($request); + return $response; } } diff --git a/stubs/Http/Requests/StoreBlogRequest.php b/stubs/Http/Requests/StoreBlogRequest.php deleted file mode 100755 index 3ff8d7f..0000000 --- a/stubs/Http/Requests/StoreBlogRequest.php +++ /dev/null @@ -1,54 +0,0 @@ - - */ - public function rules() - { - return [ - 'title' => 'required|between:3,50', - 'description' => 'required|min:20|max:250', - 'image' => 'image|mimes:jpeg,png,jpg,gif,svg|max:2048', - ]; - } - - /** - * Prepare the data for validation. - * - * @return void - */ - protected function prepareForValidation() - { - $this->merge([ - 'title' => Str::ucfirst($this->title), - 'slug' => Str::slug($this->title, "-"), - ]); - } -} diff --git a/stubs/Http/Resources/BlogCollection.php b/stubs/Http/Resources/BlogCollection.php deleted file mode 100755 index 293d274..0000000 --- a/stubs/Http/Resources/BlogCollection.php +++ /dev/null @@ -1,25 +0,0 @@ - $this->collection, - 'links' => [ - 'self' => 'link-value', - ], - ]; - } -} diff --git a/stubs/Http/Resources/BlogResource.php b/stubs/Http/Resources/BlogResource.php deleted file mode 100755 index 04c7352..0000000 --- a/stubs/Http/Resources/BlogResource.php +++ /dev/null @@ -1,28 +0,0 @@ - $this->id, - 'title' => $this->title, - 'description' => $this->description, - 'is_published' => $this->is_published, - 'user_id' => $this->user_id, - 'created_at' => $this->created_at, - 'updated_at' => $this->updated_at, - ]; - } -} diff --git a/stubs/Jobs/SendEmailJob.php b/stubs/Jobs/SendEmailJob.php deleted file mode 100755 index eb2746a..0000000 --- a/stubs/Jobs/SendEmailJob.php +++ /dev/null @@ -1,45 +0,0 @@ -userFrom = $userFrom; - $this->userTo = $userTo; - $this->blog = $blog; - $this->comment = $comment; - } - - /** - * Execute the job. - * - * @return void - */ - public function handle() - { - if ($this->userTo->email != $this->userFrom->email) { - Mail::to($this->userTo->email)->send(new SendMailable($this->userFrom, $this->blog, $this->comment)); - } - } -} diff --git a/stubs/Listeners/NotifyUserWithBlogStatus.php b/stubs/Listeners/NotifyUserWithBlogStatus.php deleted file mode 100755 index 03c2b32..0000000 --- a/stubs/Listeners/NotifyUserWithBlogStatus.php +++ /dev/null @@ -1,41 +0,0 @@ -blog->status, [Blog::STATUS_APPROVE, Blog::STATUS_REJECTED])) { - $user = $event->blog->user; - Mail::send('emails.blog_action', ['user' => $user, 'blog'=>$event->blog], function ($message) use ($user) { - $message->from('admin@admin.com', 'MBS['.config('app.name').']'); - $message->subject('Action Performed on you Blog!'); - $message->to($user->email); - }); - } - } -} diff --git a/stubs/Mail/SendMailable.php b/stubs/Mail/SendMailable.php deleted file mode 100755 index 3521139..0000000 --- a/stubs/Mail/SendMailable.php +++ /dev/null @@ -1,40 +0,0 @@ -userFrom = $userFrom; - $this->blog = $blog; - $this->comment = $comment; - } - - /** - * Build the message. - * - * @return $this - */ - public function build() - { - return $this->subject('New Comment Added')->view('emails.comment_action', [ - 'user'=>$this->userFrom, 'blog'=>$this->blog, 'comment'=>$this->comment - ]); - } -} diff --git a/stubs/Models/Blog.php b/stubs/Models/Blog.php deleted file mode 100755 index fd47957..0000000 --- a/stubs/Models/Blog.php +++ /dev/null @@ -1,109 +0,0 @@ - Auth::id(), - ]; - - public $sortable = ['id','title','description','is_published']; - protected $fillable = [ - 'title', - 'description', - 'slug', - 'is_published', - 'status', - 'user_id', - 'approve_by', - 'reject_reason', - 'published_at', - 'image', - ]; - - /** - * Get the route key for the model. - * - * @return string - */ - public function getRouteKeyName() - { - return 'slug'; - } - - /** - * Increment blog slug with count if exists. - */ - public function setSlugAttribute($value) { - if (empty($this->id) && static::whereSlug($slug = Str::slug($value, "-"))->exists()) { - $slug = "{$value}-" . random_int(1, 999) . ""; - } elseif (static::whereSlug($slug = Str::slug($value, "-"))->where('id', '!=', $this->id)->exists()) { - $slug = "{$value}-{$this->id}"; - } - $this->attributes['slug'] = $slug; - } - /** - * Get the user associated with the blog. - */ - public function user() - { - return $this->hasOne(User::class, 'id', 'user_id'); - } - /** - * Get the user associated with the blog. - */ - public function admin() - { - return $this->hasOne(User::class, 'id', 'action_by'); - } - - /** - * The has Many Relationship - * - * @var array - */ - public function comments() - { - return $this->hasMany(Comment::class)->whereNull('parent_id')->orderBy('pinned', 'DESC')->latest('created_at'); - } - - /** - * The has Many Relationship - * - * @var array - */ - public function totalComments() - { - return $this->hasMany(Comment::class); - } - - /** - * The has Many Relationship - * - * @var array - */ - public function tags() - { - return $this->belongsToMany(Tag::class, 'blog_tag', 'blog_id', 'tag_id'); - } -} diff --git a/stubs/Models/Comment.php b/stubs/Models/Comment.php deleted file mode 100755 index 4362033..0000000 --- a/stubs/Models/Comment.php +++ /dev/null @@ -1,51 +0,0 @@ -belongsTo(User::class); - } - - /** - * The has Many Relationship - * - * @var array - */ - public function replies() - { - return $this->hasMany(Comment::class, 'parent_id')->orderBy('pinned', 'DESC'); - } - - /** - * delete nested child comments - * - * @var array - */ - public function deleteNestedComments() - { - // Calling the same method to all of the child of this replies - $this->replies->each->deleteNestedComments(); - - // Delete all replies of this comment - $this->replies()->delete(); - } -} diff --git a/stubs/Models/Tag.php b/stubs/Models/Tag.php deleted file mode 100755 index 3338311..0000000 --- a/stubs/Models/Tag.php +++ /dev/null @@ -1,25 +0,0 @@ -belongsToMany(Blog::class, 'blog_tag', 'tag_id', 'blog_id'); - } -} diff --git a/stubs/Notifications/BlogPublishRequest.php b/stubs/Notifications/BlogPublishRequest.php deleted file mode 100755 index 0824a45..0000000 --- a/stubs/Notifications/BlogPublishRequest.php +++ /dev/null @@ -1,62 +0,0 @@ -blog = $blog; - } - - /** - * Get the notification's delivery channels. - * - * @param mixed $notifiable - * @return array - */ - public function via($notifiable) - { - return ['mail']; - } - - /** - * Get the mail representation of the notification. - * - * @param mixed $notifiable - * @return \Illuminate\Notifications\Messages\MailMessage - */ - public function toMail($notifiable) - { - return (new MailMessage) - ->subject('New Publish Request') - ->line(new HtmlString(ucwords($this->blog->user->name) .' Has Raised a publish request for “'.$this->blog->title.'” Blog!')) - ->action('View Blog', route('blogs.index')); - } - - /** - * Get the array representation of the notification. - * - * @param mixed $notifiable - * @return array - */ - public function toArray($notifiable) - { - return [ - // - ]; - } -} diff --git a/stubs/Policies/BlogPolicy.php b/stubs/Policies/BlogPolicy.php deleted file mode 100755 index 3c50b07..0000000 --- a/stubs/Policies/BlogPolicy.php +++ /dev/null @@ -1,95 +0,0 @@ -is_published == true || $user->id === $blog->user_id || $user->role == 'admin' ? Response::allow() : Response::deny(__('blog.permission_denied_error')); - } - - /** - * Determine whether the user can create models. - * - * @param \App\Models\User $user - * @return \Illuminate\Auth\Access\Response|bool - */ - public function create(User $user) - { - // - } - - /** - * Determine whether the user can update the model. - * - * @param \App\Models\User $user - * @param \App\Models\Blog $blog - * @return \Illuminate\Auth\Access\Response|bool - */ - public function update(User $user, Blog $blog) - { - return $user->id === $blog->user_id || $user->role == 'admin' ? Response::allow() : Response::deny(__('blog.permission_denied_error')); - } - - /** - * Determine whether the user can delete the model. - * - * @param \App\Models\User $user - * @param \App\Models\Blog $blog - * @return \Illuminate\Auth\Access\Response|bool - */ - public function delete(User $user, Blog $blog) - { - return $user->id === $blog->user_id ? Response::allow(): Response::deny(__('blog.permission_denied_error')); - } - - /** - * Determine whether the user can restore the model. - * - * @param \App\Models\User $user - * @param \App\Models\Blog $blog - * @return \Illuminate\Auth\Access\Response|bool - */ - public function restore(User $user, Blog $blog) - { - return $user->id === $blog->user_id ? Response::allow(): Response::deny(__('blog.permission_denied_error')); - } - - /** - * Determine whether the user can permanently delete the model. - * - * @param \App\Models\User $user - * @param \App\Models\Blog $blog - * @return \Illuminate\Auth\Access\Response|bool - */ - public function forceDelete(User $user, Blog $blog) - { - return $user->id === $blog->user_id ? Response::allow(): Response::deny(__('blog.permission_denied_error')); - } -} diff --git a/stubs/View/Components/AlertMessage.php b/stubs/View/Components/AlertMessage.php deleted file mode 100755 index 5b5048e..0000000 --- a/stubs/View/Components/AlertMessage.php +++ /dev/null @@ -1,50 +0,0 @@ -type = $type; - $this->message = $message; - } - - /** - * Get the view / contents that represent the component. - * - * @return \Illuminate\Contracts\View\View|\Closure|string - */ - public function render() - { - return <<<'blade' -
merge(['class' => 'alert alert-'.$type]) }}> - - {{ $message }} -
- blade; - } -} diff --git a/stubs/config/blog-application.php b/stubs/config/blog-application.php deleted file mode 100644 index 37d3c35..0000000 --- a/stubs/config/blog-application.php +++ /dev/null @@ -1,7 +0,0 @@ - true, - 'application_logo' => 'https://cdn.shopify.com/s/files/1/0252/7490/8726/files/messi-logo-word_200x.png', - 'application_favicon' => '//cdn.shopify.com/s/files/1/0252/7490/8726/files/footer-logo_100x100.png', -]; diff --git a/stubs/config/security-headers.php b/stubs/config/security-headers.php new file mode 100644 index 0000000..0a6c5fc --- /dev/null +++ b/stubs/config/security-headers.php @@ -0,0 +1,693 @@ + '', + + /* + * X-Content-Type-Options + * + * Reference: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options + * + * Available Value: 'nosniff' + */ + + 'x-content-type-options' => 'nosniff', + + /* + * X-Download-Options + * + * Reference: https://msdn.microsoft.com/en-us/library/jj542450(v=vs.85).aspx + * + * Available Value: 'noopen' + */ + + 'x-download-options' => 'noopen', + + /* + * X-Frame-Options + * + * Reference: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options + * + * Available Value: 'deny', 'sameorigin', 'allow-from ' + */ + + 'x-frame-options' => 'sameorigin', + + /* + * X-Permitted-Cross-Domain-Policies + * + * Reference: https://www.adobe.com/devnet/adobe-media-server/articles/cross-domain-xml-for-streaming.html + * + * Available Value: 'all', 'none', 'master-only', 'by-content-type', 'by-ftp-filename' + */ + + 'x-permitted-cross-domain-policies' => 'none', + + /* + * X-Powered-By + * + * Note: it will not add to response header if the value is empty string. + * + * Also, verify that expose_php is turned Off in php.ini. + * Otherwise the header will still be included in the response. + * + * Reference: https://github.com/bepsvpt/secure-headers/issues/58#issuecomment-782332442 + */ + + 'x-powered-by' => '', + + /* + * X-XSS-Protection + * + * Reference: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-XSS-Protection + * + * Available Value: '1', '0', '1; mode=block' + */ + + 'x-xss-protection' => '1; mode=block', + + /* + * Referrer-Policy + * + * Reference: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy + * + * Available Value: 'no-referrer', 'no-referrer-when-downgrade', 'origin', 'origin-when-cross-origin', + * 'same-origin', 'strict-origin', 'strict-origin-when-cross-origin', 'unsafe-url' + */ + + 'referrer-policy' => 'no-referrer', + + /* + * Cross-Origin-Embedder-Policy + * + * Reference: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Embedder-Policy + * + * Available Value: 'unsafe-none', 'require-corp' + */ + 'cross-origin-embedder-policy' => 'unsafe-none', + + /* + * Cross-Origin-Opener-Policy + * + * Reference: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Opener-Policy + * + * Available Value: 'unsafe-none', 'same-origin-allow-popups', 'same-origin' + */ + 'cross-origin-opener-policy' => 'unsafe-none', + + /* + * Cross-Origin-Resource-Policy + * + * Reference: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Resource-Policy + * + * Available Value: 'same-site', 'same-origin', 'cross-origin' + */ + 'cross-origin-resource-policy' => 'cross-origin', + + /* + * Clear-Site-Data + * + * Reference: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Clear-Site-Data + */ + + 'clear-site-data' => [ + 'enable' => false, + + 'all' => false, + + 'cache' => true, + + 'cookies' => true, + + 'storage' => true, + + 'executionContexts' => true, + ], + + /* + * HTTP Strict Transport Security + * + * Reference: https://developer.mozilla.org/en-US/docs/Web/Security/HTTP_strict_transport_security + * + * Please ensure your website had set up ssl/tls before enable hsts. + */ + + 'hsts' => [ + 'enable' => false, + + 'max-age' => 31536000, + + 'include-sub-domains' => false, + + 'preload' => false, + ], + + /* + * Expect-CT + * + * Reference: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Expect-CT + */ + + 'expect-ct' => [ + 'enable' => false, + + 'max-age' => 2147483648, + + 'enforce' => false, + + // report uri must be absolute-URI + 'report-uri' => null, + ], + + /* + * Permissions Policy + * + * Reference: https://w3c.github.io/webappsec-permissions-policy/ + */ + + 'permissions-policy' => [ + 'enable' => true, + + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Feature-Policy/accelerometer + 'accelerometer' => [ + 'none' => false, + + '*' => false, + + 'self' => true, + + 'origins' => [], + ], + + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Feature-Policy/ambient-light-sensor + 'ambient-light-sensor' => [ + 'none' => false, + + '*' => false, + + 'self' => true, + + 'origins' => [], + ], + + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Feature-Policy/autoplay + 'autoplay' => [ + 'none' => false, + + '*' => false, + + 'self' => true, + + 'origins' => [], + ], + + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Feature-Policy/battery + 'battery' => [ + 'none' => false, + + '*' => false, + + 'self' => true, + + 'origins' => [], + ], + + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Feature-Policy/camera + 'camera' => [ + 'none' => false, + + '*' => false, + + 'self' => true, + + 'origins' => [], + ], + + // https://www.chromestatus.com/feature/5690888397258752 + 'cross-origin-isolated' => [ + 'none' => false, + + '*' => false, + + 'self' => true, + + 'origins' => [], + ], + + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Feature-Policy/display-capture + 'display-capture' => [ + 'none' => false, + + '*' => false, + + 'self' => true, + + 'origins' => [], + ], + + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Feature-Policy/document-domain + 'document-domain' => [ + 'none' => false, + + '*' => true, + + 'self' => false, + + 'origins' => [], + ], + + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Feature-Policy/encrypted-media + 'encrypted-media' => [ + 'none' => false, + + '*' => false, + + 'self' => true, + + 'origins' => [], + ], + + // https://wicg.github.io/page-lifecycle/#execution-while-not-rendered + 'execution-while-not-rendered' => [ + 'none' => false, + + '*' => true, + + 'self' => false, + + 'origins' => [], + ], + + // https://wicg.github.io/page-lifecycle/#execution-while-out-of-viewport + 'execution-while-out-of-viewport' => [ + 'none' => false, + + '*' => true, + + 'self' => false, + + 'origins' => [], + ], + + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Feature-Policy/fullscreen + 'fullscreen' => [ + 'none' => false, + + '*' => false, + + 'self' => true, + + 'origins' => [], + ], + + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Feature-Policy/geolocation + 'geolocation' => [ + 'none' => false, + + '*' => false, + + 'self' => true, + + 'origins' => [], + ], + + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Feature-Policy/gyroscope + 'gyroscope' => [ + 'none' => false, + + '*' => false, + + 'self' => true, + + 'origins' => [], + ], + + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Feature-Policy/magnetometer + 'magnetometer' => [ + 'none' => false, + + '*' => false, + + 'self' => true, + + 'origins' => [], + ], + + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Feature-Policy/microphone + 'microphone' => [ + 'none' => false, + + '*' => false, + + 'self' => true, + + 'origins' => [], + ], + + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Feature-Policy/midi + 'midi' => [ + 'none' => false, + + '*' => false, + + 'self' => true, + + 'origins' => [], + ], + + // https://drafts.csswg.org/css-nav-1/ + 'navigation-override' => [ + 'none' => false, + + '*' => false, + + 'self' => true, + + 'origins' => [], + ], + + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Feature-Policy/payment + 'payment' => [ + 'none' => false, + + '*' => false, + + 'self' => true, + + 'origins' => [], + ], + + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Feature-Policy/picture-in-picture + 'picture-in-picture' => [ + 'none' => false, + + '*' => true, + + 'self' => false, + + 'origins' => [], + ], + + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Feature-Policy/publickey-credentials-get + 'publickey-credentials-get' => [ + 'none' => false, + + '*' => false, + + 'self' => true, + + 'origins' => [], + ], + + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Feature-Policy/screen-wake-lock + 'screen-wake-lock' => [ + 'none' => false, + + '*' => false, + + 'self' => true, + + 'origins' => [], + ], + + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Feature-Policy/sync-xhr + 'sync-xhr' => [ + 'none' => false, + + '*' => true, + + 'self' => false, + + 'origins' => [], + ], + + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Feature-Policy/usb + 'usb' => [ + 'none' => false, + + '*' => false, + + 'self' => true, + + 'origins' => [], + ], + + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Feature-Policy/web-share + 'web-share' => [ + 'none' => false, + + '*' => false, + + 'self' => true, + + 'origins' => [], + ], + + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Feature-Policy/xr-spatial-tracking + 'xr-spatial-tracking' => [ + 'none' => false, + + '*' => false, + + 'self' => true, + + 'origins' => [], + ], + ], + + /* + * Content Security Policy + * + * Reference: https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP + */ + + 'csp' => [ + 'enable' => true, + + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only + 'report-only' => false, + + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/report-to + 'report-to' => '', + + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/report-uri + 'report-uri' => [ + // uri + ], + + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/block-all-mixed-content + 'block-all-mixed-content' => false, + + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/upgrade-insecure-requests + 'upgrade-insecure-requests' => false, + + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/base-uri + 'base-uri' => [ + // + ], + + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/child-src + 'child-src' => [ + // + ], + + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/connect-src + 'connect-src' => [ + // + ], + + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/default-src + 'default-src' => [ + // + ], + + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/font-src + 'font-src' => [ + // + ], + + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/form-action + 'form-action' => [ + // + ], + + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/frame-ancestors + 'frame-ancestors' => [ + // + ], + + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/frame-src + 'frame-src' => [ + // + ], + + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/img-src + 'img-src' => [ + // + ], + + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/manifest-src + 'manifest-src' => [ + // + ], + + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/media-src + 'media-src' => [ + // + ], + + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/navigate-to + 'navigate-to' => [ + 'unsafe-allow-redirects' => false, + ], + + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/object-src + 'object-src' => [ + // + ], + + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/plugin-types + 'plugin-types' => [ + // 'application/pdf', + ], + + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/prefetch-src + 'prefetch-src' => [ + // + ], + + // https://w3c.github.io/webappsec-trusted-types/dist/spec/#integration-with-content-security-policy + 'require-trusted-types-for' => [ + 'script' => false, + ], + + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/sandbox + 'sandbox' => [ + 'enable' => false, + + 'allow-downloads-without-user-activation' => false, + + 'allow-forms' => false, + + 'allow-modals' => false, + + 'allow-orientation-lock' => false, + + 'allow-pointer-lock' => false, + + 'allow-popups' => false, + + 'allow-popups-to-escape-sandbox' => false, + + 'allow-presentation' => false, + + 'allow-same-origin' => false, + + 'allow-scripts' => false, + + 'allow-storage-access-by-user-activation' => false, + + 'allow-top-navigation' => false, + + 'allow-top-navigation-by-user-activation' => false, + ], + + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/script-src + 'script-src' => [ + 'none' => false, + + 'self' => false, + + 'report-sample' => false, + + 'allow' => [ + // 'url', + ], + + 'schemes' => [ + // 'data:', + // 'https:', + ], + + /* followings are only work for `script` and `style` related directives */ + + 'unsafe-inline' => false, + + 'unsafe-eval' => false, + + // https://www.w3.org/TR/CSP3/#unsafe-hashes-usage + 'unsafe-hashes' => false, + + // Enable `strict-dynamic` will *ignore* `self`, `unsafe-inline`, + // `allow` and `schemes`. You can find more information from: + // https://www.w3.org/TR/CSP3/#strict-dynamic-usage + 'strict-dynamic' => false, + + 'hashes' => [ + 'sha256' => [ + // 'sha256-hash-value-with-base64-encode', + ], + + 'sha384' => [ + // 'sha384-hash-value-with-base64-encode', + ], + + 'sha512' => [ + // 'sha512-hash-value-with-base64-encode', + ], + ], + ], + + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/script-src-attr + 'script-src-attr' => [ + // + ], + + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/script-src-elem + 'script-src-elem' => [ + // + ], + + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/style-src + 'style-src' => [ + // + ], + + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/style-src-attr + 'style-src-attr' => [ + // + ], + + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/style-src-elem + 'style-src-elem' => [ + // + ], + + // https://w3c.github.io/webappsec-trusted-types/dist/spec/#trusted-types-csp-directive + 'trusted-types' => [ + 'enable' => false, + + 'allow-duplicates' => false, + + 'default' => false, + + 'policies' => [ + // + ], + ], + + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/worker-src + 'worker-src' => [ + // + ], + ], +]; diff --git a/stubs/database/.gitignore b/stubs/database/.gitignore deleted file mode 100755 index 9b19b93..0000000 --- a/stubs/database/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.sqlite* diff --git a/stubs/database/migrations/2022_07_13_054933_create_blogs_table.php b/stubs/database/migrations/2022_07_13_054933_create_blogs_table.php deleted file mode 100755 index c7bfae7..0000000 --- a/stubs/database/migrations/2022_07_13_054933_create_blogs_table.php +++ /dev/null @@ -1,42 +0,0 @@ -id(); - $table->string('slug')->unique()->nullable(); - $table->string('title'); - $table->string('image')->nullable(); - $table->text('description'); - $table->boolean('is_published')->default(false); - $table->date('published_at')->nullable(); - $table->foreignId('user_id')->constrained('users'); - $table->enum('status', ['draft', 'pending', 'approved', 'rejected'])->default('draft'); - $table->foreignId('action_by')->nullable()->constrained('users'); - $table->string('reject_reason', 500)->nullable(); - $table->softDeletes(); - $table->timestamps(); - }); - } - - /** - * Reverse the migrations. - * - * @return void - */ - public function down() - { - Schema::dropIfExists('blogs'); - } -}; diff --git a/stubs/database/migrations/2022_07_20_102233_alter_user_table_add_blog_related_column.php b/stubs/database/migrations/2022_07_20_102233_alter_user_table_add_blog_related_column.php deleted file mode 100755 index 566e8b4..0000000 --- a/stubs/database/migrations/2022_07_20_102233_alter_user_table_add_blog_related_column.php +++ /dev/null @@ -1,34 +0,0 @@ -string('language')->default('en'); - $table->enum('role', ['user', 'admin'])->default('user')->after('email'); - }); - } - - /** - * Reverse the migrations. - * - * @return void - */ - public function down() - { - Schema::table('users', function (Blueprint $table) { - $table->dropColumn('language'); - $table->dropColumn('role'); - }); - } -}; diff --git a/stubs/database/migrations/2022_07_26_090330_create_blogs_comments_table.php b/stubs/database/migrations/2022_07_26_090330_create_blogs_comments_table.php deleted file mode 100755 index aa4cafb..0000000 --- a/stubs/database/migrations/2022_07_26_090330_create_blogs_comments_table.php +++ /dev/null @@ -1,36 +0,0 @@ -id(); - $table->integer('user_id')->unsigned(); - $table->integer('blog_id')->unsigned(); - $table->integer('parent_id')->unsigned()->nullable(); - $table->text('body'); - $table->boolean('pinned')->default(false); - $table->timestamps(); - }); - } - - /** - * Reverse the migrations. - * - * @return void - */ - public function down() - { - Schema::dropIfExists('comments'); - } -}; diff --git a/stubs/database/migrations/2022_08_11_124913_create_tags_table.php b/stubs/database/migrations/2022_08_11_124913_create_tags_table.php deleted file mode 100755 index 06ce750..0000000 --- a/stubs/database/migrations/2022_08_11_124913_create_tags_table.php +++ /dev/null @@ -1,32 +0,0 @@ -id(); - $table->string('name',50); - $table->timestamps(); - }); - } - - /** - * Reverse the migrations. - * - * @return void - */ - public function down() - { - Schema::dropIfExists('tags'); - } -}; diff --git a/stubs/database/migrations/2022_08_11_125433_create_blog_tag_table.php b/stubs/database/migrations/2022_08_11_125433_create_blog_tag_table.php deleted file mode 100755 index cabc555..0000000 --- a/stubs/database/migrations/2022_08_11_125433_create_blog_tag_table.php +++ /dev/null @@ -1,32 +0,0 @@ -id(); - $table->foreignId('blog_id')->nullable()->constrained('blogs')->onDelete('cascade'); - $table->foreignId('tag_id')->nullable()->constrained('tags')->onDelete('cascade'); - }); - } - - /** - * Reverse the migrations. - * - * @return void - */ - public function down() - { - Schema::dropIfExists('blog_tag'); - } -}; diff --git a/stubs/database/seeders/BlogSeeder.php b/stubs/database/seeders/BlogSeeder.php deleted file mode 100644 index b83b787..0000000 --- a/stubs/database/seeders/BlogSeeder.php +++ /dev/null @@ -1,22 +0,0 @@ -count(50) - ->create(); - } -} diff --git a/stubs/database/seeders/TagSeeder.php b/stubs/database/seeders/TagSeeder.php deleted file mode 100755 index d1c20af..0000000 --- a/stubs/database/seeders/TagSeeder.php +++ /dev/null @@ -1,28 +0,0 @@ -delete(); - $tagString = 'Advertising-Advice-Android-Anime-Apple-Architecture-Art-Baking-Beauty-Bible-Blog-Blogging-Book Reviews-Books-Business-Canada-Cars-Cartoons-Celebrities-Celebrity-Children-Christian-Christianity-Comedy-Comics-Cooking-Cosmetics-Crafts-Cuisine-Culinary-Culture-Dating-Design-Diy-Dogs-Drawing-Economy-Education-Entertainment-Environment-Events-Exercise-Faith-Family-Fantasy-Fashion-Fiction-Film-Fitness-Folk-Food-Football-France-Fun-Funny-Gadgets-Games-Gaming-Geek-Google-Gossip-Graphic Design-Green-Health-Hip Hop-History-Home-Home Improvement-Homes-Humor-Humour-Hunting-Illustration-Indie-Inspiration-Interior Design-Internet-Internet Marketing-Iphone-Italy-Kids-Landscape-Law-Leadership-Life-Lifestyle-Literature-London-Love-Management-Marketing-Media-Men-Mobile-Money-Movies-Music-Nature-News-Nutrition-Opinion-Painting-Parenting-Personal-Personal Development-Pets-Philosophy-Photo-Photography-Photos-Pictures-Poetry-Politics-Real Estate-Recipes-Relationships-Religion-Reviews-Running-Sales-Satire-Science-Seo-Sex-Shopping-Soccer-Social Media-Software-Spirituality-Sports-Technology-Television-Tips-Travel-Tutorials-Tv-Uk-Vacation-Video-Videos-Voices.com-Web-Web Design-Weight Loss-Wellness-Wildlife-Wine-Women-Wordpress-Writing'; - $tags = explode('-', $tagString); - foreach ($tags as $key => $tag) { - Tag::create([ - "name" => $tag, - ]); - } - } -} diff --git a/stubs/lang/en/blog.php b/stubs/lang/en/blog.php deleted file mode 100755 index 43bf80a..0000000 --- a/stubs/lang/en/blog.php +++ /dev/null @@ -1,73 +0,0 @@ - 'Dashboard', - 'new_blog_button' => 'New Blog', - 'restore_all_button' => 'Restore All', - 'title' => 'Title', - 'description' => 'Description', - 'published' => 'Published', - 'not_published' => 'Unpublished', - 'actions' => 'Actions', - 'create_blog_title' => 'Create Blog', - 'update_blog_title' => 'Update Blog', - 'index_blog_title' => 'Blogs', - 'submit_button' => 'Submit', - 'back_button' => 'Back', - 'delete_button' => 'Delete', - 'restore_button' => 'Restore', - 'cancel_button' => 'Cancel', - 'approve_button' => 'Approve', - 'reject_button' => 'Reject', - 'confirmation_title' => 'Are you sure?', - 'no_record_found' => 'No record found!!!', - 'delete_description' => 'you want to delete :blogName blog?', - 'restore_description' => 'you want to restore :blogName blog?', - 'approve_description' => 'you want to approve :blogName blog?', - 'reject_description' => 'you want to reject :blogName blog?', - 'restore_all_description' => 'you want to restore all blog?', - 'created_date' => 'Date Created', - 'create_success_message' => 'Blog created successfully!!', - 'update_success_message' => 'Blog updated successfully!!', - 'delete_success_message' => 'Blog deleted successfully!!', - 'restore_success_message' => 'Blog restored successfully!!', - 'error_message' => 'Whoops,Something went wrong!!', - 'change_lang' => 'Language', - 'sr_no' => 'Sr. No', - 'view_blog_title' => 'Blog Detail : :blogName', - 'blog_owner'=> 'Author', - 'all_blogs' => 'Published Blogs', - 'trash_bin_title' => 'Trash Bin', - 'update_status_description' => 'You want to :status :blogName blog?', - 'publish_text' => 'Publish', - 'unpublish_text' => 'Unpublish', - 'change_status_text' => 'Click to change status', - 'permission_denied_error' => 'You do not have permission to perform this action', - 'delete_tooltip' => 'Delete', - 'edit_tooltip' => 'Edit', - 'view_tooltip' => 'View', - 'restore_tooltip' => 'Restore', - 'comment_tooltip' => 'Comment', - 'approve_tooltip' => 'Approved', - 'reject_tooltip' => 'Rejected', - 'pending_tooltip' => 'Pending', - 'on_action_tooltip' => 'Draft', - 'blog_status' => 'Status', - 'want_to_publish' => 'Want to publish blog?', - 'reject_modal_title' => 'Reason:', - 'tags' => 'Tags', - 'no_tags' => 'No Tag', - 'image' => 'Image', -]; diff --git a/stubs/lang/en/comment.php b/stubs/lang/en/comment.php deleted file mode 100755 index f747aab..0000000 --- a/stubs/lang/en/comment.php +++ /dev/null @@ -1,18 +0,0 @@ - 'Comments', - 'comments_reply' => 'Reply', - 'add_comment' => 'Add Comment', -]; diff --git a/stubs/lang/en/validation.php b/stubs/lang/en/validation.php deleted file mode 100644 index cef02f5..0000000 --- a/stubs/lang/en/validation.php +++ /dev/null @@ -1,170 +0,0 @@ - 'The :attribute must be accepted.', - 'accepted_if' => 'The :attribute must be accepted when :other is :value.', - 'active_url' => 'The :attribute is not a valid URL.', - 'after' => 'The :attribute must be a date after :date.', - 'after_or_equal' => 'The :attribute must be a date after or equal to :date.', - 'alpha' => 'The :attribute must only contain letters.', - 'alpha_dash' => 'The :attribute must only contain letters, numbers, dashes and underscores.', - 'alpha_num' => 'The :attribute must only contain letters and numbers.', - 'array' => 'The :attribute must be an array.', - 'before' => 'The :attribute must be a date before :date.', - 'before_or_equal' => 'The :attribute must be a date before or equal to :date.', - 'between' => [ - 'array' => 'The :attribute must have between :min and :max items.', - 'file' => 'The :attribute must be between :min and :max kilobytes.', - 'numeric' => 'The :attribute must be between :min and :max.', - 'string' => 'The :attribute must be between :min and :max characters.', - ], - 'boolean' => 'The :attribute field must be true or false.', - 'confirmed' => 'The :attribute confirmation does not match.', - 'current_password' => 'The password is incorrect.', - 'date' => 'The :attribute is not a valid date.', - 'date_equals' => 'The :attribute must be a date equal to :date.', - 'date_format' => 'The :attribute does not match the format :format.', - 'declined' => 'The :attribute must be declined.', - 'declined_if' => 'The :attribute must be declined when :other is :value.', - 'different' => 'The :attribute and :other must be different.', - 'digits' => 'The :attribute must be :digits digits.', - 'digits_between' => 'The :attribute must be between :min and :max digits.', - 'dimensions' => 'The :attribute has invalid image dimensions.', - 'distinct' => 'The :attribute field has a duplicate value.', - 'doesnt_start_with' => 'The :attribute may not start with one of the following: :values.', - 'email' => 'The :attribute must be a valid email address.', - 'ends_with' => 'The :attribute must end with one of the following: :values.', - 'enum' => 'The selected :attribute is invalid.', - 'exists' => 'The selected :attribute is invalid.', - 'file' => 'The :attribute must be a file.', - 'filled' => 'The :attribute field must have a value.', - 'gt' => [ - 'array' => 'The :attribute must have more than :value items.', - 'file' => 'The :attribute must be greater than :value kilobytes.', - 'numeric' => 'The :attribute must be greater than :value.', - 'string' => 'The :attribute must be greater than :value characters.', - ], - 'gte' => [ - 'array' => 'The :attribute must have :value items or more.', - 'file' => 'The :attribute must be greater than or equal to :value kilobytes.', - 'numeric' => 'The :attribute must be greater than or equal to :value.', - 'string' => 'The :attribute must be greater than or equal to :value characters.', - ], - 'image' => 'The :attribute must be an image.', - 'in' => 'The selected :attribute is invalid.', - 'in_array' => 'The :attribute field does not exist in :other.', - 'integer' => 'The :attribute must be an integer.', - 'ip' => 'The :attribute must be a valid IP address.', - 'ipv4' => 'The :attribute must be a valid IPv4 address.', - 'ipv6' => 'The :attribute must be a valid IPv6 address.', - 'json' => 'The :attribute must be a valid JSON string.', - 'lt' => [ - 'array' => 'The :attribute must have less than :value items.', - 'file' => 'The :attribute must be less than :value kilobytes.', - 'numeric' => 'The :attribute must be less than :value.', - 'string' => 'The :attribute must be less than :value characters.', - ], - 'lte' => [ - 'array' => 'The :attribute must not have more than :value items.', - 'file' => 'The :attribute must be less than or equal to :value kilobytes.', - 'numeric' => 'The :attribute must be less than or equal to :value.', - 'string' => 'The :attribute must be less than or equal to :value characters.', - ], - 'mac_address' => 'The :attribute must be a valid MAC address.', - 'max' => [ - 'array' => 'The :attribute must not have more than :max items.', - 'file' => 'The :attribute must not be greater than :max kilobytes.', - 'numeric' => 'The :attribute must not be greater than :max.', - 'string' => 'The :attribute must not be greater than :max characters.', - ], - 'mimes' => 'The :attribute must be a file of type: :values.', - 'mimetypes' => 'The :attribute must be a file of type: :values.', - 'min' => [ - 'array' => 'The :attribute must have at least :min items.', - 'file' => 'The :attribute must be at least :min kilobytes.', - 'numeric' => 'The :attribute must be at least :min.', - 'string' => 'The :attribute must be at least :min characters.', - ], - 'multiple_of' => 'The :attribute must be a multiple of :value.', - 'not_in' => 'The selected :attribute is invalid.', - 'not_regex' => 'The :attribute format is invalid.', - 'numeric' => 'The :attribute must be a number.', - 'password' => [ - 'letters' => 'The :attribute must contain at least one letter.', - 'mixed' => 'The :attribute must contain at least one uppercase and one lowercase letter.', - 'numbers' => 'The :attribute must contain at least one number.', - 'symbols' => 'The :attribute must contain at least one symbol.', - 'uncompromised' => 'The given :attribute has appeared in a data leak. Please choose a different :attribute.', - ], - 'present' => 'The :attribute field must be present.', - 'prohibited' => 'The :attribute field is prohibited.', - 'prohibited_if' => 'The :attribute field is prohibited when :other is :value.', - 'prohibited_unless' => 'The :attribute field is prohibited unless :other is in :values.', - 'prohibits' => 'The :attribute field prohibits :other from being present.', - 'regex' => 'The :attribute format is invalid.', - 'required' => 'The :attribute field is required.', - 'required_array_keys' => 'The :attribute field must contain entries for: :values.', - 'required_if' => 'The :attribute field is required when :other is :value.', - 'required_unless' => 'The :attribute field is required unless :other is in :values.', - 'required_with' => 'The :attribute field is required when :values is present.', - 'required_with_all' => 'The :attribute field is required when :values are present.', - 'required_without' => 'The :attribute field is required when :values is not present.', - 'required_without_all' => 'The :attribute field is required when none of :values are present.', - 'same' => 'The :attribute and :other must match.', - 'size' => [ - 'array' => 'The :attribute must contain :size items.', - 'file' => 'The :attribute must be :size kilobytes.', - 'numeric' => 'The :attribute must be :size.', - 'string' => 'The :attribute must be :size characters.', - ], - 'starts_with' => 'The :attribute must start with one of the following: :values.', - 'string' => 'The :attribute must be a string.', - 'timezone' => 'The :attribute must be a valid timezone.', - 'unique' => 'The :attribute has already been taken.', - 'uploaded' => 'The :attribute failed to upload.', - 'url' => 'The :attribute must be a valid URL.', - 'uuid' => 'The :attribute must be a valid UUID.', - - /* - |-------------------------------------------------------------------------- - | Custom Validation Language Lines - |-------------------------------------------------------------------------- - | - | Here you may specify custom validation messages for attributes using the - | convention "attribute.rule" to name the lines. This makes it quick to - | specify a specific custom language line for a given attribute rule. - | - */ - - 'custom' => [ - 'attribute-name' => [ - 'rule-name' => 'custom-message', - ], - ], - - /* - |-------------------------------------------------------------------------- - | Custom Validation Attributes - |-------------------------------------------------------------------------- - | - | The following language lines are used to swap our attribute placeholder - | with something more reader friendly such as "E-Mail Address" instead - | of "email". This simply helps us make our message more expressive. - | - */ - - 'attributes' => [], - -]; diff --git a/stubs/lang/fr/blog.php b/stubs/lang/fr/blog.php deleted file mode 100755 index ea56f9a..0000000 --- a/stubs/lang/fr/blog.php +++ /dev/null @@ -1,73 +0,0 @@ - 'Tableau de bord', - 'new_blog_button' => 'Nouveau blog', - 'restore_all_button' => 'Tout restaurer', - 'title' => 'Titre', - 'description' => 'Description', - 'published' => 'Publié', - 'not_published' => 'Non publié', - 'actions' => 'Actions', - 'create_blog_title' => 'Créer un blog', - 'update_blog_title' => 'Mettre à jour le blog', - 'index_blog_title' => 'Blogs', - 'submit_button' => 'Soumettre', - 'back_button' => 'Retour', - 'delete_button' => 'Supprimer', - 'restore_button' => 'Restaurer', - 'cancel_button' => 'Annuler', - 'approve_button' => 'approuver', - 'reject_button' => 'Rejeter', - 'confirmation_title' => 'Êtes-vous sûr ?', - 'no_record_found' => 'Aucun Enregistrement Trouvé!!!', - 'delete_description' => 'vous voulez supprimer le blog :blogName ?', - 'restore_description' => 'vous voulez Restaurer le blog :blogName ?', - 'approve_description' => 'vous voulez approuver le blog:blogName ?', - 'reject_description' => 'vous voulez rejeter le blog:blogName ?', - 'restore_all_description' => 'vous voulez restaurer tout le blog ?', - 'created_date' => 'date créée', - 'create_success_message' => 'Blog créé avec succès !!', - 'update_success_message' => 'Blog mis à jour avec succès !!', - 'delete_success_message' => 'Blog supprimé avec succès !!', - 'restore_success_message' => 'Blog restauré avec succès !!', - 'error_message' => 'Oup\',Quelque chose s\'est mal passé !!', - 'change_lang' => 'Langue', - 'sr_no' => 'Sr non', - 'view_blog_title' => 'Détail du blog : :blogName', - 'blog_owner'=> 'Auteur', - 'all_blogs' => 'Blogues publiés', - 'trash_bin_title' => 'Corbeille', - 'update_status_description' => 'Vous voulez :status :blogName blog ?', - 'publish_text' => 'Publier', - 'unpublish_text' => 'Dépublier', - 'change_status_text' => 'cliquez pour changer de statut', - 'permission_denied_error' => 'Vous n\'êtes pas autorisé à effectuer cette action', - 'delete_tooltip' => 'Supprimer', - 'edit_tooltip' => 'Modifier', - 'view_tooltip' => 'Voir', - 'restore_tooltip' => 'Restaurer', - 'comment_tooltip' => 'Commentaire', - 'approve_tooltip' => 'Approuvée', - 'reject_tooltip' => 'rejetée', - 'pending_tooltip' => 'En attente', - 'on_action_tooltip' => 'Brouillon', - 'blog_status' => 'Statut', - 'want_to_publish' => 'Vous voulez publier un blog ?', - 'reject_modal_title' => 'Raison:', - 'tags' => 'Mots clés', - 'no_tags' => 'pas de balises', - 'image' => 'Image', -]; diff --git a/stubs/lang/fr/comment.php b/stubs/lang/fr/comment.php deleted file mode 100755 index cb81def..0000000 --- a/stubs/lang/fr/comment.php +++ /dev/null @@ -1,18 +0,0 @@ - 'Commentaires', - 'comments_reply' => 'Répondre', - 'add_comment' => 'Ajouter un commentaire', -]; diff --git a/stubs/lang/fr/validation.php b/stubs/lang/fr/validation.php deleted file mode 100644 index b592273..0000000 --- a/stubs/lang/fr/validation.php +++ /dev/null @@ -1,169 +0,0 @@ - 'L\':attribute doit être accepté.', - 'accepted_if' => 'L\' :attribut doit être accepté lorsque :other vaut :value.', - 'active_url' => 'L\' :attribut n\'est pas une URL valide.', - 'after' => 'Le :attribute doit être une date postérieure à :date.', - 'after_or_equal' => 'Le :attribute doit être une date postérieure ou égale à :date.', - 'alpha' => 'Le :attribut ne doit contenir que des lettres.', - 'alpha_dash' => 'Le :attribut ne doit contenir que des lettres, des chiffres, des tirets et des traits de soulignement.', - 'alpha_num' => 'Le :attribut ne doit contenir que des lettres et des chiffres.', - 'array' => 'Le :attribut doit être un tableau.', - 'before' => 'Le :attribut doit être une date avant :date.', - 'before_or_equal' => 'Le :attribute doit être une date antérieure ou égale à :date.', - 'between' => [ - 'array' => 'Le :attribute doit avoir entre :min et :max éléments.', - 'file' => 'Le :attribute doit être compris entre :min et :max kilo-octets.', - 'numeric' => 'Le :attribute doit être compris entre :min et :max.', - 'string' => 'Le :attribute doit être compris entre :min et :max caractères.', - ], - 'boolean' => 'Le champ :attribute doit être vrai ou faux.', - 'confirmed' => 'La confirmation :attribute ne correspond pas.', - 'current_password' => 'Le mot de passe est incorrect.', - 'date' => 'Le :attribut n\'est pas une date valide.', - 'date_equals' => 'Le :attribut doit être une date égale à :date.', - 'date_format' => 'Le :attribut ne correspond pas au format :format.', - 'declined' => 'Le :attribute doit être refusé.', - 'declined_if' => 'Le :attribute doit être refusé lorsque :other vaut :value.', - 'different' => 'Le :attribute et :other doivent être différents.', - 'digits' => 'Le :attribut doit être :digits chiffres.', - 'digits_between' => 'Le :attribut doit être compris entre :min et :max chiffres.', - 'dimensions' => 'L\' :attribut a des dimensions d\'image invalides.', - 'distinct' => 'Le champ :attribute a une valeur en double.', - 'doesnt_start_with' => 'Le :attribute ne peut pas commencer par l\'un des éléments suivants : :values.', - 'email' => 'Le :attribute doit être une adresse e-mail valide.', - 'ends_with' => 'Le :attribute doit se terminer par l\'un des éléments suivants : :values.', - 'enum' => 'L\'attribut sélectionné n\'est pas valide.', - 'exists' => 'L\'attribut sélectionné n\'est pas valide.', - 'file' => 'Le :attribute doit être un fichier.', - 'filled' => 'Le champ :attribute doit avoir une valeur.', - 'gt' => [ - 'array' => 'Le :attribute doit avoir plus de :value éléments.', - 'file' => 'Le :attribute doit être supérieur à :value kilo-octets.', - 'numeric' => 'Le :attribut doit être supérieur à :valeur.', - 'string' => 'Le :attribut doit être supérieur à :value caractères.', - ], - 'gte' => [ - 'array' => 'Le :attribute doit avoir des éléments :value ou plus.', - 'file' => 'Le :attribute doit être supérieur ou égal à :value kilo-octets.', - 'numeric' => 'Le :attribut doit être supérieur ou égal à :value.', - 'string' => 'Le :attribut doit être supérieur ou égal à :value caractères.', - ], - 'image' => 'Le :attribute doit être une image.', - 'in' => 'L\'attribut sélectionné n\'est pas valide.', - 'in_array' => 'Le champ :attribute n\'existe pas dans :other.', - 'integer' => 'Le :attribut doit être un entier.', - 'ip' => 'Le :attribute doit être une adresse IP valide.', - 'ipv4' => 'Le :attribute doit être une adresse IPv4 valide.', - 'ipv6' => 'Le :attribute doit être une adresse IPv6 valide.', - 'json' => 'Le :attribute doit être une chaîne JSON valide.', - 'lt' => [ - 'array' => 'Le :attribute doit avoir moins de :value éléments.', - 'file' => 'Le :attribute doit être inférieur à :value kilo-octets.', - 'numeric' => 'Le :attribut doit être inférieur à :value.', - 'string' => 'Le :attribute doit être inférieur à :value caractères.', - ], - 'lte' => [ - 'array' => 'Le :attribut ne doit pas avoir plus de :value éléments.', - 'file' => 'Le :attribute doit être inférieur ou égal à :value kilo-octets.', - 'numeric' => 'Le :attribut doit être inférieur ou égal à :value.', - 'string' => 'Le :attribut doit être inférieur ou égal à :value caractères.', - ], - 'mac_address' => 'Le :attribute doit être une adresse MAC valide.', - 'max' => [ - 'array' => 'Le :attribut ne doit pas avoir plus de :max éléments.', - 'file' => 'Le :attribute ne doit pas être supérieur à :max kilo-octets.', - 'numeric' => 'Le :attribute ne doit pas être supérieur à :max.', - 'string' => 'Le :attribut ne doit pas être supérieur à :max caractères.', - ], - 'mimes' => 'Le :attribute doit être un fichier de type : :values.', - 'mimetypes' => 'Le :attribute doit être un fichier de type : :values.', - 'min' => [ - 'array' => 'Le :attribute doit avoir au moins :min éléments.', - 'file' => 'Le :attribute doit faire au moins :min kilo-octets.', - 'numeric' => 'Le :attribut doit être au moins égal à :min.', - 'string' => 'Le :attribute doit contenir au moins :min caractères.', - ], - 'multiple_of' => 'Le :attribut doit être un multiple de :value.', - 'not_in' => 'L\'attribut sélectionné n\'est pas valide.', - 'not_regex' => 'Le format :attribute est invalide.', - 'numeric' => 'Le :attribute doit être un nombre.', - 'password' => [ - 'letters' => 'Le :attribute doit contenir au moins une lettre.', - 'mixed' => 'Le :attribute doit contenir au moins une lettre majuscule et une lettre minuscule.', - 'numbers' => 'Le :attribute doit contenir au moins un nombre.', - 'symbols' => 'Le :attribute doit contenir au moins un symbole.', - 'uncompromised' => 'L\'attribut :donné est apparu dans une fuite de données. Veuillez choisir un autre :attribut.', - ], - 'present' => 'Le champ :attribute doit être présent.', - 'prohibited' => 'Le champ :attribute est interdit.', - 'prohibited_if' => 'Le champ :attribute est interdit lorsque :other vaut :value.', - 'prohibited_unless' => 'Le champ :attribute est interdit sauf si :other est dans :values.', - 'prohibits' => 'Le champ :attribute interdit la présence de :other.', - 'regex' => 'Le format :attribute n\'est pas valide.', - 'required' => 'Le champ :attribute est obligatoire.', - 'required_array_keys' => 'Le champ :attribute doit contenir des entrées pour : :values.', - 'required_if' => 'Le champ :attribute est obligatoire lorsque :other vaut :value.', - 'required_unless' => 'Le champ :attribute est obligatoire sauf si :other est dans :values.', - 'required_with' => 'Le champ :attribute est obligatoire lorsque :values ​​est présent.', - 'required_with_all' => 'Le champ :attribute est obligatoire lorsque :des valeurs sont présentes.', - 'required_without' => 'Le champ :attribute est requis lorsque :values ​​n\'est pas présent.', - 'required_without_all' => 'Le champ :attribute est requis lorsqu\'aucune des :values ​​n\'est présente.', - 'same' => 'Le :attribute et :other doivent correspondre.', - 'size' => [ - 'array' => 'Le :attribut doit contenir des éléments :size.', - 'file' => 'Le :attribut doit être :size kilo-octets.', - 'numeric' => 'Le :attribut doit être :size.', - 'string' => 'Le :attribut doit être composé de :size caractères.', - ], - 'starts_with' => 'Le :attribute doit commencer par l\'un des éléments suivants : :values.', - 'string' => 'Le :attribute doit être une chaîne.', - 'timezone' => 'L\' :attribut doit être un fuseau horaire valide.', - 'unique' => 'L\':attribut a déjà été pris.', - 'uploaded' => 'Le :attribut n\'a pas pu être téléchargé.', - 'url' => 'Le :attribute doit être une URL valide.', - 'uuid' => 'Le :attribute doit être un UUID valide.', - - /* - |-------------------------------------------------------------------------- - | Custom Validation Language Lines - |-------------------------------------------------------------------------- - | - | Here you may specify custom validation messages for attributes using the - | convention "attribute.rule" to name the lines. This makes it quick to - | specify a specific custom language line for a given attribute rule. - | - */ - - 'custom' => [ - 'attribute-name' => [ - 'rule-name' => 'custom-message', - ], - ], - - /* - |-------------------------------------------------------------------------- - | Custom Validation Attributes - |-------------------------------------------------------------------------- - | - | The following language lines are used to swap our attribute placeholder - | with something more reader friendly such as "E-Mail Address" instead - | of "email". This simply helps us make our message more expressive. - | - */ - - 'attributes' => [], -]; diff --git a/stubs/lang/hi/blog.php b/stubs/lang/hi/blog.php deleted file mode 100755 index f6b16c4..0000000 --- a/stubs/lang/hi/blog.php +++ /dev/null @@ -1,73 +0,0 @@ - 'डैशबोर्ड', - 'new_blog_button' => 'नया ब्लॉग', - 'restore_all_button' => 'सभी पुनर्स्थापित करो', - 'title' => 'शीर्षक', - 'description' => 'विवरण', - 'published' => 'प्रकाशित', - 'not_published' => 'अप्रकाशित', - 'actions' => 'क्रियाएँ', - 'create_blog_title' => 'ब्लॉग बनाएँ', - 'update_blog_title' => 'ब्लॉग अपडेट करें', - 'index_blog_title' => 'ब्लॉग', - 'submit_button' => 'सबमिट', - 'back_button' => 'बैक', - 'delete_button' => 'डिलीट', - 'restore_button' => 'रिस्टोर', - 'cancel_button' => 'रद्द करें', - 'approve_button' => 'मंज़ूरी देना', - 'reject_button' => 'अस्वीकार', - 'confirmation_title' => 'क्या आप निश्चित हैं?', - 'no_record_found' => 'कोई रिकॉर्ड नहीं मिला!!!', - 'delete_description' => 'आप :blogName ब्लॉग को हटाना चाहते हैं?', - 'restore_description' => 'आप :blogName ब्लॉग को पुनर्स्थापित करना चाहते हैं?', - 'approve_description' => 'आप :blogName ब्लॉग को स्वीकृत करना चाहते हैं ?', - 'reject_description' => 'आप :blogName ब्लॉग को अस्वीकार करना चाहते हैं?', - 'restore_all_description' => 'आप सभी ब्लॉग को पुनर्स्थापित करना चाहते हैं?', - 'created_date' => 'बनाई गई तिथि', - 'create_success_message' => 'ब्लॉग सफलतापूर्वक बनाया गया !!', - 'update_success_message' => 'ब्लॉग सफलतापूर्वक अपडेट किया गया !!', - 'delete_success_message' => 'ब्लॉग सफलतापूर्वक हटा दिया गया !!', - 'restore_success_message' => 'ब्लॉग सफलतापूर्वक पुनर्स्थापित किया गया !!', - 'error_message' => 'वूप\', कुछ गलत हो गया !!', - 'change_lang' => 'भाषा', - 'sr_no' => 'अनु क्रमांक', - 'view_blog_title' => 'ब्लॉग विवरण : :blogName', - 'blog_owner'=> 'लेखक', - 'all_blogs' => 'प्रकाशित ब्लॉग', - 'trash_bin_title' => 'ट्रैश बिन', - 'update_status_description' => 'आप :blogName ब्लॉग :status करना चाहते हैं ?', - 'publish_text' => 'प्रकाशित', - 'unpublish_text' => 'अप्रकाशित', - 'change_status_text' => 'स्थिति बदलने के लिए क्लिक करें', - 'permission_denied_error' => 'आपको यह क्रिया करने की अनुमति नहीं है', - 'delete_tooltip' => 'डिलीट', - 'edit_tooltip' => 'संपादित करें', - 'view_tooltip' => 'व्यू', - 'restore_tooltip' => 'रिस्टोर', - 'comment_tooltip' => 'टिप्पणी', - 'approve_tooltip' => 'स्वीकृत', - 'reject_tooltip' => 'अस्वीकृत', - 'pending_tooltip' => 'लंबित', - 'on_action_tooltip' => 'ड्राफ्ट', - 'blog_status' => 'स्थिति', - 'want_to_publish' => 'ब्लॉग प्रकाशित करना चाहते हैं?', - 'reject_modal_title' => 'कारण:', - 'tags' => 'टैग', - 'no_tags' => 'कोई टैग नहीं', - 'image' => 'छवि', -]; diff --git a/stubs/lang/hi/comment.php b/stubs/lang/hi/comment.php deleted file mode 100755 index a6d6aa7..0000000 --- a/stubs/lang/hi/comment.php +++ /dev/null @@ -1,18 +0,0 @@ - 'टिप्पणियाँ', - 'comments_reply' => 'जवाब दें', - 'add_comment' => 'टिप्पणी जोड़ें', -]; diff --git a/stubs/lang/hi/validation.php b/stubs/lang/hi/validation.php deleted file mode 100755 index 4ebd724..0000000 --- a/stubs/lang/hi/validation.php +++ /dev/null @@ -1,168 +0,0 @@ - ':attribute को स्वीकार किया जाना चाहिए।', - 'accepted_if' => 'द :attribute तभी स्वीकार किया जाना चाहिए जब :other is :value।', - 'active_url' => ':attribute एक मान्य URL नहीं है।', - 'after' => 'द :attribute :date के बाद की तारीख होनी चाहिए।', - 'after_or_equal' => ':attribute :date के बाद या उसके बराबर की तारीख होनी चाहिए।', - 'alpha' => 'द :attribute में केवल अक्षर होने चाहिए।', - 'alpha_dash' => ':attribute में केवल अक्षर, संख्याएं, डैश और अंडरस्कोर होने चाहिए।', - 'alpha_num' => 'इस :attribute में केवल अक्षर और अंक होने चाहिए।', - 'array' => ':attribute एक सरणी होनी चाहिए।', - 'before' => 'The :attribute :date पहले की तारीख होनी चाहिए।', - 'before_or_equal' => ':attribute :date से पहले या उसके बराबर की तारीख होनी चाहिए।', - 'between' => [ - 'array' => ':attribute :min और :max आइटम के बीच होनी चाहिए।', - 'file' => ':attribute :min और :max किलोबाइट के बीच होनी चाहिए।', - 'numeric' => 'द :attribute :min और :max के बीच होना चाहिए।', - 'string' => 'द :attribute :min और :max कैरेक्टर्स के बीच होना चाहिए।', - ], - 'boolean' => ':attribute फ़ील्ड सही या गलत होना चाहिए।', - 'confirmed' => 'द :attribute कन्फर्मेशन मेल नहीं खाता।', - 'current_password' => 'पासवर्ड गलत है।', - 'date' => 'द :attribute वैध तारीख नहीं है।', - 'date_equals' => 'द :attribute :date के बराबर एक तारीख होनी चाहिए।', - 'date_format' => 'द :attribute :format के फॉर्मेट से मेल नहीं खाता।', - 'declined' => 'द :attribute को अस्वीकार किया जाना चाहिए।', - 'declined_if' => ': जब :other is :value हो तो :attribute को अस्वीकार कर दिया जाना चाहिए।', - 'different' => 'द :attribute और :other अलग-अलग होने चाहिए।', - 'digits' => 'The :attribute :digits के अंक होने चाहिए।', - 'digits_between' => ':attribute :min और :max अंकों के बीच होनी चाहिए।', - 'dimensions' => 'द :attribute का इमेज डाइमेंशन अमान्य है।', - 'distinct' => ':attribute फ़ील्ड में एक डुप्लिकेट :values है।', - 'doesnt_start_with' => ':attribute निम्न में से किसी एक के साथ शुरू नहीं हो सकती है: :values', - 'email' => 'द:attribute एक वैध ईमेल पता होना चाहिए।', - 'ends_with' => ':attribute निम्न में से किसी एक के साथ समाप्त होनी चाहिए: :values।', - 'enum' => 'चयनित :attribute अमान्य है।', - 'exists' => 'चयनित :attribute अमान्य है।', - 'file' => 'द :attribute एक फाइल होना चाहिए।', - 'filled' => 'द :attribute फील्ड में एक मान होना चाहिए।', - 'gt' => [ - 'array' => 'द :attribute में :value आइटम्स से अधिक होना चाहिए।', - 'file' => 'द :attribute :value किलोबाइट्स से बड़ा होना चाहिए।', - 'numeric' => 'द :attribute :value से बड़ा होना चाहिए।', - 'string' => 'द :attribute :value कैरेक्टर्स से बड़ा होना चाहिए।', - ], - 'gte' => [ - 'array' => 'द :attribute में :value आइटम्स या अधिक होना चाहिए।', - 'file' => 'द :attribute :value किलोबाइट्स से बड़ा या उसके बराबर होना चाहिए।', - 'numeric' => ':attribute :value से अधिक या उसके बराबर होनी चाहिए।', - 'string' => 'द :attribute :value कैरेक्टर से बड़ा या उसके बराबर होना चाहिए।', - ], - 'image' => ':attribute एक छवि होनी चाहिए।', - 'in' => 'चयनित :attribute अमान्य है।', - 'in_array' => 'द :attribute फील्ड :other में मौजूद नहीं है।', - 'integer' => ':attribute एक पूर्णांक होना चाहिए।', - 'ip' => 'द :attribute एक वैध IP पता होना चाहिए।', - 'ipv4' => ':attribute एक मान्य IPv4 पता होना चाहिए।', - 'ipv6' => ':attribute एक मान्य IPv6 पता होना चाहिए।', - 'json' => 'द :attribute एक मान्य JSON स्ट्रिंग होनी चाहिए।', - 'lt' => [ - 'array' => 'द :attribute में :value आइटम्स से कम होना चाहिए।', - 'file' => ':attribute :value किलोबाइट से कम होनी चाहिए।', - 'numeric' => 'द :attribute :value से कम होनी चाहिए।', - 'string' => 'द :attribute :value कैरेक्टर्स से कम होना चाहिए।', - ], - 'lte' => [ - 'array' => 'द :attribute में :value आइटम्स से अधिक नहीं होना चाहिए।', - 'file' => ':attribute :value किलोबाइट से कम या उसके बराबर होनी चाहिए।', - 'numeric' => 'द :attribute :value से कम या उसके बराबर होनी चाहिए।', - 'string' => 'द :attribute :value कैरेक्टर से कम या उसके बराबर होना चाहिए।', - ], - 'mac_address' => ':attribute एक वैध MAC पता होना चाहिए।', - 'max' => [ - 'array' => ':attribute में :max आइटम से अधिक नहीं होना चाहिए।', - 'file' => ':attribute :max किलोबाइट से अधिक नहीं होनी चाहिए।', - 'numeric' => ':attribute :max से अधिक नहीं होनी चाहिए।', - 'string' => ':attribute :max वर्णों से अधिक नहीं होनी चाहिए।', - ], - 'mimes' => 'द :attribute एक प्रकार की फाइल होनी चाहिए: :values।', - 'mimetypes' => 'द :attribute एक प्रकार की फाइल होनी चाहिए: :values।', - 'min' => [ - 'array' => 'द :attribute में कम से कम :min आइटम्स होने चाहिए।', - 'file' => 'द :attribute कम से कम :min किलोबाइट्स होना चाहिए।', - 'numeric' => ':attribute कम से कम :min होनी चाहिए।', - 'string' => 'द :attribute कम से कम :min कैरेक्टर का होना चाहिए।', - ], - 'multiple_of' => 'द :attribute :value का गुणज होना चाहिए।', - 'not_in' => 'चयनित :attribute अमान्य है।', - 'not_regex' => ':attribute प्रारूप अमान्य है।', - 'numeric' => ':attribute एक संख्या होनी चाहिए।', - 'password' => [ - 'letters' => ':attribute में कम से कम एक अक्षर होना चाहिए।', - 'mixed' => ':attribute में कम से कम एक अपरकेस और एक लोअरकेस अक्षर होना चाहिए।', - 'numbers' => 'The :attribute में कम से कम एक नंबर होना चाहिए।', - 'symbols' => 'द :attribute में कम से कम एक सिंबल होना चाहिए।', - 'uncompromised' => 'दिया गया :attribute डेटा लीक में प्रकट हुई है। कृपया कोई भिन्न :attribute चुनें।', - ], - 'present' => 'द :attribute क्षेत्र अवश्य मौजूद होना चाहिए।', - 'prohibited' => 'द :attribute फील्ड निषिद्ध है।', - 'prohibited_if' => ':attribute फ़ील्ड निषिद्ध है जब :other में :value।', - 'prohibited_unless' => ':attribute क्षेत्र तब तक निषिद्ध है जब तक :other :value में न हो।', - 'prohibits' => 'द :attribute फील्ड :other को उपस्थित होने से रोकता है।', - 'regex' => ':attribute प्रारूप अमान्य है।', - 'required' => 'द :attribute फ़ील्ड की आवश्यकता है।', - 'required_array_keys' => ':attribute फ़ील्ड में निम्न के लिए प्रविष्टियाँ होनी चाहिए: :values।', - 'required_if' => 'द :attribute फील्ड की जरूरत तब पड़ती है जब :other में :value।', - 'required_unless' => 'द :attribute फील्ड तब तक जरूरी है जब तक :other :values ​​में न हो।', - 'required_with' => 'द :attribute फील्ड की जरूरत तब पड़ती है जब :values ​​मौजूद हो।', - 'required_with_all' => 'जब :values ​​मौजूद हों तो :attribute फ़ील्ड आवश्यक है।', - 'required_without' => 'जब :values ​​मौजूद नहीं है, तब :attribute फ़ील्ड की आवश्यकता होती है।', - 'required_without_all' => 'जब कोई भी :values ​​मौजूद न हो तो :attribute फ़ील्ड की आवश्यकता होती है।', - 'same' => 'The :attribute और :other का मिलान होना चाहिए।', - 'size' => [ - 'array' => 'द :attribute में :size आइटम्स होने चाहिए।', - 'file' => 'द :attribute :size किलोबाइट्स होना चाहिए।', - 'numeric' => 'द :attribute :size होना चाहिए।', - 'string' => 'द :attribute :size कैरेक्टर होना चाहिए।', - ], - 'starts_with' => ':attribute निम्न में से किसी एक से शुरू होनी चाहिए: :values।', - 'string' => 'द :attribute एक स्ट्रिंग होना चाहिए।', - 'timezone' => 'द :attribute एक मान्य टाइमज़ोन होना चाहिए।', - 'unique' => 'The :attribute पहले ही लिया जा चुका है।', - 'uploaded' => 'The :attribute अपलोड करने में विफल रहा।', - 'url' => ':attribute एक मान्य URL होना चाहिए।', - 'uuid' => 'द :attribute एक मान्य UUID होना चाहिए।', - /* - |-------------------------------------------------------------------------- - | Custom Validation Language Lines - |-------------------------------------------------------------------------- - | - | Here you may specify custom validation messages for attributes using the - | convention "attribute.rule" to name the lines. This makes it quick to - | specify a specific custom language line for a given attribute rule. - | - */ - - 'custom' => [ - 'attribute-name' => [ - 'rule-name' => 'custom-message', - ], - ], - - /* - |-------------------------------------------------------------------------- - | Custom Validation Attributes - |-------------------------------------------------------------------------- - | - | The following language lines are used to swap our attribute placeholder - | with something more reader friendly such as "E-Mail Address" instead - | of "email". This simply helps us make our message more expressive. - | - */ - - 'attributes' => [], - -]; diff --git a/stubs/resources/css/app.css b/stubs/resources/css/app.css deleted file mode 100755 index e97f611..0000000 --- a/stubs/resources/css/app.css +++ /dev/null @@ -1,1758 +0,0 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; -/* -! tailwindcss v3.1.3 | MIT License | https://tailwindcss.com -*//* -1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4) -2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116) -*/ - -*, -::before, -::after { - box-sizing: border-box; /* 1 */ - border-width: 0; /* 2 */ - border-style: solid; /* 2 */ - border-color: #e5e7eb; /* 2 */ -} - -::before, -::after { - --tw-content: ''; -} - -/* -1. Use a consistent sensible line-height in all browsers. -2. Prevent adjustments of font size after orientation changes in iOS. -3. Use a more readable tab size. -4. Use the user's configured `sans` font-family by default. -*/ - -html { - line-height: 1.5; /* 1 */ - -webkit-text-size-adjust: 100%; /* 2 */ - -moz-tab-size: 4; /* 3 */ - -o-tab-size: 4; - tab-size: 4; /* 3 */ - font-family: Nunito, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; /* 4 */ -} - -/* -1. Remove the margin in all browsers. -2. Inherit line-height from `html` so users can set them as a class directly on the `html` element. -*/ - -body { - margin: 0; /* 1 */ - line-height: inherit; /* 2 */ -} - -/* -1. Add the correct height in Firefox. -2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655) -3. Ensure horizontal rules are visible by default. -*/ - -hr { - height: 0; /* 1 */ - color: inherit; /* 2 */ - border-top-width: 1px; /* 3 */ -} - -/* -Add the correct text decoration in Chrome, Edge, and Safari. -*/ - -abbr:where([title]) { - -webkit-text-decoration: underline dotted; - text-decoration: underline dotted; -} - -/* -Remove the default font size and weight for headings. -*/ - -h1, -h2, -h3, -h4, -h5, -h6 { - font-size: inherit; - font-weight: inherit; -} - -/* -Reset links to optimize for opt-in styling instead of opt-out. -*/ - -a { - color: inherit; - text-decoration: inherit; -} - -/* -Add the correct font weight in Edge and Safari. -*/ - -b, -strong { - font-weight: bolder; -} - -/* -1. Use the user's configured `mono` font family by default. -2. Correct the odd `em` font sizing in all browsers. -*/ - -code, -kbd, -samp, -pre { - font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; /* 1 */ - font-size: 1em; /* 2 */ -} - -/* -Add the correct font size in all browsers. -*/ - -small { - font-size: 80%; -} - -/* -Prevent `sub` and `sup` elements from affecting the line height in all browsers. -*/ - -sub, -sup { - font-size: 75%; - line-height: 0; - position: relative; - vertical-align: baseline; -} - -sub { - bottom: -0.25em; -} - -sup { - top: -0.5em; -} - -/* -1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297) -2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016) -3. Remove gaps between table borders by default. -*/ - -table { - text-indent: 0; /* 1 */ - border-color: inherit; /* 2 */ - border-collapse: collapse; /* 3 */ -} - -/* -1. Change the font styles in all browsers. -2. Remove the margin in Firefox and Safari. -3. Remove default padding in all browsers. -*/ - -button, -input, -optgroup, -select, -textarea { - font-family: inherit; /* 1 */ - font-size: 100%; /* 1 */ - font-weight: inherit; /* 1 */ - line-height: inherit; /* 1 */ - color: inherit; /* 1 */ - margin: 0; /* 2 */ - padding: 0; /* 3 */ -} - -/* -Remove the inheritance of text transform in Edge and Firefox. -*/ - -button, -select { - text-transform: none; -} - -/* -1. Correct the inability to style clickable types in iOS and Safari. -2. Remove default button styles. -*/ - -button, -[type='button'], -[type='reset'], -[type='submit'] { - -webkit-appearance: button; /* 1 */ - background-color: transparent; /* 2 */ - background-image: none; /* 2 */ -} - -/* -Use the modern Firefox focus style for all focusable elements. -*/ - -:-moz-focusring { - outline: auto; -} - -/* -Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737) -*/ - -:-moz-ui-invalid { - box-shadow: none; -} - -/* -Add the correct vertical alignment in Chrome and Firefox. -*/ - -progress { - vertical-align: baseline; -} - -/* -Correct the cursor style of increment and decrement buttons in Safari. -*/ - -::-webkit-inner-spin-button, -::-webkit-outer-spin-button { - height: auto; -} - -/* -1. Correct the odd appearance in Chrome and Safari. -2. Correct the outline style in Safari. -*/ - -[type='search'] { - -webkit-appearance: textfield; /* 1 */ - outline-offset: -2px; /* 2 */ -} - -/* -Remove the inner padding in Chrome and Safari on macOS. -*/ - -::-webkit-search-decoration { - -webkit-appearance: none; -} - -/* -1. Correct the inability to style clickable types in iOS and Safari. -2. Change font properties to `inherit` in Safari. -*/ - -::-webkit-file-upload-button { - -webkit-appearance: button; /* 1 */ - font: inherit; /* 2 */ -} - -/* -Add the correct display in Chrome and Safari. -*/ - -summary { - display: list-item; -} - -/* -Removes the default spacing and border for appropriate elements. -*/ - -blockquote, -dl, -dd, -h1, -h2, -h3, -h4, -h5, -h6, -hr, -figure, -p, -pre { - margin: 0; -} - -fieldset { - margin: 0; - padding: 0; -} - -legend { - padding: 0; -} - -ol, -ul, -menu { - list-style: none; - margin: 0; - padding: 0; -} - -.select2.select2-container { - width: 100% !important; -} -.select{ - -webkit-appearance: listbox !important -} -/* -Prevent resizing textareas horizontally by default. -*/ - -textarea { - resize: vertical; -} - -/* -1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300) -2. Set the default placeholder color to the user's configured gray 400 color. -*/ - -input::-moz-placeholder, textarea::-moz-placeholder { - opacity: 1; /* 1 */ - color: #9ca3af; /* 2 */ -} - -input:-ms-input-placeholder, textarea:-ms-input-placeholder { - opacity: 1; /* 1 */ - color: #9ca3af; /* 2 */ -} - -input::placeholder, -textarea::placeholder { - opacity: 1; /* 1 */ - color: #9ca3af; /* 2 */ -} - -/* -Set the default cursor for buttons. -*/ - -button, -[role="button"] { - cursor: pointer; -} - -/* -Make sure disabled buttons don't get the pointer cursor. -*/ -:disabled { - cursor: default; -} - -/* -1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14) -2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210) - This can trigger a poorly considered lint error in some tools but is included by design. -*/ - -img, -svg, -video, -canvas, -audio, -iframe, -embed, -object { - display: block; /* 1 */ - vertical-align: middle; /* 2 */ -} - -/* -Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14) -*/ - -img, -video { - max-width: 100%; - height: auto; -} - -[type='text'],[type='email'],[type='url'],[type='password'],[type='number'],[type='date'],[type='datetime-local'],[type='month'],[type='search'],[type='tel'],[type='time'],[type='week'],[multiple],textarea,select { - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; - background-color: #fff; - border-color: #6b7280; - border-width: 1px; - border-radius: 0px; - padding-top: 0.5rem; - padding-right: 0.75rem; - padding-bottom: 0.5rem; - padding-left: 0.75rem; - font-size: 1rem; - line-height: 1.5rem; - --tw-shadow: 0 0 #0000; -} - -[type='text']:focus, [type='email']:focus, [type='url']:focus, [type='password']:focus, [type='number']:focus, [type='date']:focus, [type='datetime-local']:focus, [type='month']:focus, [type='search']:focus, [type='tel']:focus, [type='time']:focus, [type='week']:focus, [multiple]:focus, textarea:focus, select:focus { - outline: 2px solid transparent; - outline-offset: 2px; - --tw-ring-inset: var(--tw-empty,/*!*/ /*!*/); - --tw-ring-offset-width: 0px; - --tw-ring-offset-color: #fff; - --tw-ring-color: #2563eb; - --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color); - box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); - border-color: #2563eb; -} - -input::-moz-placeholder, textarea::-moz-placeholder { - color: #6b7280; - opacity: 1; -} - -input:-ms-input-placeholder, textarea:-ms-input-placeholder { - color: #6b7280; - opacity: 1; -} - -input::placeholder,textarea::placeholder { - color: #6b7280; - opacity: 1; -} - -::-webkit-datetime-edit-fields-wrapper { - padding: 0; -} - -::-webkit-date-and-time-value { - min-height: 1.5em; -} - -::-webkit-datetime-edit,::-webkit-datetime-edit-year-field,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute-field,::-webkit-datetime-edit-second-field,::-webkit-datetime-edit-millisecond-field,::-webkit-datetime-edit-meridiem-field { - padding-top: 0; - padding-bottom: 0; -} - -select { - background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e"); - background-position: right 0.5rem center; - background-repeat: no-repeat; - background-size: 1.5em 1.5em; - padding-right: 2.5rem; - -webkit-print-color-adjust: exact; - color-adjust: exact; -} - -[multiple] { - background-image: initial; - background-position: initial; - background-repeat: unset; - background-size: initial; - padding-right: 0.75rem; - -webkit-print-color-adjust: unset; - color-adjust: unset; -} - -[type='checkbox'],[type='radio'] { - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; - padding: 0; - -webkit-print-color-adjust: exact; - color-adjust: exact; - display: inline-block; - vertical-align: middle; - background-origin: border-box; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - flex-shrink: 0; - height: 1rem; - width: 1rem; - color: #2563eb; - background-color: #fff; - border-color: #6b7280; - border-width: 1px; - --tw-shadow: 0 0 #0000; -} - -[type='checkbox'] { - border-radius: 0px; -} - -[type='radio'] { - border-radius: 100%; -} - -[type='checkbox']:focus,[type='radio']:focus { - outline: 2px solid transparent; - outline-offset: 2px; - --tw-ring-inset: var(--tw-empty,/*!*/ /*!*/); - --tw-ring-offset-width: 2px; - --tw-ring-offset-color: #fff; - --tw-ring-color: #2563eb; - --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color); - box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); -} - -[type='checkbox']:checked,[type='radio']:checked { - border-color: transparent; - background-color: currentColor; - background-size: 100% 100%; - background-position: center; - background-repeat: no-repeat; -} - -[type='checkbox']:checked { - background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3e%3c/svg%3e"); -} - -[type='radio']:checked { - background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3ccircle cx='8' cy='8' r='3'/%3e%3c/svg%3e"); -} - -[type='checkbox']:checked:hover,[type='checkbox']:checked:focus,[type='radio']:checked:hover,[type='radio']:checked:focus { - border-color: transparent; - background-color: currentColor; -} - -[type='checkbox']:indeterminate { - background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 16 16'%3e%3cpath stroke='white' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8h8'/%3e%3c/svg%3e"); - border-color: transparent; - background-color: currentColor; - background-size: 100% 100%; - background-position: center; - background-repeat: no-repeat; -} - -[type='checkbox']:indeterminate:hover,[type='checkbox']:indeterminate:focus { - border-color: transparent; - background-color: currentColor; -} - -[type='file'] { - background: unset; - border-color: inherit; - border-width: 0; - border-radius: 0; - padding: 0; - font-size: unset; - line-height: inherit; -} - -[type='file']:focus { - outline: 1px auto -webkit-focus-ring-color; -} - -*, ::before, ::after { - --tw-border-spacing-x: 0; - --tw-border-spacing-y: 0; - --tw-translate-x: 0; - --tw-translate-y: 0; - --tw-rotate: 0; - --tw-skew-x: 0; - --tw-skew-y: 0; - --tw-scale-x: 1; - --tw-scale-y: 1; - --tw-pan-x: ; - --tw-pan-y: ; - --tw-pinch-zoom: ; - --tw-scroll-snap-strictness: proximity; - --tw-ordinal: ; - --tw-slashed-zero: ; - --tw-numeric-figure: ; - --tw-numeric-spacing: ; - --tw-numeric-fraction: ; - --tw-ring-inset: ; - --tw-ring-offset-width: 0px; - --tw-ring-offset-color: #fff; - --tw-ring-color: rgb(59 130 246 / 0.5); - --tw-ring-offset-shadow: 0 0 #0000; - --tw-ring-shadow: 0 0 #0000; - --tw-shadow: 0 0 #0000; - --tw-shadow-colored: 0 0 #0000; - --tw-blur: ; - --tw-brightness: ; - --tw-contrast: ; - --tw-grayscale: ; - --tw-hue-rotate: ; - --tw-invert: ; - --tw-saturate: ; - --tw-sepia: ; - --tw-drop-shadow: ; - --tw-backdrop-blur: ; - --tw-backdrop-brightness: ; - --tw-backdrop-contrast: ; - --tw-backdrop-grayscale: ; - --tw-backdrop-hue-rotate: ; - --tw-backdrop-invert: ; - --tw-backdrop-opacity: ; - --tw-backdrop-saturate: ; - --tw-backdrop-sepia: ; -} - -::-webkit-backdrop { - --tw-border-spacing-x: 0; - --tw-border-spacing-y: 0; - --tw-translate-x: 0; - --tw-translate-y: 0; - --tw-rotate: 0; - --tw-skew-x: 0; - --tw-skew-y: 0; - --tw-scale-x: 1; - --tw-scale-y: 1; - --tw-pan-x: ; - --tw-pan-y: ; - --tw-pinch-zoom: ; - --tw-scroll-snap-strictness: proximity; - --tw-ordinal: ; - --tw-slashed-zero: ; - --tw-numeric-figure: ; - --tw-numeric-spacing: ; - --tw-numeric-fraction: ; - --tw-ring-inset: ; - --tw-ring-offset-width: 0px; - --tw-ring-offset-color: #fff; - --tw-ring-color: rgb(59 130 246 / 0.5); - --tw-ring-offset-shadow: 0 0 #0000; - --tw-ring-shadow: 0 0 #0000; - --tw-shadow: 0 0 #0000; - --tw-shadow-colored: 0 0 #0000; - --tw-blur: ; - --tw-brightness: ; - --tw-contrast: ; - --tw-grayscale: ; - --tw-hue-rotate: ; - --tw-invert: ; - --tw-saturate: ; - --tw-sepia: ; - --tw-drop-shadow: ; - --tw-backdrop-blur: ; - --tw-backdrop-brightness: ; - --tw-backdrop-contrast: ; - --tw-backdrop-grayscale: ; - --tw-backdrop-hue-rotate: ; - --tw-backdrop-invert: ; - --tw-backdrop-opacity: ; - --tw-backdrop-saturate: ; - --tw-backdrop-sepia: ; -} - -::backdrop { - --tw-border-spacing-x: 0; - --tw-border-spacing-y: 0; - --tw-translate-x: 0; - --tw-translate-y: 0; - --tw-rotate: 0; - --tw-skew-x: 0; - --tw-skew-y: 0; - --tw-scale-x: 1; - --tw-scale-y: 1; - --tw-pan-x: ; - --tw-pan-y: ; - --tw-pinch-zoom: ; - --tw-scroll-snap-strictness: proximity; - --tw-ordinal: ; - --tw-slashed-zero: ; - --tw-numeric-figure: ; - --tw-numeric-spacing: ; - --tw-numeric-fraction: ; - --tw-ring-inset: ; - --tw-ring-offset-width: 0px; - --tw-ring-offset-color: #fff; - --tw-ring-color: rgb(59 130 246 / 0.5); - --tw-ring-offset-shadow: 0 0 #0000; - --tw-ring-shadow: 0 0 #0000; - --tw-shadow: 0 0 #0000; - --tw-shadow-colored: 0 0 #0000; - --tw-blur: ; - --tw-brightness: ; - --tw-contrast: ; - --tw-grayscale: ; - --tw-hue-rotate: ; - --tw-invert: ; - --tw-saturate: ; - --tw-sepia: ; - --tw-drop-shadow: ; - --tw-backdrop-blur: ; - --tw-backdrop-brightness: ; - --tw-backdrop-contrast: ; - --tw-backdrop-grayscale: ; - --tw-backdrop-hue-rotate: ; - --tw-backdrop-invert: ; - --tw-backdrop-opacity: ; - --tw-backdrop-saturate: ; - --tw-backdrop-sepia: ; -} -.container { - width: 100%; -} -@media (min-width: 640px) { - - .container { - max-width: 640px; - } -} -@media (min-width: 768px) { - - .container { - max-width: 768px; - } -} -@media (min-width: 1024px) { - - .container { - max-width: 1024px; - } -} -@media (min-width: 1280px) { - - .container { - max-width: 1280px; - } -} -@media (min-width: 1536px) { - - .container { - max-width: 1536px; - } -} -.fixed { - position: fixed; -} -.absolute { - position: absolute; -} -.relative { - position: relative; -} -.left-0 { - left: 0px; -} -.right-0 { - right: 0px; -} -.top-0 { - top: 0px; -} -.z-0 { - z-index: 0; -} -.z-50 { - z-index: 50; -} -.float-right { - float: right; -} -.mx-auto { - margin-left: auto; - margin-right: auto; -} -.ml-3 { - margin-left: 0.75rem; -} -.-ml-px { - margin-left: -1px; -} -.mt-2 { - margin-top: 0.5rem; -} -.mt-3 { - margin-top: 0.75rem; -} -.mt-6 { - margin-top: 1.5rem; -} -.mb-4 { - margin-bottom: 1rem; -} -.mt-1 { - margin-top: 0.25rem; -} -.mt-4 { - margin-top: 1rem; -} -.ml-2 { - margin-left: 0.5rem; -} -.mt-5 { - margin-top: 1.25rem; -} -.ml-1 { - margin-left: 0.25rem; -} -.mr-2 { - margin-right: 0.5rem; -} -.ml-4 { - margin-left: 1rem; -} -.mt-8 { - margin-top: 2rem; -} -.ml-12 { - margin-left: 3rem; -} -.-mt-px { - margin-top: -1px; -} -.mb-5 { - margin-bottom: 1.25rem; -} -.mb-0 { - margin-bottom: 0px; -} -.ml-auto { - margin-left: auto; -} -.mr-3 { - margin-right: 0.75rem; -} -.mb-3 { - margin-bottom: 0.75rem; -} -.-mr-2 { - margin-right: -0.5rem; -} -.mr-1 { - margin-right: 0.25rem; -} -.block { - display: block; -} -.inline { - display: inline; -} -.flex { - display: flex; -} -.inline-flex { - display: inline-flex; -} -.table { - display: table; -} -.grid { - display: grid; -} -.hidden { - display: none; -} -.h-5 { - height: 1.25rem; -} -.h-20 { - height: 5rem; -} -.h-8 { - height: 2rem; -} -.h-16 { - height: 4rem; -} -.h-10 { - height: 2.5rem; -} -.h-4 { - height: 1rem; -} -.h-6 { - height: 1.5rem; -} -.min-h-screen { - min-height: 100vh; -} -.w-5 { - width: 1.25rem; -} -.w-48 { - width: 12rem; -} -.w-full { - width: 100%; -} -.w-20 { - width: 5rem; -} -.w-8 { - width: 2rem; -} -.w-auto { - width: auto; -} -.w-4 { - width: 1rem; -} -.w-6 { - width: 1.5rem; -} -.max-w-7xl { - max-width: 80rem; -} -.max-w-6xl { - max-width: 72rem; -} -.max-w-xl { - max-width: 36rem; -} -.flex-1 { - flex: 1 1 0%; -} -.shrink-0 { - flex-shrink: 0; -} -.border-collapse { - border-collapse: collapse; -} -.origin-top-left { - transform-origin: top left; -} -.origin-top { - transform-origin: top; -} -.origin-top-right { - transform-origin: top right; -} -.scale-95 { - --tw-scale-x: .95; - --tw-scale-y: .95; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); -} -.scale-100 { - --tw-scale-x: 1; - --tw-scale-y: 1; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); -} -.transform { - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); -} -.cursor-default { - cursor: default; -} -.list-inside { - list-style-position: inside; -} -.list-disc { - list-style-type: disc; -} -.grid-cols-1 { - grid-template-columns: repeat(1, minmax(0, 1fr)); -} -.flex-col { - flex-direction: column; -} -.items-center { - align-items: center; -} -.justify-end { - justify-content: flex-end; -} -.justify-center { - justify-content: center; -} -.justify-between { - justify-content: space-between; -} -.justify-items-center { - justify-items: center; -} -.space-x-8 > :not([hidden]) ~ :not([hidden]) { - --tw-space-x-reverse: 0; - margin-right: calc(2rem * var(--tw-space-x-reverse)); - margin-left: calc(2rem * calc(1 - var(--tw-space-x-reverse))); -} -.space-y-1 > :not([hidden]) ~ :not([hidden]) { - --tw-space-y-reverse: 0; - margin-top: calc(0.25rem * calc(1 - var(--tw-space-y-reverse))); - margin-bottom: calc(0.25rem * var(--tw-space-y-reverse)); -} -.overflow-hidden { - overflow: hidden; -} -.break-all { - word-break: break-all; -} -.rounded-md { - border-radius: 0.375rem; -} -.rounded { - border-radius: 0.25rem; -} -.rounded-lg { - border-radius: 0.5rem; -} -.rounded-l-md { - border-top-left-radius: 0.375rem; - border-bottom-left-radius: 0.375rem; -} -.rounded-r-md { - border-top-right-radius: 0.375rem; - border-bottom-right-radius: 0.375rem; -} -.border { - border-width: 1px; -} -.border-0 { - border-width: 0px; -} -.border-t { - border-top-width: 1px; -} -.border-r { - border-right-width: 1px; -} -.border-b { - border-bottom-width: 1px; -} -.border-b-2 { - border-bottom-width: 2px; -} -.border-l-4 { - border-left-width: 4px; -} -.border-gray-300 { - --tw-border-opacity: 1; - border-color: rgb(209 213 219 / var(--tw-border-opacity)); -} -.border-gray-200 { - --tw-border-opacity: 1; - border-color: rgb(229 231 235 / var(--tw-border-opacity)); -} -.border-gray-400 { - --tw-border-opacity: 1; - border-color: rgb(156 163 175 / var(--tw-border-opacity)); -} -.border-gray-100 { - --tw-border-opacity: 1; - border-color: rgb(243 244 246 / var(--tw-border-opacity)); -} -.border-transparent { - border-color: transparent; -} -.border-indigo-400 { - --tw-border-opacity: 1; - border-color: rgb(129 140 248 / var(--tw-border-opacity)); -} -.bg-white { - --tw-bg-opacity: 1; - background-color: rgb(255 255 255 / var(--tw-bg-opacity)); -} -.bg-gray-100 { - --tw-bg-opacity: 1; - background-color: rgb(243 244 246 / var(--tw-bg-opacity)); -} -.bg-gray-800 { - --tw-bg-opacity: 1; - background-color: rgb(31 41 55 / var(--tw-bg-opacity)); -} -.bg-indigo-50 { - --tw-bg-opacity: 1; - background-color: rgb(238 242 255 / var(--tw-bg-opacity)); -} -.fill-current { - fill: currentColor; -} -.p-6 { - padding: 1.5rem; -} -.p-2 { - padding: 0.5rem; -} -.px-4 { - padding-left: 1rem; - padding-right: 1rem; -} -.py-2 { - padding-top: 0.5rem; - padding-bottom: 0.5rem; -} -.px-2 { - padding-left: 0.5rem; - padding-right: 0.5rem; -} -.py-12 { - padding-top: 3rem; - padding-bottom: 3rem; -} -.py-1 { - padding-top: 0.25rem; - padding-bottom: 0.25rem; -} -.px-6 { - padding-left: 1.5rem; - padding-right: 1.5rem; -} -.py-4 { - padding-top: 1rem; - padding-bottom: 1rem; -} -.py-6 { - padding-top: 1.5rem; - padding-bottom: 1.5rem; -} -.px-1 { - padding-left: 0.25rem; - padding-right: 0.25rem; -} -.pt-6 { - padding-top: 1.5rem; -} -.pt-8 { - padding-top: 2rem; -} -.pt-0 { - padding-top: 0px; -} -.pt-2 { - padding-top: 0.5rem; -} -.pb-3 { - padding-bottom: 0.75rem; -} -.pt-4 { - padding-top: 1rem; -} -.pb-1 { - padding-bottom: 0.25rem; -} -.pt-1 { - padding-top: 0.25rem; -} -.pl-3 { - padding-left: 0.75rem; -} -.pr-4 { - padding-right: 1rem; -} -.text-center { - text-align: center; -} -.font-sans { - font-family: Nunito, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; -} -.text-sm { - font-size: 0.875rem; - line-height: 1.25rem; -} -.text-xl { - font-size: 1.25rem; - line-height: 1.75rem; -} -.text-lg { - font-size: 1.125rem; - line-height: 1.75rem; -} -.text-base { - font-size: 1rem; - line-height: 1.5rem; -} -.text-xs { - font-size: 0.75rem; - line-height: 1rem; -} -.font-medium { - font-weight: 500; -} -.font-semibold { - font-weight: 600; -} -.uppercase { - text-transform: uppercase; -} -.leading-5 { - line-height: 1.25rem; -} -.leading-tight { - line-height: 1.25; -} -.leading-7 { - line-height: 1.75rem; -} -.tracking-wider { - letter-spacing: 0.05em; -} -.tracking-widest { - letter-spacing: 0.1em; -} -.text-gray-500 { - --tw-text-opacity: 1; - color: rgb(107 114 128 / var(--tw-text-opacity)); -} -.text-gray-700 { - --tw-text-opacity: 1; - color: rgb(55 65 81 / var(--tw-text-opacity)); -} -.text-gray-800 { - --tw-text-opacity: 1; - color: rgb(31 41 55 / var(--tw-text-opacity)); -} -.text-red-600 { - --tw-text-opacity: 1; - color: rgb(220 38 38 / var(--tw-text-opacity)); -} -.text-indigo-600 { - --tw-text-opacity: 1; - color: rgb(79 70 229 / var(--tw-text-opacity)); -} -.text-gray-600 { - --tw-text-opacity: 1; - color: rgb(75 85 99 / var(--tw-text-opacity)); -} -.text-gray-200 { - --tw-text-opacity: 1; - color: rgb(229 231 235 / var(--tw-text-opacity)); -} -.text-gray-300 { - --tw-text-opacity: 1; - color: rgb(209 213 219 / var(--tw-text-opacity)); -} -.text-gray-400 { - --tw-text-opacity: 1; - color: rgb(156 163 175 / var(--tw-text-opacity)); -} -.text-gray-900 { - --tw-text-opacity: 1; - color: rgb(17 24 39 / var(--tw-text-opacity)); -} -.text-green-600 { - --tw-text-opacity: 1; - color: rgb(22 163 74 / var(--tw-text-opacity)); -} -.text-white { - --tw-text-opacity: 1; - color: rgb(255 255 255 / var(--tw-text-opacity)); -} -.text-indigo-700 { - --tw-text-opacity: 1; - color: rgb(67 56 202 / var(--tw-text-opacity)); -} -.underline { - -webkit-text-decoration-line: underline; - text-decoration-line: underline; -} -.antialiased { - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} -.opacity-0 { - opacity: 0; -} -.opacity-100 { - opacity: 1; -} -.shadow-sm { - --tw-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05); - --tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); -} -.shadow-lg { - --tw-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1); - --tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); -} -.shadow-md { - --tw-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1); - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); -} -.shadow { - --tw-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1); - --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); -} -.ring-1 { - --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color); - box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); -} -.ring-gray-300 { - --tw-ring-opacity: 1; - --tw-ring-color: rgb(209 213 219 / var(--tw-ring-opacity)); -} -.ring-black { - --tw-ring-opacity: 1; - --tw-ring-color: rgb(0 0 0 / var(--tw-ring-opacity)); -} -.ring-opacity-5 { - --tw-ring-opacity: 0.05; -} -.transition { - transition-property: color, background-color, border-color, fill, stroke, opacity, box-shadow, transform, filter, -webkit-text-decoration-color, -webkit-backdrop-filter; - transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter; - transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter, -webkit-text-decoration-color, -webkit-backdrop-filter; - transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); - transition-duration: 150ms; -} -.duration-150 { - transition-duration: 150ms; -} -.duration-200 { - transition-duration: 200ms; -} -.duration-75 { - transition-duration: 75ms; -} -.ease-in-out { - transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); -} -.ease-out { - transition-timing-function: cubic-bezier(0, 0, 0.2, 1); -} -.ease-in { - transition-timing-function: cubic-bezier(0.4, 0, 1, 1); -} - -/* Define primary and secondary color variable */ -:root { - --primary_color: #035891; - --secondary_color: #adc7d9; -} - -/* Miligram overrides */ -body { - font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; - font-weight: 400; - background: #f5f7fa; -} - -.btn-primary-color{ - background-color: var(--primary_color) !important; - color: #ffffff; - border: 1px solid var(--primary_color) !important; -} - -.text-red{ - color: #ff0000; -} -.top-nav-links, -.side-nav, -h1, h2, h3, h4, h5, h6, -.text-primary, .primary-text { - font-family: "Raleway", sans-serif; -} - -.text-primary-color, .primary-text-color { - color: var(--primary_color) !important; -} - -.btn-success { - color: #fff !important; - background-color: #218838 !important; - border-color: #1e7e34 !important; -} -.btn-danger { - color: #fff; - background-color: #dc3545 !important; - border-color: #dc3545; -} -.btn-danger:hover { - background-color: #fff !important; - color: #dc3545 !important; - border-color: #dc3545; -} -.btn-success:hover { - background-color: #fff !important; - color: #218838 !important; - border-color: #1e7e34 !important; -} -.container { - margin: auto; -} - -h1, h2, h3, h4, h5, h6 { - font-weight: 400; - color: var(--primary_color) !important; -} - -a { - color:var(--primary_color); - transition:all 0.2s linear; -} - -a:hover, -a:focus, -a:active { - color: #2a6496; - transition:all 0.2s ease-out; -} - -/* Nav bar */ -.top-nav { - display: flex; - align-items: center; - justify-content: space-between; - /* max-width: 112rem; */ - padding: 1rem; - /* margin: 0 auto 2rem; */ - background-color: var(--secondary_color); -} -.top-nav-title a { - font-size: 2.4rem; - color: var(--primary_color); -} -.top-nav-title span { - color: #404041; -} -.top-nav-links a { - margin: 0 0.5rem; -} -.top-nav-title a, -.top-nav-links a { - font-weight: bold; -} - -hr { - border: 0; - border-top: 0.3rem solid var(--primary_color); - /* margin: 0 0 4rem 0; */ -} - -.center{ - margin-left: auto; - margin-right: auto; -} - -table { - border-spacing: 0; - width: 100%; -} - -td:first-child, th:first-child { - padding-left: 0; -} - -td { - color: #000; -} - -td, th { - border-bottom: 0.1rem solid #e1e1e1; - padding: 1.2rem 1.5rem; - text-align: left; -} - -td:last-child, th:last-child { - padding-right: 0; -} - -.content { - padding: 2rem; - background: #ffffff; - border-radius: 0.4rem; - box-shadow: 0 7px 14px 0 rgb(60 66 87 / 10%), 0 3px 6px 0 rgb(0 0 0 / 7%); -} - -.product_image{ - height: 165px; - display: flex; - align-items: center; - justify-content: center; -} - -.product_action{ - display: flex; - align-items: center; - justify-content: center; -} - -.hover\:border-gray-300:hover { - --tw-border-opacity: 1; - border-color: rgb(209 213 219 / var(--tw-border-opacity)); -} - -.hover\:bg-gray-100:hover { - --tw-bg-opacity: 1; - background-color: rgb(243 244 246 / var(--tw-bg-opacity)); -} - -.hover\:bg-gray-700:hover { - --tw-bg-opacity: 1; - background-color: rgb(55 65 81 / var(--tw-bg-opacity)); -} - -.hover\:bg-gray-50:hover { - --tw-bg-opacity: 1; - background-color: rgb(249 250 251 / var(--tw-bg-opacity)); -} - -.hover\:text-gray-500:hover { - --tw-text-opacity: 1; - color: rgb(107 114 128 / var(--tw-text-opacity)); -} - -.hover\:text-gray-400:hover { - --tw-text-opacity: 1; - color: rgb(156 163 175 / var(--tw-text-opacity)); -} - -.hover\:text-gray-900:hover { - --tw-text-opacity: 1; - color: rgb(17 24 39 / var(--tw-text-opacity)); -} - -.hover\:text-gray-700:hover { - --tw-text-opacity: 1; - color: rgb(55 65 81 / var(--tw-text-opacity)); -} - -.hover\:text-gray-800:hover { - --tw-text-opacity: 1; - color: rgb(31 41 55 / var(--tw-text-opacity)); -} - -.focus\:z-10:focus { - z-index: 10; -} - -.focus\:border-blue-300:focus { - --tw-border-opacity: 1; - border-color: rgb(147 197 253 / var(--tw-border-opacity)); -} - -.focus\:border-indigo-300:focus { - --tw-border-opacity: 1; - border-color: rgb(165 180 252 / var(--tw-border-opacity)); -} - -.focus\:border-gray-300:focus { - --tw-border-opacity: 1; - border-color: rgb(209 213 219 / var(--tw-border-opacity)); -} - -.focus\:border-gray-900:focus { - --tw-border-opacity: 1; - border-color: rgb(17 24 39 / var(--tw-border-opacity)); -} - -.focus\:border-indigo-700:focus { - --tw-border-opacity: 1; - border-color: rgb(67 56 202 / var(--tw-border-opacity)); -} - -.focus\:bg-gray-100:focus { - --tw-bg-opacity: 1; - background-color: rgb(243 244 246 / var(--tw-bg-opacity)); -} - -.focus\:bg-indigo-100:focus { - --tw-bg-opacity: 1; - background-color: rgb(224 231 255 / var(--tw-bg-opacity)); -} - -.focus\:bg-gray-50:focus { - --tw-bg-opacity: 1; - background-color: rgb(249 250 251 / var(--tw-bg-opacity)); -} - -.focus\:text-gray-700:focus { - --tw-text-opacity: 1; - color: rgb(55 65 81 / var(--tw-text-opacity)); -} - -.focus\:text-gray-500:focus { - --tw-text-opacity: 1; - color: rgb(107 114 128 / var(--tw-text-opacity)); -} - -.focus\:text-indigo-800:focus { - --tw-text-opacity: 1; - color: rgb(55 48 163 / var(--tw-text-opacity)); -} - -.focus\:text-gray-800:focus { - --tw-text-opacity: 1; - color: rgb(31 41 55 / var(--tw-text-opacity)); -} - -.focus\:outline-none:focus { - outline: 2px solid transparent; - outline-offset: 2px; -} - -.focus\:ring:focus { - --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color); - box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); -} - -.focus\:ring-indigo-200:focus { - --tw-ring-opacity: 1; - --tw-ring-color: rgb(199 210 254 / var(--tw-ring-opacity)); -} - -.focus\:ring-opacity-50:focus { - --tw-ring-opacity: 0.5; -} - -.active\:bg-gray-100:active { - --tw-bg-opacity: 1; - background-color: rgb(243 244 246 / var(--tw-bg-opacity)); -} - -.active\:bg-gray-900:active { - --tw-bg-opacity: 1; - background-color: rgb(17 24 39 / var(--tw-bg-opacity)); -} - -.active\:text-gray-700:active { - --tw-text-opacity: 1; - color: rgb(55 65 81 / var(--tw-text-opacity)); -} - -.active\:text-gray-500:active { - --tw-text-opacity: 1; - color: rgb(107 114 128 / var(--tw-text-opacity)); -} - -.disabled\:opacity-25:disabled { - opacity: 0.25; -} - -@media (prefers-color-scheme: dark) { - - .dark\:border-gray-700 { - --tw-border-opacity: 1; - border-color: rgb(55 65 81 / var(--tw-border-opacity)); - } - - .dark\:bg-gray-900 { - --tw-bg-opacity: 1; - background-color: rgb(17 24 39 / var(--tw-bg-opacity)); - } - - .dark\:bg-gray-800 { - --tw-bg-opacity: 1; - background-color: rgb(31 41 55 / var(--tw-bg-opacity)); - } - - .dark\:text-gray-500 { - --tw-text-opacity: 1; - color: rgb(107 114 128 / var(--tw-text-opacity)); - } - - .dark\:text-white { - --tw-text-opacity: 1; - color: rgb(255 255 255 / var(--tw-text-opacity)); - } - - .dark\:text-gray-400 { - --tw-text-opacity: 1; - color: rgb(156 163 175 / var(--tw-text-opacity)); - } -} - -@media (min-width: 640px) { - - .sm\:-my-px { - margin-top: -1px; - margin-bottom: -1px; - } - - .sm\:ml-0 { - margin-left: 0px; - } - - .sm\:ml-10 { - margin-left: 2.5rem; - } - - .sm\:ml-6 { - margin-left: 1.5rem; - } - - .sm\:block { - display: block; - } - - .sm\:flex { - display: flex; - } - - .sm\:hidden { - display: none; - } - - .sm\:h-20 { - height: 5rem; - } - - .sm\:max-w-md { - max-width: 28rem; - } - - .sm\:flex-1 { - flex: 1 1 0%; - } - - .sm\:items-center { - align-items: center; - } - - .sm\:justify-start { - justify-content: flex-start; - } - - .sm\:justify-center { - justify-content: center; - } - - .sm\:justify-between { - justify-content: space-between; - } - - .sm\:rounded-lg { - border-radius: 0.5rem; - } - - .sm\:px-6 { - padding-left: 1.5rem; - padding-right: 1.5rem; - } - - .sm\:pt-0 { - padding-top: 0px; - } - - .sm\:text-left { - text-align: left; - } - - .sm\:text-right { - text-align: right; - } -} - -@media (min-width: 768px) { - - .md\:grid-cols-2 { - grid-template-columns: repeat(2, minmax(0, 1fr)); - } - - .md\:border-t-0 { - border-top-width: 0px; - } - - .md\:border-l { - border-left-width: 1px; - } -} - -@media (min-width: 1024px) { - - .lg\:px-8 { - padding-left: 2rem; - padding-right: 2rem; - } -} -.odd-row { - background-color: #efefef; -} diff --git a/stubs/resources/views/blog/add.blade.php b/stubs/resources/views/blog/add.blade.php deleted file mode 100755 index 34b5790..0000000 --- a/stubs/resources/views/blog/add.blade.php +++ /dev/null @@ -1,74 +0,0 @@ - - -
-
-
-

{{__('blog.create_blog_title')}}

- - - - @csrf -
- - - - - - - - - - - - - - - - - - - - - - - - - -
- @error('title') -
{{ $message }}
- @enderror -
- - - - @error('description') -
{{ $message }}
- @enderror -
- @error('image') -
{{ $message }}
- @enderror -
- - - -
- - - @include('blog.tags', ['tags' => $tags, 'selected' => []]) -
- - {{__('blog.back_button')}} -
- - - -
-
-
-
\ No newline at end of file diff --git a/stubs/resources/views/blog/commentsDisplay.blade.php b/stubs/resources/views/blog/commentsDisplay.blade.php deleted file mode 100755 index efde632..0000000 --- a/stubs/resources/views/blog/commentsDisplay.blade.php +++ /dev/null @@ -1,47 +0,0 @@ - -@foreach($comments as $comment) -
parent_id != null) style="margin-left:40px;" @endif> - {{ $comment->user->name }}: {{ $comment->created_at->diffForHumans() }} - @if($comment->pinned) - @can('isOwner',$blog) - - - - @else - - - - - @endcan - @endif -

- {{ $comment->body }}

-
- @csrf -
- - @error('body_'. $comment->id) -
{{ $message }}
- @enderror - - - @can('isOwner',$blog) - @unless($comment->pinned) - - - - @endunless - @endcan - - {{__('comment.comments_reply')}} - - @if($comment->user->id == auth()->user()->id) - - {{__('blog.delete_button')}} - - @endif -
-
- @include('blog.commentsDisplay', ['comments' => $comment->replies]) -
-@endforeach \ No newline at end of file diff --git a/stubs/resources/views/blog/edit.blade.php b/stubs/resources/views/blog/edit.blade.php deleted file mode 100755 index fb61260..0000000 --- a/stubs/resources/views/blog/edit.blade.php +++ /dev/null @@ -1,76 +0,0 @@ - -
-
-
-

{{__('blog.update_blog_title')}}

- - - - @csrf - @method('PUT') -
- - - - - - - - - - - - - - - - - - - - - - - - - -
- @error('title') -
{{ $message }}
- @enderror -
- - - - @error('description') -
{{ $message }}
- @enderror -
- - @error('image') -
{{ $message }}
- @enderror - {{$blog->image}} -
- - - -
- - - @include('blog.tags', ['tags' => $tags, 'selected' => $blog->tags->pluck('name')->toArray()]) -
- - {{__('blog.back_button')}} -
- - - -
-
-
-
diff --git a/stubs/resources/views/blog/index.blade.php b/stubs/resources/views/blog/index.blade.php deleted file mode 100755 index bb8f535..0000000 --- a/stubs/resources/views/blog/index.blade.php +++ /dev/null @@ -1,283 +0,0 @@ - -@push('css') - - -@endpush -
-
-
- @if ($message = Session::get('success')) - - @endif - @if(!$published) - @can('isUser') - {{__('blog.new_blog_button')}} - @endcan -

{{__('blog.index_blog_title')}}

- @else -

{{__('blog.all_blogs')}}

- @endif - @if(isset($blogs)) - - - - - - - - - - - @if(! $published) - - @endif - - - - - @forelse($blogs as $blog) - odd) class="odd-row" @endif> - - - - - - - - @if(! $published) - - @endif - - - @empty - - - - @endforelse - -
{{__('blog.sr_no')}}@sortablelink('title',__('blog.title')){{__('blog.image')}}@sortablelink('description',__('blog.description')){{__('blog.tags')}}@sortablelink('is_published',__('blog.published'))@sortablelink('user.name',__('blog.blog_owner')){{__('blog.blog_status')}}{{__('blog.actions')}}
{{ $loop->iteration + $blogs->firstItem() - 1 }} - - {{ $blog->title }} - - {{$blog->image}}{{ Str::limit($blog->description, 100) }} - @forelse($blog->tags as $tag) - @if($loop->iteration <= 5) - {{ $tag->name }} - @else - ... - @break - @endif - @empty - {{__('blog.no_tags')}} - @endforelse - - @if ($blog->is_published) - {{__('blog.published')}} - @else - {{__('blog.not_published')}} - @endif - - {{$blog->user->name}} - - @if ($blog->status == Blog::STATUS_PENDING) - {{__('blog.pending_tooltip')}} - @elseif($blog->status == Blog::STATUS_APPROVE) - {{__('blog.approve_tooltip')}} - @elseif($blog->status == Blog::STATUS_DRAFT) - {{__('blog.on_action_tooltip')}} - @else - {{__('blog.reject_tooltip')}} - @endif - - @if($published) - - - {{count($blog->totalComments)}} - - - - @can('isOwner',$blog) - - - - - - - @endcan - @else - @can('isAdmin') - @if($blog->status == 'pending') - - - - - - - @endif - @endcan - @can('isUser') - - - - - - - - - - @endcan - @endif -
-
- {{$blogs->onEachSide(2)->links()}} -
- @endif -
-
- @can('isAdmin') - - @endcan -
- -
\ No newline at end of file diff --git a/stubs/resources/views/blog/tags.blade.php b/stubs/resources/views/blog/tags.blade.php deleted file mode 100755 index 3cf3fb9..0000000 --- a/stubs/resources/views/blog/tags.blade.php +++ /dev/null @@ -1,18 +0,0 @@ - - - -@push('css') - -@endpush \ No newline at end of file diff --git a/stubs/resources/views/blog/trash_bin.blade.php b/stubs/resources/views/blog/trash_bin.blade.php deleted file mode 100755 index ffdd0e8..0000000 --- a/stubs/resources/views/blog/trash_bin.blade.php +++ /dev/null @@ -1,141 +0,0 @@ - -
-
-
- @if ($message = Session::get('success')) - - @endif - @if($blogs->isNotEmpty()) - {{__('blog.restore_all_button')}} - @endif -

{{__('blog.trash_bin_title')}}

- @if(isset($blogs)) - - - - - - - - - - - - - - @forelse($blogs as $blog) - odd) class="odd-row" @endif> - - - - - - - - - @empty - - - - @endforelse - -
{{__('blog.sr_no')}}@sortablelink('title',__('blog.title')){{__('blog.image')}}@sortablelink('description',__('blog.description'))@sortablelink('is_published',__('blog.published'))@sortablelink('user.name',__('blog.blog_owner')){{__('blog.actions')}}
{{ $loop->iteration + $blogs->firstItem() - 1 }} - {{ $blog->title }} - {{$blog->image}}{{ Str::limit($blog->description, 100) }} - @if ($blog->is_published) - {{__('blog.published')}} - @else - {{__('blog.not_published')}} - @endif - - {{$blog->user->name}} - - - - - - - -
-
- {{$blogs->onEachSide(2)->links()}} -
- @endif -
-
-
- -
\ No newline at end of file diff --git a/stubs/resources/views/blog/view.blade.php b/stubs/resources/views/blog/view.blade.php deleted file mode 100755 index 702de6d..0000000 --- a/stubs/resources/views/blog/view.blade.php +++ /dev/null @@ -1,132 +0,0 @@ - -
-
-
-

{!!__('blog.view_blog_title',['blogName' => $blog->title])!!}

- {{$counter}} - {{__('blog.back_button')}} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
{{__('blog.title')}}:title; ?>
{{__('blog.description')}}:description; ?>
{{__('blog.blog_owner')}}:user->name; ?>
{{$blog->image}}
{{__('blog.published')}}: - @if ($blog->is_published) - {{__('blog.published')}} - @else - {{__('blog.not_published')}} - @endif -
{{__('blog.tags')}}: - @forelse($blog->tags as $tag) - {{ $tag->name }} - @empty - {{__('blog.no_tags')}} - @endforelse -
{{__('blog.blog_status')}}: - @if ($blog->status == Blog::STATUS_PENDING) - {{__('blog.pending_tooltip')}} - @elseif($blog->status == Blog::STATUS_APPROVE) - {{__('blog.approve_tooltip')}} - @elseif($blog->status == Blog::STATUS_DRAFT) - {{__('blog.on_action_tooltip')}} - @else -

{{__('blog.reject_tooltip')}}[{{__('blog.reject_modal_title')}} {{$blog->reject_reason}}]

- @endif -
{{__('blog.created_date')}}:created_at->format('d M Y H:i A') ; ?>
-
- @if($blog->is_published && $blog->status == Blog::STATUS_APPROVE) -
-

{{__('comment.comments_title')}}

- @include('blog.commentsDisplay', ['comments' => $blog->comments, 'blog' => $blog]) -
- @csrf -
- - @error('body_') -
{{ $message }}
- @enderror - -
-
- -
-
-
- @endif -
-
- -
\ No newline at end of file diff --git a/stubs/resources/views/components/application-logo.blade.php b/stubs/resources/views/components/application-logo.blade.php deleted file mode 100644 index 553e3f2..0000000 --- a/stubs/resources/views/components/application-logo.blade.php +++ /dev/null @@ -1 +0,0 @@ -Laravel Application \ No newline at end of file diff --git a/stubs/resources/views/dashboard.blade.php b/stubs/resources/views/dashboard.blade.php deleted file mode 100644 index 2620bb1..0000000 --- a/stubs/resources/views/dashboard.blade.php +++ /dev/null @@ -1,20 +0,0 @@ - - -

- {{ __('Dashboard') }} -

-
- -
-
-
-
- @if(! auth()->user()->email_verified_at) - {{ __('Verify Email') }} - @endif - -
-
-
-
-
diff --git a/stubs/resources/views/emails/blog_action.blade.php b/stubs/resources/views/emails/blog_action.blade.php deleted file mode 100755 index 56b3180..0000000 --- a/stubs/resources/views/emails/blog_action.blade.php +++ /dev/null @@ -1,15 +0,0 @@ - - - - -
- {{ __('Your Blog is ') . ucwords($blog->status) . __(' by ') . ucwords($blog->admin->name)}} -
- - -
-
diff --git a/stubs/resources/views/emails/comment_action.blade.php b/stubs/resources/views/emails/comment_action.blade.php deleted file mode 100755 index 6cb9f3e..0000000 --- a/stubs/resources/views/emails/comment_action.blade.php +++ /dev/null @@ -1,17 +0,0 @@ - - - - -
- {{ ucwords($user->name) .' Commented on your blog!!'}} -
- “{{$comment->body}}” -
- - -
-
diff --git a/stubs/resources/views/layouts/app.blade.php b/stubs/resources/views/layouts/app.blade.php deleted file mode 100644 index 9f217ed..0000000 --- a/stubs/resources/views/layouts/app.blade.php +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - {{ config('app.name', 'Laravel') }} - - - - - - - - - - - - - - @vite(['resources/css/app.css', 'resources/js/app.js']) - @stack('css') - - -
- @include('layouts.navigation') - - - {{--
-
- {{ $header }} -
-
--}} - - {{-- {{ Breadcrumbs::render() }} --}} -
- {{ $slot }} -
- @include('layouts.footer') -
- - diff --git a/stubs/resources/views/layouts/footer.blade.php b/stubs/resources/views/layouts/footer.blade.php deleted file mode 100644 index bf5f3ce..0000000 --- a/stubs/resources/views/layouts/footer.blade.php +++ /dev/null @@ -1,28 +0,0 @@ - diff --git a/stubs/resources/views/layouts/guest.blade.php b/stubs/resources/views/layouts/guest.blade.php deleted file mode 100644 index a5ec1c3..0000000 --- a/stubs/resources/views/layouts/guest.blade.php +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - {{ config('app.name', 'Laravel') }} - - - - - - @vite(['resources/css/app.css', 'resources/js/app.js']) - - -
- {{ $slot }} -
- - diff --git a/stubs/resources/views/layouts/navigation.blade.php b/stubs/resources/views/layouts/navigation.blade.php deleted file mode 100644 index c62475e..0000000 --- a/stubs/resources/views/layouts/navigation.blade.php +++ /dev/null @@ -1,125 +0,0 @@ - diff --git a/stubs/routes/web.php b/stubs/routes/web.php deleted file mode 100644 index e4d7545..0000000 --- a/stubs/routes/web.php +++ /dev/null @@ -1,68 +0,0 @@ - ['web', 'auth', 'change_site_language']], function () { - Route::get('/dashboard', function () { - $language = session()->get('locale'); - if (! in_array($language, ['en', 'fr', 'hi'])) { - $language = 'en'; - } - App::setLocale($language); - session()->put('locale', $language); - return view('dashboard'); - })->name('dashboard'); - - Route::get('/published/blogs', [BlogController::class, 'published'])->name('blogs.published'); - Route::post('/trash-bin/{blog}/blogs', [BlogController::class, 'restore'])->name('blogs.restore'); - Route::get('/trash-bin/blogs', [BlogController::class, 'trashBin'])->name('blogs.trash_bin'); - Route::delete('/force-delete/{blog}/blogs', [BlogController::class, 'forceDestroy'])->name('blogs.forceDestroy'); - Route::post('/restore-all/blogs', [BlogController::class, 'restoreAll'])->name('blogs.restoreAll'); - Route::patch('/blogs/update_status/{blog}', [BlogController::class, 'updateStatus'])->name('blogs.update_status'); - - Route::resource('blogs', BlogController::class)->missing(function (Request $request) { - return Redirect::route('blogs.index'); - })->parameters(['blogs' => 'blog']); - - Route::post('/add_comment', [CommentController::class, 'store'])->name('comments.store'); - Route::delete('/remove_comment/{comment}', [CommentController::class, 'destroy'])->name('comments.destroy'); - Route::post('/pin_comment/{comment}', [CommentController::class, 'pinComment'])->name('comments.pin_comment'); - - Route::get('change-language/{locale}', function (Request $request, $locale) { - if (! in_array($locale, ['en', 'fr', 'hi'])) { - abort(404); - } - App::setLocale($locale); - session()->put('locale', $locale); - return redirect()->back(); - })->name('locale.setting'); - - Route::get('/profile', [ProfileController::class, 'edit'])->name('profile.edit'); - Route::patch('/profile', [ProfileController::class, 'update'])->name('profile.update'); - Route::delete('/profile', [ProfileController::class, 'destroy'])->name('profile.destroy'); -}); - -require base_path('routes/auth.php');