├── .editorconfig ├── .env.example ├── .env.testing ├── .gitattributes ├── .gitignore ├── .phpstorm.meta.php ├── .prettierignore ├── .prettierrc ├── LICENSE ├── README.md ├── TODO.md ├── _ide_helper.php ├── _ide_helper_actions.php ├── app ├── Actions │ ├── Admin │ │ ├── Cms │ │ │ ├── ContactMessages.php │ │ │ └── ContactMessagesDelete.php │ │ ├── Dashboard.php │ │ ├── Profile │ │ │ └── MainProfile.php │ │ └── Settings │ │ │ ├── Configurations.php │ │ │ └── ResetSystem.php │ ├── Auth │ │ ├── Login.php │ │ ├── LoginLinkSent.php │ │ ├── LoginViaMagicLink.php │ │ ├── Logout.php │ │ ├── Register.php │ │ ├── RequestPasswordReset.php │ │ ├── ResetPassword.php │ │ └── VerifyLogin.php │ ├── Frontend │ │ ├── About.php │ │ ├── Contact.php │ │ ├── Home.php │ │ └── PolicyPages.php │ ├── User │ │ ├── Dashboard.php │ │ └── Profile │ │ │ └── MainProfile.php │ └── UserRedirector.php ├── Console │ ├── Commands │ │ ├── CleanLoginTokensTable.php │ │ ├── ClearRedis.php │ │ ├── Setup.php │ │ ├── UpdateConfigurations.php │ │ └── UpdateConfigurationsTerminal.php │ ├── Generators │ │ ├── EnumMakeCommand.php │ │ ├── FacadeMakeCommand.php │ │ ├── FilterMakeCommand.php │ │ ├── GeneratorCommand.php │ │ ├── ListenerMakeCommand.php │ │ ├── NotificationMakeCommand.php │ │ ├── RepositoryMakeCommand.php │ │ ├── ResourceMakeCommand.php │ │ ├── ServiceMakeCommand.php │ │ ├── WidgetMakeCommand.php │ │ └── stubs │ │ │ ├── enum.stub │ │ │ ├── facade.stub │ │ │ ├── filter.stub │ │ │ ├── listener-queued.stub │ │ │ ├── notification.stub │ │ │ ├── repository.stub │ │ │ ├── resource-collection.stub │ │ │ ├── resource.stub │ │ │ ├── service.stub │ │ │ └── widget.stub │ └── Kernel.php ├── Contracts │ └── RedisInterface.php ├── Events │ ├── CRUDErrorOccurred.php │ ├── ContactFormWasFilled.php │ ├── UserLoggedIn.php │ └── UserWasCreated.php ├── Exceptions │ └── Handler.php ├── Http │ ├── Controllers │ │ └── Controller.php │ ├── Kernel.php │ ├── Middleware │ │ ├── Authenticate.php │ │ ├── CheckIfUserActive.php │ │ ├── EncryptCookies.php │ │ ├── HandleInertiaRequests.php │ │ ├── Localization.php │ │ ├── PreventRequestsDuringMaintenance.php │ │ ├── RedirectIfAuthenticated.php │ │ ├── RoleChecker.php │ │ ├── TrimStrings.php │ │ ├── TrustHosts.php │ │ ├── TrustProxies.php │ │ ├── ValidateSignature.php │ │ └── VerifyCsrfToken.php │ └── Resources │ │ ├── ContactMessageResource.php │ │ ├── ContactMessageResourceCollection.php │ │ ├── UserResource.php │ │ └── UserSlimResource.php ├── Jobs │ └── SendLoginAlertEmail.php ├── Library │ ├── Datatable.php │ ├── RedisConfigurations │ │ ├── Extras.php │ │ ├── Models.php │ │ ├── RedisTemplate.php │ │ ├── Settings.php │ │ └── StaticData.php │ ├── events.php │ └── helpers.php ├── Listeners │ ├── CRUDErrorHasOccurred.php │ ├── ContactFormHasBeenFilled.php │ ├── UserHasBeenCreated.php │ └── UserHasLoggedIn.php ├── Mail │ ├── ContactFormMailable.php │ └── MagicLoginLink.php ├── Models │ ├── Configuration.php │ ├── ContactMessage.php │ ├── LoginToken.php │ ├── User.php │ ├── UserAccessorsTrait.php │ ├── UserLogin.php │ ├── UserRelationshipsTrait.php │ └── UserScopesTrait.php ├── Notifications │ ├── CrudErrorNotification.php │ ├── NotifyAdmin.php │ ├── NotifyUserOfLogin.php │ └── NotifyUserOfPasswordHardReset.php ├── Providers │ ├── AppServiceProvider.php │ ├── AuthServiceProvider.php │ ├── BroadcastServiceProvider.php │ ├── EventServiceProvider.php │ ├── RedisServiceProvider.php │ └── RouteServiceProvider.php ├── Repositories │ ├── RedisRepository.php │ ├── SystemInfoRepository.php │ └── UserRepository.php └── Traits │ ├── CustomControllerResponsesTrait.php │ ├── QueueMailConstants.php │ └── ThemesTrait.php ├── artisan ├── bootstrap ├── app.php └── cache │ └── .gitignore ├── composer.json ├── composer.lock ├── config ├── app.php ├── auth.php ├── broadcasting.php ├── cache.php ├── cors.php ├── database.php ├── filesystems.php ├── hashing.php ├── inertia.php ├── location.php ├── logging.php ├── mail.php ├── queue.php ├── sanctum.php ├── services.php ├── session.php ├── system.php ├── system_configurations.php ├── system_redis.php └── view.php ├── database ├── .gitignore ├── factories │ ├── ContactMessageFactory.php │ └── UserFactory.php ├── maxmind │ ├── GeoLite2-City.mmdb │ └── GeoLite2-Country.mmdb ├── migrations │ ├── 2014_10_12_000000_create_users_table.php │ ├── 2014_10_12_100000_create_password_reset_tokens_table.php │ ├── 2019_08_19_000000_create_failed_jobs_table.php │ ├── 2019_12_14_000001_create_personal_access_tokens_table.php │ ├── 2023_03_29_173045_create_sessions_table.php │ ├── 2023_03_30_003434_add_columns_to_users_table.php │ ├── 2023_03_30_185913_create_notifications_table.php │ ├── 2023_03_30_190907_create_configurations_table.php │ ├── 2023_04_05_234427_create_user_logins_table.php │ ├── 2023_04_08_144736_create_contact_messages_table.php │ └── 2023_04_28_140325_create_login_tokens_table.php └── seeders │ ├── DatabaseSeeder.php │ ├── DemoTableSeeder.php │ └── UserTableSeeder.php ├── lang └── en │ ├── auth.php │ ├── pagination.php │ ├── passwords.php │ └── validation.php ├── package.json ├── phpunit.xml ├── pnpm-lock.yaml ├── postcss.config.cjs ├── public ├── .htaccess ├── android-chrome-96x96.png ├── apple-touch-icon.png ├── browserconfig.xml ├── favicon-16x16.png ├── favicon-32x32.png ├── favicon.ico ├── fonts │ └── boxicons │ │ ├── css │ │ ├── animations.css │ │ ├── boxicons.css │ │ ├── boxicons.min.css │ │ └── transformations.css │ │ └── fonts │ │ ├── boxicons.eot │ │ ├── boxicons.svg │ │ ├── boxicons.ttf │ │ ├── boxicons.woff │ │ └── boxicons.woff2 ├── img │ ├── gumroad-button.jpg │ ├── laravelte-dashboard.png │ ├── laravelte-logo-full.png │ ├── laravelte-logo-small.png │ ├── laravelte-logo.png │ ├── laravelte-screenshot-1.jpg │ ├── laravelte-screenshot-2.jpg │ ├── laravelte-screenshot-3.jpg │ ├── laravelte-screenshot-4.jpg │ ├── laravelte-screenshot-5.png │ ├── laravelte-screenshot-6.png │ ├── laravelte-screenshot-7.png │ └── no-data.png ├── index.php ├── mstile-150x150.png ├── robots.txt ├── safari-pinned-tab.svg └── site.webmanifest ├── resources ├── css │ └── app.css ├── markdown │ ├── policy.md │ └── terms.md ├── ts │ ├── Components │ │ ├── Alert.svelte │ │ ├── Button.svelte │ │ ├── Circle.svelte │ │ ├── ComingSoon.svelte │ │ ├── ContactForm.svelte │ │ ├── DisplayErrors.svelte │ │ ├── Divider.svelte │ │ ├── Empty.svelte │ │ ├── FancyButton.svelte │ │ ├── Footer.svelte │ │ ├── Hero.svelte │ │ ├── Icon.svelte │ │ ├── Input.svelte │ │ ├── Loading.svelte │ │ ├── Modal.svelte │ │ ├── ModalClose.svelte │ │ ├── PageHeader.svelte │ │ ├── Pagination.svelte │ │ ├── PremiumAccess.svelte │ │ ├── Seo.svelte │ │ ├── SimpleTable.svelte │ │ ├── SubscribeForm.svelte │ │ ├── Sweet.svelte │ │ ├── Textarea.svelte │ │ ├── ThemeSwitcher.svelte │ │ ├── Title.svelte │ │ ├── ValidationErrors.svelte │ │ └── index.ts │ ├── Layouts │ │ ├── AdminDashboardLayout.svelte │ │ ├── AppLayout.svelte │ │ ├── DashboardLayout.svelte │ │ └── MainLayout.svelte │ ├── Pages │ │ ├── About.svelte │ │ ├── Admin │ │ │ ├── Components │ │ │ │ ├── AdminSidebar.svelte │ │ │ │ ├── AdminStats.svelte │ │ │ │ ├── AdminTitle.svelte │ │ │ │ ├── ConfigurationModal.svelte │ │ │ │ ├── ContactMessages.svelte │ │ │ │ └── ContactMessagesModal.svelte │ │ │ ├── Dashboard.svelte │ │ │ ├── Profile │ │ │ │ └── MainProfile.svelte │ │ │ └── Settings │ │ │ │ ├── Configurations.svelte │ │ │ │ └── ResetSystem.svelte │ │ ├── Auth │ │ │ ├── Login.svelte │ │ │ ├── LoginLinkSent.svelte │ │ │ └── Register.svelte │ │ ├── Contact.svelte │ │ ├── Home.svelte │ │ ├── PrivacyPolicy.svelte │ │ └── User │ │ │ ├── Components │ │ │ ├── UserSidebar.svelte │ │ │ └── UserTitle.svelte │ │ │ ├── Dashboard.svelte │ │ │ └── Profile │ │ │ └── MainProfile.svelte │ ├── app.ts │ ├── bootstrap.ts │ ├── helpers.ts │ └── types │ │ ├── global.ts │ │ ├── index.ts │ │ └── vite-env.d.ts └── views │ ├── app.blade.php │ └── emails │ ├── contact-form-email.blade.php │ ├── magic-login-link.blade.php │ └── user-login-alert.blade.php ├── routes ├── api.php ├── channels.php ├── console.php ├── modules │ ├── admin.php │ ├── auth.php │ └── user.php └── web.php ├── storage ├── app │ ├── .gitignore │ └── public │ │ └── .gitignore ├── debugbar │ └── .gitignore ├── framework │ ├── .gitignore │ ├── cache │ │ ├── .gitignore │ │ └── data │ │ │ └── .gitignore │ ├── sessions │ │ └── .gitignore │ ├── testing │ │ └── .gitignore │ └── views │ │ └── .gitignore └── logs │ └── .gitignore ├── stubs └── action.stub ├── svelte.config.js ├── tailwind.config.cjs ├── tests ├── CreatesApplication.php ├── Feature │ ├── AuthenticationTest.php │ ├── ContactMessagesTest.php │ ├── ExampleTest.php │ ├── FrontendPagesTest.php │ └── RegistrationTest.php ├── Pest.php ├── TestCase.php └── Unit │ └── ExampleTest.php ├── tsconfig.json ├── tsconfig.node.json └── vite.config.ts /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | indent_size = 4 7 | indent_style = space 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | 14 | [*.{yml,yaml}] 15 | indent_size = 2 16 | 17 | [docker-compose.yml] 18 | indent_size = 4 19 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | APP_NAME=Laravelte 2 | APP_ENV=local 3 | APP_KEY= 4 | APP_DEBUG=true 5 | APP_URL=http://laravelte.test 6 | SESSION_DOMAIN=laravelte.test 7 | SANCTUM_STATEFUL_DOMAINS=laravelte.test 8 | APP_LOGO="/img/laravelte_logo.png" 9 | 10 | LOG_CHANNEL=stack 11 | LOG_DEPRECATIONS_CHANNEL=null 12 | LOG_LEVEL=debug 13 | DEBUGBAR_ENABLED=false 14 | 15 | DB_CONNECTION=mysql 16 | DB_HOST=127.0.0.1 17 | DB_PORT=3306 18 | DB_DATABASE=laravelte 19 | DB_USERNAME=root 20 | DB_PASSWORD= 21 | 22 | BROADCAST_DRIVER=log 23 | CACHE_DRIVER=redis 24 | CACHE_PREFIX="laravelte_" 25 | FILESYSTEM_DISK=local 26 | QUEUE_CONNECTION=sync 27 | SESSION_DRIVER=redis 28 | SESSION_LIFETIME=120 29 | SESSION_CONNECTION="session" 30 | 31 | MEMCACHED_HOST=127.0.0.1 32 | 33 | REDIS_HOST=127.0.0.1 34 | REDIS_PASSWORD=null 35 | REDIS_PORT=6379 36 | 37 | MAIL_MAILER=mailpit 38 | MAIL_HOST=0.0.0.0 39 | MAIL_PORT=1025 40 | MAIL_USERNAME=null 41 | MAIL_PASSWORD=null 42 | MAIL_ENCRYPTION=null 43 | MAIL_FROM_ADDRESS="hello@example.com" 44 | MAIL_FROM_NAME="${APP_NAME}" 45 | 46 | AWS_ACCESS_KEY_ID= 47 | AWS_SECRET_ACCESS_KEY= 48 | AWS_DEFAULT_REGION=us-east-1 49 | AWS_BUCKET= 50 | AWS_USE_PATH_STYLE_ENDPOINT=false 51 | 52 | PUSHER_APP_ID= 53 | PUSHER_APP_KEY= 54 | PUSHER_APP_SECRET= 55 | PUSHER_HOST= 56 | PUSHER_PORT=443 57 | PUSHER_SCHEME=https 58 | PUSHER_APP_CLUSTER=mt1 59 | 60 | VITE_PUSHER_APP_KEY="${PUSHER_APP_KEY}" 61 | VITE_PUSHER_HOST="${PUSHER_HOST}" 62 | VITE_PUSHER_PORT="${PUSHER_PORT}" 63 | VITE_PUSHER_SCHEME="${PUSHER_SCHEME}" 64 | VITE_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}" 65 | 66 | DEMO_USERNAME="acelords" 67 | DEMO_PASSWORD="acelords" 68 | -------------------------------------------------------------------------------- /.env.testing: -------------------------------------------------------------------------------- 1 | APP_NAME=Laravelte 2 | APP_ENV=production 3 | APP_KEY=base64:GKVp3UUkWnXCqvI2DOMLw84D0/ysWhcYaGYioAkAYNU= 4 | APP_DEBUG=true 5 | APP_URL=http://laravelte.test 6 | SESSION_DOMAIN=laravelte.test 7 | SANCTUM_STATEFUL_DOMAINS=laravelte.test 8 | APP_LOGO="/img/laravelte_logo.png" 9 | 10 | LOG_CHANNEL=stack 11 | LOG_DEPRECATIONS_CHANNEL=null 12 | LOG_LEVEL=debug 13 | DEBUGBAR_ENABLED=false 14 | DD_ON_ERROR=false 15 | 16 | DB_CONNECTION=sqlite 17 | DB_HOST=127.0.0.1 18 | DB_PORT=3306 19 | DB_DATABASE=laravelte 20 | DB_USERNAME=root 21 | DB_PASSWORD= 22 | 23 | BROADCAST_DRIVER=log 24 | CACHE_DRIVER=redis 25 | CACHE_PREFIX="laravelte_testing_" 26 | FILESYSTEM_DISK=local 27 | QUEUE_CONNECTION=sync 28 | SESSION_DRIVER=redis 29 | SESSION_LIFETIME=120 30 | SESSION_CONNECTION="session" 31 | 32 | MEMCACHED_HOST=127.0.0.1 33 | 34 | REDIS_HOST=127.0.0.1 35 | REDIS_PASSWORD=null 36 | REDIS_PORT=6379 37 | 38 | MAIL_MAILER=log 39 | MAIL_HOST=mailpit 40 | MAIL_PORT=1025 41 | MAIL_USERNAME=null 42 | MAIL_PASSWORD=null 43 | MAIL_ENCRYPTION=null 44 | MAIL_FROM_ADDRESS="hello@example.com" 45 | MAIL_FROM_NAME="${APP_NAME}" 46 | 47 | AWS_ACCESS_KEY_ID= 48 | AWS_SECRET_ACCESS_KEY= 49 | AWS_DEFAULT_REGION=us-east-1 50 | AWS_BUCKET= 51 | AWS_USE_PATH_STYLE_ENDPOINT=false 52 | 53 | PUSHER_APP_ID= 54 | PUSHER_APP_KEY= 55 | PUSHER_APP_SECRET= 56 | PUSHER_HOST= 57 | PUSHER_PORT=443 58 | PUSHER_SCHEME=https 59 | PUSHER_APP_CLUSTER=mt1 60 | 61 | VITE_PUSHER_APP_KEY="${PUSHER_APP_KEY}" 62 | VITE_PUSHER_HOST="${PUSHER_HOST}" 63 | VITE_PUSHER_PORT="${PUSHER_PORT}" 64 | VITE_PUSHER_SCHEME="${PUSHER_SCHEME}" 65 | VITE_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}" 66 | 67 | DEMO_USERNAME="acelords" 68 | DEMO_PASSWORD="acelords" 69 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | 3 | *.blade.php diff=html 4 | *.css diff=css 5 | *.html diff=html 6 | *.md diff=markdown 7 | *.php diff=php 8 | 9 | /.github export-ignore 10 | CHANGELOG.md export-ignore 11 | .styleci.yml export-ignore 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.phpunit.cache 2 | /node_modules 3 | /public/build 4 | /public/hot 5 | /public/storage 6 | /storage/*.key 7 | /vendor 8 | .env 9 | .env.backup 10 | .env.production 11 | .phpunit.result.cache 12 | Homestead.json 13 | Homestead.yaml 14 | auth.json 15 | npm-debug.log 16 | yarn-error.log 17 | /.fleet 18 | /.idea 19 | /.vscode 20 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /build 4 | /.svelte-kit 5 | /package 6 | .env 7 | .env.* 8 | !.env.example 9 | 10 | # Ignore files for PNPM, NPM and YARN 11 | pnpm-lock.yaml 12 | package-lock.json 13 | yarn.lock 14 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": false, 3 | "singleQuote": true, 4 | "arrowParens": "avoid", 5 | "printWidth": 120 6 | } 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Lexx YungCarter 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | # Todo List 2 | - [x] Homepage 3 | - [x] Footer 4 | - [x] Modals 5 | - [x] Toasts 6 | - [x] About us page 7 | - [x] Contact us page 8 | - [x] Login 9 | - [x] Register 10 | - [ ] Forgot Password 11 | - [ ] Reset Password 12 | - [ ] Social logins (Socialite) 13 | - [x] Admin - dashboard 14 | - [x] Admin - configurations 15 | - [x] Admin - reset system 16 | - [x] Admin Contact us messages 17 | - [x] Admin - profile 18 | - [ ] Admin - profile - logins 19 | - [ ] Admin - profile - update password 20 | - [ ] Admin - User mgmt 21 | - [x] User - dashboard 22 | - [x] User - profile 23 | - [ ] User - profile - logins 24 | - [ ] User - profile - update password 25 | 26 | 27 | ## Tests coverage 28 | - [x] Homepage 29 | - [ ] About us 30 | - [ ] Contact us 31 | - [x] Login 32 | - [x] Register 33 | - [ ] Forgot Password 34 | - [ ] Reset Password 35 | - [ ] Social logins (Socialite) 36 | - [ ] Admin - dashboard 37 | - [ ] Admin - configurations 38 | - [x] Admin - manage contact form messages 39 | - [ ] Admin - reset system 40 | - [ ] Admin - profile 41 | - [ ] Admin - User mgmt 42 | - [ ] User - dashboard 43 | - [ ] User - profile 44 | -------------------------------------------------------------------------------- /app/Actions/Admin/Cms/ContactMessages.php: -------------------------------------------------------------------------------- 1 | whereNull('last_read_at')->pluck('id')->toArray()) 23 | ->update([ 24 | 'last_read_at' => now() 25 | ]); 26 | 27 | $data = new ContactMessageResourceCollection($messages->fresh()); 28 | 29 | return $request->wantsJson() 30 | ? $data 31 | : $this->generateBackendPage('Cms/ContactMessages', [ 32 | 'messages' => $data, 33 | ]); 34 | 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /app/Actions/Admin/Cms/ContactMessagesDelete.php: -------------------------------------------------------------------------------- 1 | delete(); 21 | 22 | return $this->respJuicer($resp); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/Actions/Admin/Dashboard.php: -------------------------------------------------------------------------------- 1 | isAdmin || doe()->isSudo)) { 16 | return redirect()->route('user.dashboard'); 17 | } 18 | 19 | return $this->generateBackendPage('Dashboard', [ 20 | 'title' => "Welcome Back, " . doe()->full_name, 21 | ]); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /app/Actions/Admin/Profile/MainProfile.php: -------------------------------------------------------------------------------- 1 | generateBackendPage('Profile/MainProfile', [ 19 | 'title' => doe()->full_name . ' Profile', 20 | ]); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/Actions/Admin/Settings/Configurations.php: -------------------------------------------------------------------------------- 1 | isMethod('get')) { 22 | return $this->generateBackendPage('Settings/Configurations', [ 23 | 'configurations' => $data, 24 | ]); 25 | } 26 | 27 | $request->validate([ 28 | 'name' => 'required|string', 29 | 'id' => 'required|integer', 30 | ]); 31 | 32 | $config = Configuration::findOrFail($request->id); 33 | $resp = $config->update([ 34 | 'value' => $request->value, 35 | ]); 36 | 37 | if($resp) { 38 | // refresh redis 39 | resetRedis('update-configurations'); 40 | } 41 | 42 | return $this->respJuicer($resp); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /app/Actions/Admin/Settings/ResetSystem.php: -------------------------------------------------------------------------------- 1 | 'Clear Redis', 23 | 'action' => 'redis', 24 | ], 25 | [ 26 | 'text' => 'Clear Cached Views', 27 | 'action' => 'views', 28 | ], 29 | [ 30 | 'text' => 'Refresh Configurations (Settings)', 31 | 'action' => 'configurations', 32 | ], 33 | [ 34 | 'text' => 'Update Configurations (Settings)', 35 | 'action' => 'update-configurations', 36 | ], 37 | [ 38 | 'text' => 'Truncate & Reset Configurations (Settings)', 39 | 'action' => 'reset-configurations', 40 | ], 41 | [ 42 | 'text' => 'Run Seeder', 43 | 'action' => 'run-seeder', 44 | ], 45 | [ 46 | 'text' => 'Seed Demo Data', 47 | 'action' => 'seed-demo-data', 48 | ], 49 | ]; 50 | 51 | if($request->isMethod('get')) { 52 | 53 | return $this->generateBackendPage('Settings/ResetSystem', [ 54 | 'actions' => $actions, 55 | ]); 56 | } 57 | 58 | $request->validate([ 59 | 'action' => [ 60 | 'required', 61 | 'string', 62 | Rule::in(collect($actions)->pluck('action')->toArray()), 63 | ] 64 | ]); 65 | 66 | $repo = resolve(SystemInfoRepository::class); 67 | $status = $repo->reset($request->action); 68 | 69 | if($status) { 70 | // TODO: event 71 | return $this->respSuccess(); 72 | } 73 | 74 | return $this->respError(); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /app/Actions/Auth/LoginLinkSent.php: -------------------------------------------------------------------------------- 1 | generatePage('login-link-sent', 'Auth/LoginLinkSent'); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/Actions/Auth/LoginViaMagicLink.php: -------------------------------------------------------------------------------- 1 | validate([ 22 | 'email' => 'required|email' 23 | ]); 24 | 25 | $user = User::where('email', $request->email)->first(); 26 | 27 | if ($user) { 28 | try { 29 | $user->sendLoginLink(); 30 | } catch (Exception $e) { 31 | ddOnError($e); 32 | 33 | event(new CRUDErrorOccurred($e->getMessage())); 34 | 35 | return $this->respError(trans('An error occurred while sending the login link')); 36 | } 37 | } 38 | 39 | return redirect()->route('login-link-sent') 40 | ->withSuccess(trans('We have sent a magic link to the email. If the account exists, you shall receive an email.')); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /app/Actions/Auth/Logout.php: -------------------------------------------------------------------------------- 1 | id)); 23 | 24 | if($request->wantsJson()) 25 | { 26 | $request->user()->currentAccessToken()->delete(); 27 | 28 | return new JsonResponse([ 29 | 'message' => 'Logout Success' 30 | ], 204); 31 | } 32 | 33 | Auth::guard('web')->logout(); 34 | 35 | $request->session()->invalidate(); 36 | 37 | $request->session()->regenerateToken(); 38 | 39 | return redirect()->to('/'); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /app/Actions/Auth/RequestPasswordReset.php: -------------------------------------------------------------------------------- 1 | isMethod('get')) { 19 | return $this->generatePage('forgot-password', 'Auth/ForgotPassword', [ 20 | 'title' => 'Request Password Reset' 21 | ]); 22 | } 23 | 24 | return $request->wantsJson() 25 | ? response()->json([ 26 | 'message' => trans('Premium Feature!'), 27 | 'errors' => trans('Premium Feature!'), 28 | ], 422) 29 | : back()->withErrors(['email' => trans('Premium Feature!')]); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /app/Actions/Auth/ResetPassword.php: -------------------------------------------------------------------------------- 1 | isMethod('get')) { 19 | return $this->generatePage('reset-password', 'Auth/ResetPassword', [ 20 | 'token' => $token, 21 | 'title' => trans('Reset Password') 22 | ]); 23 | } 24 | 25 | return $request->wantsJson() 26 | ? response()->json([ 27 | 'message' => trans('Premium Feature!'), 28 | 'errors' => trans('Premium Feature!'), 29 | ], 422) 30 | : back()->withErrors(['email' => trans('Premium Feature!')]); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/Actions/Auth/VerifyLogin.php: -------------------------------------------------------------------------------- 1 | firstOrFail(); 22 | 23 | abort_unless($request->hasValidSignature() && $token->isValid(), 401); 24 | 25 | $token->consume(); 26 | 27 | $user = $token->user; 28 | 29 | // verify is user is active, + other checks 30 | if (!$user->canLogin()) { 31 | return redirect()->route('login')->withErrors([ 32 | 'username' => [trans('auth.account_not_active')], 33 | ]); 34 | } 35 | 36 | Auth::login($user); 37 | 38 | $deviceName = $request->device_name ?? $user->name . ' web device'; 39 | 40 | event(new UserLoggedIn([ 41 | 'ip' => $request->ip(), 42 | 'user_agent' => $request->header('User-Agent'), 43 | 'referer' => $request->header('Referer'), 44 | 'host' => $request->header('Host'), 45 | 'url' => $request->root(), 46 | 'device_name' => $deviceName, 47 | ], $user)); 48 | 49 | $request->session()->regenerate(); 50 | 51 | if ($user->isAdmin || $user->isSudo) { 52 | return redirect()->route('admin.dashboard'); 53 | } 54 | 55 | return redirect()->route('user.dashboard'); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /app/Actions/Frontend/About.php: -------------------------------------------------------------------------------- 1 | generatePage('about', 'About'); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/Actions/Frontend/Contact.php: -------------------------------------------------------------------------------- 1 | isMethod('get')) { 22 | $data = [ 23 | 'country' => 'United Kingdom', 24 | ]; 25 | 26 | if ($position = Location::get()) { 27 | $data = [ 28 | 'country' => $position->countryName, 29 | ]; 30 | } 31 | 32 | return $this->generatePage('contact', 'Contact', $data); 33 | } 34 | 35 | $request->validate([ 36 | 'name' => 'required|string|max:255', 37 | 'email' => 'nullable|email|max:255', 38 | 'phone' => 'nullable|string|max:20|min:10|required_without:email', 39 | 'subject' => 'required|string|max:255', 40 | 'body' => 'required|string|max:10000', 41 | ], [ 42 | 'name.required' => 'Please provide your name(s)', 43 | ]); 44 | 45 | $resp = ContactMessage::create([ 46 | 'user_id' => doe() ? doe()->id : null, 47 | 'name' => $request->name, 48 | 'email' => $request->email, 49 | 'phone' => $request->phone, 50 | 'subject' => $request->subject, 51 | 'body' => $request->body, 52 | 'site_domain' => sanitizeDomainUrl(), 53 | 'ip_address' => $request->ip(), 54 | ]); 55 | 56 | event(new ContactFormWasFilled($resp)); 57 | 58 | return $request->wantsJson() 59 | ? $this->respJuicer($resp, "We have received your message. We shall get in touch soon.") 60 | : back()->with('success', "We have received your message. We shall get in touch soon."); 61 | 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /app/Actions/Frontend/Home.php: -------------------------------------------------------------------------------- 1 | generatePage('home', 'Home', [ 17 | 'laravelVersion' => Application::VERSION, 18 | 'phpVersion' => PHP_VERSION, 19 | ]); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/Actions/User/Dashboard.php: -------------------------------------------------------------------------------- 1 | isAdmin) { 16 | return redirect()->route('admin.dashboard'); 17 | } 18 | 19 | return $this->generateBackendPage('Dashboard', [ 20 | 'title' => "Welcome Back, " . doe()->full_name, 21 | ]); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /app/Actions/User/Profile/MainProfile.php: -------------------------------------------------------------------------------- 1 | generateBackendPage('Profile/MainProfile', [ 19 | 'title' => doe()->full_name . ' Profile', 20 | ]); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/Actions/UserRedirector.php: -------------------------------------------------------------------------------- 1 | isAdmin || doe()->isSudo) { 14 | return redirect()->route('admin.dashboard'); 15 | } 16 | 17 | return redirect()->route('user.dashboard'); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /app/Console/Commands/CleanLoginTokensTable.php: -------------------------------------------------------------------------------- 1 | subWeeks(1)) 31 | ->delete(); 32 | 33 | // remove consumed tokens. 34 | // For analytics sake, we can maybe only rely on the first 35 | // option. We can track how often users use the magic link 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /app/Console/Commands/ClearRedis.php: -------------------------------------------------------------------------------- 1 | info("DONE! Refresh the page"); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /app/Console/Commands/Setup.php: -------------------------------------------------------------------------------- 1 | output->createProgressBar($steps); 45 | 46 | $bar->start(); 47 | 48 | // run default seeder 49 | $this->line('Seeding Default Seeders'); 50 | $this->call('db:seed'); 51 | 52 | $bar->advance(); 53 | 54 | // run settings 55 | $this->line('Seeding Configurations'); 56 | $settings = new Settings(); 57 | $data = $settings->data("settings"); 58 | $settings->setDefaultConfigurations($data); 59 | 60 | $bar->advance(); 61 | 62 | // clearing cache 63 | $this->line('Clearing cache'); 64 | $this->call('cache:clear'); 65 | 66 | $bar->advance(); 67 | 68 | // generate new key 69 | $this->line('Generating new key'); 70 | $this->call('key:generate'); 71 | 72 | $bar->finish(); 73 | 74 | $this->info('Done running Setup'); 75 | 76 | return 0; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /app/Console/Commands/UpdateConfigurations.php: -------------------------------------------------------------------------------- 1 | info('Updating system configuration...'); 43 | 44 | if ($this->confirm('Do you wish to truncate configurations table?', false)) 45 | { 46 | (new Settings())->truncateTable(); 47 | } 48 | 49 | if ($this->confirm('Do you wish to repopulate configurations?', true)) 50 | { 51 | $settings = new Settings(); 52 | 53 | $data = $settings->data("settings"); 54 | 55 | $settings->setDefaultConfigurations($data); 56 | 57 | $this->info('Done! '); 58 | } 59 | 60 | if ($this->confirm('Do you wish to clear cache to refresh?', true)) 61 | { 62 | Artisan::call('cache:clear'); 63 | 64 | $this->info('cache:clear completed! '); 65 | } 66 | 67 | $this->line('Done Updating system configurations!'); 68 | 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /app/Console/Commands/UpdateConfigurationsTerminal.php: -------------------------------------------------------------------------------- 1 | info('Updating system configuration...'); 42 | 43 | $settings = new Settings(); 44 | 45 | $data = $settings->data("settings"); 46 | 47 | $settings->setDefaultConfigurations($data); 48 | 49 | $this->call('cache:clear'); 50 | 51 | $this->info('Done updating system configuration...'); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /app/Console/Generators/EnumMakeCommand.php: -------------------------------------------------------------------------------- 1 | collection()) { 39 | $this->type = 'Resource collection'; 40 | } 41 | 42 | parent::handle(); 43 | } 44 | 45 | /** 46 | * Get the stub file for the generator. 47 | * 48 | * @return string 49 | */ 50 | protected function getStub() 51 | { 52 | return $this->collection() 53 | ? __DIR__.'/stubs/resource-collection.stub' 54 | : __DIR__.'/stubs/resource.stub'; 55 | } 56 | 57 | /** 58 | * Determine if the command is generating a resource collection. 59 | * 60 | * @return bool 61 | */ 62 | protected function collection() 63 | { 64 | return $this->option('collection') || 65 | Str::endsWith($this->argument('name'), 'Collection'); 66 | } 67 | 68 | /** 69 | * Get the default namespace for the class. 70 | * 71 | * @param string $rootNamespace 72 | * @return string 73 | */ 74 | protected function getDefaultNamespace($rootNamespace) 75 | { 76 | return $rootNamespace.'\Http\Resources'; 77 | } 78 | 79 | /** 80 | * Get the console command options. 81 | * 82 | * @return array 83 | */ 84 | protected function getOptions() 85 | { 86 | return [ 87 | ['collection', 'c', InputOption::VALUE_NONE, 'Create a resource collection'], 88 | ]; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /app/Console/Generators/ServiceMakeCommand.php: -------------------------------------------------------------------------------- 1 | function($query, $value) { 18 | return $query->where(function($q) use ($value) { 19 | return $q->where('param1', 'like', $value . "%"); 20 | }); 21 | }, 22 | "param2" => function($query, $value) { 23 | return $query->where('title', 'like', '%' . $value . '%'); 24 | }, 25 | "uid" => "column:uid", 26 | "id" => "column:id", 27 | ]; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /app/Console/Generators/stubs/listener-queued.stub: -------------------------------------------------------------------------------- 1 | '#', 'value' => 'id'], 15 | // 16 | 'actions' 17 | ]; 18 | 19 | /** 20 | * Transform the resource collection into an array. 21 | * 22 | * @param \Illuminate\Http\Request 23 | * @return array 24 | */ 25 | public function toArray($request) 26 | { 27 | return [ 28 | 'data' => $this->collection, 29 | 30 | 'headers' => (new Datatable)->headers($this->headers) 31 | ]; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /app/Console/Generators/stubs/resource.stub: -------------------------------------------------------------------------------- 1 | (int) $this->id, 19 | 'user_id' => $this->user_id, 20 | 21 | // dates 22 | 'created_at' => eclair($this->created_at), 23 | 'created_at_w3c' => eclair($this->created_at, true, true), 24 | 25 | // relationships 26 | 27 | ]; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /app/Console/Generators/stubs/service.stub: -------------------------------------------------------------------------------- 1 | model = new Model(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/Console/Generators/stubs/widget.stub: -------------------------------------------------------------------------------- 1 | command('sitemap:generate')->daily(); 16 | $schedule->command('system:clean-login-tokens-table')->daily(); 17 | } 18 | 19 | /** 20 | * Register the commands for the application. 21 | */ 22 | protected function commands(): void 23 | { 24 | $this->load(__DIR__.'/Commands'); 25 | $this->load(__DIR__.'/Generators'); 26 | 27 | require base_path('routes/console.php'); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /app/Contracts/RedisInterface.php: -------------------------------------------------------------------------------- 1 | error = $error; 25 | } 26 | 27 | /** 28 | * Get the channels the event should broadcast on. 29 | * 30 | * @return array 31 | */ 32 | public function broadcastOn(): array 33 | { 34 | return [ 35 | new PrivateChannel('channel-name'), 36 | ]; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /app/Events/ContactFormWasFilled.php: -------------------------------------------------------------------------------- 1 | contactMessage = $contactMessage; 26 | } 27 | 28 | /** 29 | * Get the channels the event should broadcast on. 30 | * 31 | * @return array 32 | */ 33 | public function broadcastOn(): array 34 | { 35 | return [ 36 | new PrivateChannel('channel-name'), 37 | ]; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /app/Events/UserLoggedIn.php: -------------------------------------------------------------------------------- 1 | requestData = $requestData; 25 | $this->user = $user; 26 | } 27 | 28 | /** 29 | * Get the channels the event should broadcast on. 30 | * 31 | * @return array 32 | */ 33 | public function broadcastOn(): array 34 | { 35 | return [ 36 | new PrivateChannel('channel-name'), 37 | ]; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /app/Events/UserWasCreated.php: -------------------------------------------------------------------------------- 1 | user = $user; 34 | $this->ipAddress = $ipAddress; 35 | $this->admin = $admin; 36 | } 37 | 38 | /** 39 | * Get the channels the event should broadcast on. 40 | * 41 | * @return \Illuminate\Broadcasting\Channel|array 42 | */ 43 | public function broadcastOn() 44 | { 45 | return new PrivateChannel('channel-name'); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /app/Exceptions/Handler.php: -------------------------------------------------------------------------------- 1 | , \Psr\Log\LogLevel::*> 14 | */ 15 | protected $levels = [ 16 | // 17 | ]; 18 | 19 | /** 20 | * A list of the exception types that are not reported. 21 | * 22 | * @var array> 23 | */ 24 | protected $dontReport = [ 25 | // 26 | ]; 27 | 28 | /** 29 | * A list of the inputs that are never flashed to the session on validation exceptions. 30 | * 31 | * @var array 32 | */ 33 | protected $dontFlash = [ 34 | 'current_password', 35 | 'password', 36 | 'password_confirmation', 37 | ]; 38 | 39 | /** 40 | * Register the exception handling callbacks for the application. 41 | */ 42 | public function register(): void 43 | { 44 | $this->reportable(function (Throwable $e) { 45 | // 46 | }); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /app/Http/Controllers/Controller.php: -------------------------------------------------------------------------------- 1 | expectsJson() ? null : route('login'); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/Http/Middleware/CheckIfUserActive.php: -------------------------------------------------------------------------------- 1 | user(); 20 | 21 | if (! $user) { 22 | return $next($request); 23 | } 24 | 25 | if ($user->canLogin() || $user->isSudo) { 26 | return $next($request); 27 | } else { 28 | // return redirect()->back()->with('message', 'Your user account is deactivated!'); 29 | abort(310, trans('auth.account_not_active')); 30 | } 31 | 32 | return $next($request); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /app/Http/Middleware/EncryptCookies.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | protected $except = [ 15 | // 16 | ]; 17 | } 18 | -------------------------------------------------------------------------------- /app/Http/Middleware/Localization.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | protected $except = [ 15 | // 16 | ]; 17 | } 18 | -------------------------------------------------------------------------------- /app/Http/Middleware/RedirectIfAuthenticated.php: -------------------------------------------------------------------------------- 1 | check()) { 24 | return redirect(RouteServiceProvider::HOME); 25 | } 26 | } 27 | 28 | return $next($request); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /app/Http/Middleware/RoleChecker.php: -------------------------------------------------------------------------------- 1 | user(); 22 | 23 | if(! $user) { 24 | return deny(trans('auth.unauthenticated')); 25 | } 26 | 27 | $roles = str_replace(' ', '', $roles); 28 | $roles = Str::contains($roles, ',') ? explode(',', $roles) : explode('|', $roles); 29 | 30 | if (! in_array($user->role, $roles)) { 31 | return deny(); 32 | } 33 | 34 | return $next($request); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /app/Http/Middleware/TrimStrings.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | protected $except = [ 15 | 'current_password', 16 | 'password', 17 | 'password_confirmation', 18 | ]; 19 | } 20 | -------------------------------------------------------------------------------- /app/Http/Middleware/TrustHosts.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | public function hosts(): array 15 | { 16 | return [ 17 | $this->allSubdomainsOfApplicationUrl(), 18 | ]; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/Http/Middleware/TrustProxies.php: -------------------------------------------------------------------------------- 1 | |string|null 14 | */ 15 | protected $proxies; 16 | 17 | /** 18 | * The headers that should be used to detect proxies. 19 | * 20 | * @var int 21 | */ 22 | protected $headers = 23 | Request::HEADER_X_FORWARDED_FOR | 24 | Request::HEADER_X_FORWARDED_HOST | 25 | Request::HEADER_X_FORWARDED_PORT | 26 | Request::HEADER_X_FORWARDED_PROTO | 27 | Request::HEADER_X_FORWARDED_AWS_ELB; 28 | } 29 | -------------------------------------------------------------------------------- /app/Http/Middleware/ValidateSignature.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | protected $except = [ 15 | // 'fbclid', 16 | // 'utm_campaign', 17 | // 'utm_content', 18 | // 'utm_medium', 19 | // 'utm_source', 20 | // 'utm_term', 21 | ]; 22 | } 23 | -------------------------------------------------------------------------------- /app/Http/Middleware/VerifyCsrfToken.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | protected $except = [ 15 | // 16 | ]; 17 | } 18 | -------------------------------------------------------------------------------- /app/Http/Resources/ContactMessageResource.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | public function toArray(Request $request): array 16 | { 17 | return [ 18 | 'id' => (int) $this->id, 19 | 'user_id' => $this->user_id, 20 | 'name' => $this->name, 21 | 'email' => $this->email, 22 | 'phone' => $this->phone, 23 | 'subject' => $this->subject, 24 | 'body' => $this->body, 25 | 'ip_address' => $this->ip_address, 26 | 27 | // dates 28 | 'created_at' => eclair($this->created_at), 29 | 'created_at_w3c' => eclair($this->created_at, true, true), 30 | 31 | // 32 | 'user' => new UserSlimResource($this->whenLoaded('user')), 33 | 34 | $this->mergeWhen(doe()->isAdmin, function() { 35 | return [ 36 | 'site_domain' => $this->site_domain, 37 | 'last_read_at' => eclair($this->last_read_at), 38 | 'last_read_at_w3c' => eclair($this->last_read_at, true, true), 39 | ]; 40 | }), 41 | ]; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /app/Http/Resources/ContactMessageResourceCollection.php: -------------------------------------------------------------------------------- 1 | '#', 'value' => 'id'], 16 | 'name', 'contact', 17 | ['text' => 'Message', 'value' => 'body'], 18 | 'actions' 19 | ]; 20 | 21 | /** 22 | * Transform the resource collection into an array. 23 | * 24 | * @param \Illuminate\Http\Request 25 | * @return array 26 | */ 27 | public function toArray($request) 28 | { 29 | return [ 30 | 'data' => $this->collection, 31 | 32 | 'headers' => (new Datatable)->headers($this->headers) 33 | ]; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /app/Http/Resources/UserResource.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | public function toArray(Request $request): array 16 | { 17 | return [ 18 | 'id' => (int) $this->id, 19 | 'name' => $this->name, 20 | 'email' => $this->email, 21 | 'status' => $this->status, 22 | 'phone' => $this->phone, 23 | 'first_name' => $this->first_name, 24 | 'last_name' => $this->last_name, 25 | 'full_name' => $this->fullName, 26 | 'role' => $this->role, 27 | 'date_of_birth' => $this->date_of_birth ? $this->date_of_birth->format('Y-m-d') : null, 28 | 'timezone' => $this->timezone, 29 | 30 | // dates 31 | 'email_verified_at' => eclair($this->email_verified_at), 32 | 'email_verified_at_w3c' => eclair($this->email_verified_at, true, true), 33 | 'phone_verified_at' => eclair($this->phone_verified_at), 34 | 'phone_verified_at_w3c' => eclair($this->phone_verified_at, true, true), 35 | 'last_login_at' => eclair($this->last_login_at), 36 | 'last_login_at_w3c' => eclair($this->last_login_at, true, true), 37 | 'created_at' => eclair($this->created_at), 38 | 'created_at_w3c' => eclair($this->created_at, true, true), 39 | 'updated_at' => eclair($this->updated_at), 40 | 'updated_at_w3c' => eclair($this->updated_at, true, true), 41 | 'verified_at' => eclair($this->verified_at), 42 | 'verified_at_w3c' => eclair($this->verified_at, true, true), 43 | 44 | // links 45 | 'avatar_url' => $this->avatar_url, 46 | 47 | ]; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /app/Http/Resources/UserSlimResource.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | public function toArray(Request $request): array 16 | { 17 | return [ 18 | 'id' => (int) $this->id, 19 | 'name' => $this->name, 20 | 'aka' => $this->aka, 21 | 'email' => $this->email, 22 | 'full_name' => $this->full_name, 23 | 'phone' => $this->phone, 24 | 'status' => $this->status, 25 | 26 | // relationships 27 | 'role' => $this->role, 28 | 29 | // links 30 | 'avatar_url' => $this->avatar_url, 31 | ]; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /app/Jobs/SendLoginAlertEmail.php: -------------------------------------------------------------------------------- 1 | user = $user; 31 | $this->requestData = $requestData; 32 | } 33 | 34 | /** 35 | * Execute the job. 36 | * 37 | * @return void 38 | */ 39 | public function handle() 40 | { 41 | // send notification 42 | if($this->user->created_at >= now()->subMinutes(5)) { 43 | // user recently added or not active. No need to send an alert 44 | 45 | // log the activity 46 | if($this->user->isSudo) 47 | Log::channel('sudo-logins')->info('New user login. Email: ' . $this->user->email); 48 | else 49 | Log::channel('user-logins')->info('New user login. Email: ' . $this->user->email); 50 | 51 | } else { 52 | $this->user->notify(new NotifyUserOfLogin($this->requestData)); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /app/Library/RedisConfigurations/Extras.php: -------------------------------------------------------------------------------- 1 | keys = config('system_redis.extras'); 17 | } 18 | 19 | /* 20 | * Returns selects data to the repository for redis storage 21 | */ 22 | public function data($key = null) 23 | { 24 | $key = str_replace(config('system_redis.application_prefix'), '', $key); 25 | 26 | if(Schema::hasTable("${key}")) { 27 | return DB::table("${key}")->get(); 28 | } 29 | 30 | return collect(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/Library/RedisConfigurations/Models.php: -------------------------------------------------------------------------------- 1 | keys = config('system_redis.models'); 16 | } 17 | 18 | /* 19 | * Returns selects data to the repository for redis storage 20 | */ 21 | public function data($key = null) 22 | { 23 | if(class_exists($key)) 24 | { 25 | $model = new $key(); 26 | $tableName = $model->getTable(); 27 | 28 | if(Schema::hasTable("${tableName}")) { 29 | $data = $model->get()->toArray(); 30 | 31 | return [ 32 | 'key' => $tableName, 33 | 'data' => $data, 34 | ]; 35 | } 36 | 37 | return []; 38 | } 39 | 40 | return collect(); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /app/Library/RedisConfigurations/RedisTemplate.php: -------------------------------------------------------------------------------- 1 | setKeys(); 12 | } 13 | 14 | abstract public function setKeys(); 15 | 16 | /* 17 | * Return keys as they are stored in redis 18 | */ 19 | public function getKeys() 20 | { 21 | return $this->keys; 22 | } 23 | 24 | } -------------------------------------------------------------------------------- /app/Library/RedisConfigurations/StaticData.php: -------------------------------------------------------------------------------- 1 | keys = config('system_redis.static_data'); 15 | } 16 | 17 | /* 18 | * Returns selects data to the repository for redis storage 19 | */ 20 | public function data($key = null) 21 | { 22 | $data = collect(config('system_redis.static_data')); 23 | 24 | return $data->where('key', $key)->first()['data']; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/Library/events.php: -------------------------------------------------------------------------------- 1 | [ 14 | CRUDErrorHasOccurred::class, 15 | ], 16 | 17 | UserLoggedIn::class => [ 18 | UserHasLoggedIn::class, 19 | ], 20 | 21 | UserWasCreated::class => [ 22 | UserHasBeenCreated::class, 23 | ], 24 | 25 | ContactFormWasFilled::class => [ 26 | ContactFormHasBeenFilled::class, 27 | ], 28 | 29 | 30 | ]; 31 | -------------------------------------------------------------------------------- /app/Listeners/CRUDErrorHasOccurred.php: -------------------------------------------------------------------------------- 1 | notify(new CrudErrorNotification($event->error)); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /app/Listeners/ContactFormHasBeenFilled.php: -------------------------------------------------------------------------------- 1 | contactMessage; 35 | 36 | // send mail 37 | if($contactMessage->email) { 38 | Mail::to($contactMessage->email) 39 | ->send(new ContactFormMailable($contactMessage)); 40 | } 41 | 42 | // notify admins 43 | foreach(adminUsers() as $admin) 44 | { 45 | $admin->notify(new NotifyAdmin($contactMessage->name . " just left a message", $contactMessage->subject)); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /app/Listeners/UserHasBeenCreated.php: -------------------------------------------------------------------------------- 1 | user; 33 | $ipAddress = $event->ipAddress; 34 | $admin = $event->admin; 35 | 36 | // notify admins 37 | foreach(adminUsers() as $admin) 38 | { 39 | $message = $admin 40 | ? $admin->aka . " added a new user in the system." 41 | : "Email: " . $user->email; 42 | 43 | $admin->notify(new NotifyAdmin($user->aka . "'s account has just been created!", $message, '#', $ipAddress)); 44 | } 45 | 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /app/Listeners/UserHasLoggedIn.php: -------------------------------------------------------------------------------- 1 | user; 29 | $requestData = $event->requestData; 30 | 31 | $userLogin = new UserLogin(); 32 | $userLogin->user_id = $user->id; 33 | $userLogin->ip_address = $requestData['ip']; 34 | $userLogin->user_agent = $requestData['user_agent']; 35 | $userLogin->referer = $requestData['referer']; 36 | $userLogin->host = $requestData['host']; 37 | $userLogin->notes = 'Device name: ' . $requestData['device_name']; 38 | $userLogin->save(); 39 | 40 | $user->update([ 41 | 'last_login_at' => now(), 42 | 'last_login_ip' => $requestData['ip'], 43 | ]); 44 | 45 | dispatch(new SendLoginAlertEmail($user, $requestData)); 46 | 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /app/Mail/ContactFormMailable.php: -------------------------------------------------------------------------------- 1 | contactMessage = $contactMessage; 28 | } 29 | 30 | /** 31 | * Build the message. 32 | * 33 | * @return $this 34 | */ 35 | public function build() 36 | { 37 | Log::channel('emails-sent')->info('Contact Form Message alert sent to ' . $this->contactMessage->email); 38 | 39 | $config = $this->noReplyEmail(); 40 | 41 | return $this->from($config['email'], $config['name']) 42 | ->subject('Contact Form Submission') 43 | ->markdown('emails.contact-form-email'); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /app/Mail/MagicLoginLink.php: -------------------------------------------------------------------------------- 1 | plaintextToken = $plaintextToken; 27 | $this->expiresAt = $expiresAt; 28 | 29 | Log::info('Login token: ' . $this->plaintextToken . ', expiry: ' . $this->expiresAt); 30 | } 31 | 32 | /** 33 | * Get the message envelope. 34 | */ 35 | public function envelope(): Envelope 36 | { 37 | return new Envelope( 38 | subject: config('app.name') . ' Login Verification', 39 | ); 40 | } 41 | 42 | /** 43 | * Get the message content definition. 44 | */ 45 | public function content(): Content 46 | { 47 | return new Content( 48 | markdown: 'emails.magic-login-link', 49 | with: [ 50 | 'url' => URL::temporarySignedRoute('verify-login', $this->expiresAt, [ 51 | 'token' => $this->plaintextToken, 52 | ]), 53 | ], 54 | ); 55 | } 56 | 57 | /** 58 | * Get the attachments for the message. 59 | * 60 | * @return array 61 | */ 62 | public function attachments(): array 63 | { 64 | return []; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /app/Models/Configuration.php: -------------------------------------------------------------------------------- 1 | table = config('system_redis.defaults.tables.configurations'); 25 | 26 | parent::__construct($attributes); 27 | } 28 | 29 | public function getValueAttribute() 30 | { 31 | if ($this->type == self::TYPE_BOOL) { 32 | return (bool) $this->attributes['value']; 33 | } 34 | 35 | if ($this->type == self::TYPE_NUMBER) { 36 | return strpos($this->attributes['value'], '.') !== false 37 | ? (int) $this->attributes['value'] 38 | : (float) $this->attributes['value']; 39 | } 40 | 41 | return $this->attributes['value']; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /app/Models/ContactMessage.php: -------------------------------------------------------------------------------- 1 | 'datetime', 26 | ]; 27 | 28 | /** 29 | * belongs to a user 30 | */ 31 | public function user() 32 | { 33 | return $this->belongsTo(User::class, 'user_id'); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /app/Models/LoginToken.php: -------------------------------------------------------------------------------- 1 | 'datetime', 22 | 'consumed_at' => 'datetime', 23 | ]; 24 | 25 | public function user(): BelongsTo 26 | { 27 | return $this->belongsTo(User::class); 28 | } 29 | 30 | public function isValid() : bool 31 | { 32 | return !$this->isExpired() && !$this->isConsumed(); 33 | } 34 | 35 | public function isExpired() : bool 36 | { 37 | return $this->expires_at->isBefore(now()); 38 | } 39 | 40 | public function isConsumed() : bool 41 | { 42 | return $this->consumed_at !== null; 43 | } 44 | 45 | public function consume() : void 46 | { 47 | $this->consumed_at = now(); 48 | $this->save(); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /app/Models/UserLogin.php: -------------------------------------------------------------------------------- 1 | belongsTo(User::class); 27 | } 28 | 29 | /** 30 | * get logins without user; either due to deletion or something 31 | * 32 | * @param $query 33 | * 34 | * @return mixed 35 | */ 36 | public function scopeOrphans($query) 37 | { 38 | return $query->whereDoesntHave('user'); 39 | } 40 | 41 | /** 42 | * get logins only for humans 43 | */ 44 | public function scopeHumans($query) 45 | { 46 | return $query->whereHas('user', function ($q) { 47 | $q->humans(); 48 | }); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /app/Models/UserRelationshipsTrait.php: -------------------------------------------------------------------------------- 1 | hasMany(UserLogin::class); 13 | } 14 | 15 | public function latestLogin(): HasOne 16 | { 17 | return $this->logins()->one()->latestOfMany(); 18 | } 19 | 20 | public function contactMessages(): HasMany 21 | { 22 | return $this->hasMany(ContactMessage::class); 23 | } 24 | 25 | public function loginTokens(): HasMany 26 | { 27 | return $this->hasMany(LoginToken::class); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /app/Models/UserScopesTrait.php: -------------------------------------------------------------------------------- 1 | where('role', '<>', [User::ROLE_ADMIN, User::ROLE_SUPERADMIN, User::ROLE_DEVELOPER]); 13 | } 14 | 15 | /* 16 | * Fetch all the users with no sudo role 17 | */ 18 | public function scopeNonAdmins($query) 19 | { 20 | return $this->scopeHumans($query); 21 | } 22 | 23 | /* 24 | * Fetch all the users with admin role 25 | */ 26 | public function scopeAdmins($query) 27 | { 28 | if(setting('add_sudo_to_admin_group')) { 29 | return $query->whereIn('role', [User::ROLE_ADMIN, User::ROLE_SUPERADMIN, User::ROLE_DEVELOPER]); 30 | } 31 | 32 | return $query->where('role', User::ROLE_ADMIN); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /app/Notifications/CrudErrorNotification.php: -------------------------------------------------------------------------------- 1 | error = $error; 28 | } 29 | 30 | /** 31 | * Get the notification's delivery channels. 32 | * 33 | * @param mixed $notifiable 34 | * @return array 35 | */ 36 | public function via($notifiable) 37 | { 38 | return ['slack']; 39 | } 40 | 41 | /** 42 | * Get the mail representation of the notification. 43 | * 44 | * @param mixed $notifiable 45 | * @return \Illuminate\Notifications\Messages\MailMessage 46 | */ 47 | public function toMail($notifiable) 48 | { 49 | return (new MailMessage) 50 | ->line('The introduction to the notification.') 51 | ->action('Notification Action', url('/')) 52 | ->line('Thank you for using our application!'); 53 | } 54 | 55 | /** 56 | * Get the array representation of the notification. 57 | * 58 | * @param mixed $notifiable 59 | * @return array 60 | */ 61 | public function toArray($notifiable) 62 | { 63 | return [ 64 | // 65 | ]; 66 | } 67 | 68 | /** 69 | * Get the Slack representation of the notification. 70 | * 71 | * @param mixed $notifiable 72 | * @return SlackMessage 73 | */ 74 | public function toSlack(object $notifiable): SlackMessage 75 | { 76 | $message = "[" . config('app.name') . " CRUD Error] "; 77 | $message .= $this->error; 78 | 79 | return (new SlackMessage) 80 | // ->from(config('app.name'), ':anguished:') 81 | // ->to("#" . config('logging.channels.slack.url')) 82 | ->content($message); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /app/Notifications/NotifyAdmin.php: -------------------------------------------------------------------------------- 1 | title = $title; 30 | $this->message = $message; 31 | $this->link = $link; 32 | $this->ipAddress = $ipAddress; 33 | } 34 | 35 | /** 36 | * Get the notification's delivery channels. 37 | * 38 | * @return array 39 | */ 40 | public function via(object $notifiable): array 41 | { 42 | // return $notifiable->prefers_sms ? ['nexmo'] : ['mail', 'database']; 43 | return ['database']; 44 | } 45 | 46 | /** 47 | * Get the mail representation of the notification. 48 | */ 49 | public function toMail(object $notifiable): MailMessage 50 | { 51 | return (new MailMessage) 52 | ->line('The introduction to the notification.') 53 | ->action('Notification Action', url('/')) 54 | ->line('Thank you for using our application!'); 55 | } 56 | 57 | /** 58 | * Get the array representation of the notification. 59 | * 60 | * @return array 61 | */ 62 | public function toArray(object $notifiable): array 63 | { 64 | return [ 65 | 'title' => $this->title, 66 | 'message' => $this->message, 67 | 'link' => $this->link, 68 | 'ip_address' => $this->ipAddress, 69 | ]; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /app/Notifications/NotifyUserOfPasswordHardReset.php: -------------------------------------------------------------------------------- 1 | password = $password; 27 | } 28 | 29 | /** 30 | * Get the notification's delivery channels. 31 | * 32 | * @return array 33 | */ 34 | public function via(object $notifiable): array 35 | { 36 | return ['mail']; 37 | } 38 | 39 | /** 40 | * Get the mail representation of the notification. 41 | */ 42 | public function toMail(object $notifiable): MailMessage 43 | { 44 | $message = new MailMessage; 45 | $config = $this->noReplyEmail(); 46 | $subject = 'Password Updated!'; 47 | $markdown = "emails.password-hard-reset"; 48 | 49 | $message 50 | ->from($config['email'], $config['name']) 51 | ->subject($subject) 52 | ->markdown($markdown, [ 53 | 'support_name' => "Support", 54 | 'support_position' => 'Head Office', 55 | 'user' => $notifiable, 56 | 'password' => $this->password, 57 | 'actionText' => 'Login', 58 | 'actionUrl' => route('login'), 59 | ]); 60 | 61 | return $message; 62 | } 63 | 64 | /** 65 | * Get the array representation of the notification. 66 | * 67 | * @return array 68 | */ 69 | public function toArray(object $notifiable): array 70 | { 71 | return [ 72 | // 73 | ]; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /app/Providers/AppServiceProvider.php: -------------------------------------------------------------------------------- 1 | registerFacades(); 15 | } 16 | 17 | /** 18 | * Bootstrap any application services. 19 | */ 20 | public function boot(): void 21 | { 22 | if ($this->app->isLocal()) { 23 | $this->app->register(\Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider::class); 24 | } 25 | 26 | if(env('DEBUGBAR_ENABLED', false)) { 27 | \Debugbar::enable(); 28 | } 29 | 30 | $this->loadMacros(); 31 | } 32 | 33 | 34 | /** 35 | * register app macros 36 | * convert to collection this way: 37 | * $collection = collect($data)->recursive(); // $data is multidimensional array 38 | */ 39 | public function loadMacros() 40 | { 41 | \Illuminate\Support\Collection::macro('recursive', function () { 42 | return $this->map(function ($value) { 43 | if (is_array($value) || is_object($value)) { 44 | return collect($value)->recursive(); 45 | } 46 | 47 | return $value; 48 | }); 49 | }); 50 | 51 | \Illuminate\Support\Collection::macro('sortByDate', function (string $column = 'created_at', bool $descending = true) { 52 | return $this->sortBy(function ($datum) use ($column) { 53 | return strtotime(((object)$datum)->$column); 54 | }, SORT_REGULAR, $descending); 55 | }); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /app/Providers/AuthServiceProvider.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | protected $policies = [ 16 | // 'App\Models\Model' => 'App\Policies\ModelPolicy', 17 | ]; 18 | 19 | /** 20 | * Register any authentication / authorization services. 21 | */ 22 | public function boot(): void 23 | { 24 | // 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/Providers/BroadcastServiceProvider.php: -------------------------------------------------------------------------------- 1 | > 16 | */ 17 | protected $listen = [ 18 | Registered::class => [ 19 | SendEmailVerificationNotification::class, 20 | ], 21 | ]; 22 | 23 | /** 24 | * Register any events for your application. 25 | */ 26 | public function boot(): void 27 | { 28 | // 29 | } 30 | 31 | /** 32 | * Determine if events and listeners should be automatically discovered. 33 | */ 34 | public function shouldDiscoverEvents(): bool 35 | { 36 | return false; 37 | } 38 | 39 | /** 40 | * Get the events and handlers. 41 | * 42 | * @return array 43 | */ 44 | public function listens() 45 | { 46 | include app_path('Library/events.php'); 47 | 48 | return array_merge($this->listen, $events); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /app/Providers/RouteServiceProvider.php: -------------------------------------------------------------------------------- 1 | configureRateLimiting(); 28 | 29 | $this->routes(function () { 30 | Route::middleware('api') 31 | ->prefix('api') 32 | ->as('api.') 33 | ->group(base_path('routes/api.php')); 34 | 35 | Route::middleware('web') 36 | ->group(base_path('routes/web.php')); 37 | }); 38 | } 39 | 40 | /** 41 | * Configure the rate limiters for the application. 42 | */ 43 | protected function configureRateLimiting(): void 44 | { 45 | RateLimiter::for('api', function (Request $request) { 46 | return Limit::perMinute(60)->by($request->user()?->id ?: $request->ip()); 47 | }); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /app/Repositories/SystemInfoRepository.php: -------------------------------------------------------------------------------- 1 | del($key) : null; 55 | return true; 56 | break; 57 | 58 | case 'run-seeder': 59 | (new DatabaseSeeder)->run(); 60 | return true; 61 | break; 62 | 63 | case 'seed-demo-data': 64 | (new DemoTableSeeder)->run(); 65 | return true; 66 | break; 67 | 68 | default: 69 | break; 70 | } 71 | 72 | return false; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /app/Traits/QueueMailConstants.php: -------------------------------------------------------------------------------- 1 | $email, 21 | 'name' => $name, 22 | ]; 23 | } 24 | 25 | /** 26 | * Get Company Email 27 | * 28 | * @return string 29 | */ 30 | public function organizationEmail() 31 | { 32 | return env('MAIL_FROM_ADDRESS'); 33 | } 34 | 35 | /** 36 | * Get Company Name 37 | * 38 | * @return string 39 | */ 40 | public function organizationName() 41 | { 42 | return env('APP_NAME'); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /artisan: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | make(Illuminate\Contracts\Console\Kernel::class); 34 | 35 | $status = $kernel->handle( 36 | $input = new Symfony\Component\Console\Input\ArgvInput, 37 | new Symfony\Component\Console\Output\ConsoleOutput 38 | ); 39 | 40 | /* 41 | |-------------------------------------------------------------------------- 42 | | Shutdown The Application 43 | |-------------------------------------------------------------------------- 44 | | 45 | | Once Artisan has finished running, we will fire off the shutdown events 46 | | so that any final work may be done by the application before we shut 47 | | down the process. This is the last thing to happen to the request. 48 | | 49 | */ 50 | 51 | $kernel->terminate($input, $status); 52 | 53 | exit($status); 54 | -------------------------------------------------------------------------------- /bootstrap/app.php: -------------------------------------------------------------------------------- 1 | singleton( 30 | Illuminate\Contracts\Http\Kernel::class, 31 | App\Http\Kernel::class 32 | ); 33 | 34 | $app->singleton( 35 | Illuminate\Contracts\Console\Kernel::class, 36 | App\Console\Kernel::class 37 | ); 38 | 39 | $app->singleton( 40 | Illuminate\Contracts\Debug\ExceptionHandler::class, 41 | App\Exceptions\Handler::class 42 | ); 43 | 44 | /* 45 | |-------------------------------------------------------------------------- 46 | | Return The Application 47 | |-------------------------------------------------------------------------- 48 | | 49 | | This script returns the application instance. The instance is given to 50 | | the calling script so we can separate the building of the instances 51 | | from the actual running of the application and sending responses. 52 | | 53 | */ 54 | 55 | return $app; 56 | -------------------------------------------------------------------------------- /bootstrap/cache/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /config/cors.php: -------------------------------------------------------------------------------- 1 | ['api/*', 'sanctum/csrf-cookie'], 19 | 20 | 'allowed_methods' => ['*'], 21 | 22 | 'allowed_origins' => ['*'], 23 | 24 | 'allowed_origins_patterns' => [], 25 | 26 | 'allowed_headers' => ['*'], 27 | 28 | 'exposed_headers' => [], 29 | 30 | 'max_age' => 0, 31 | 32 | 'supports_credentials' => false, 33 | 34 | ]; 35 | -------------------------------------------------------------------------------- /config/hashing.php: -------------------------------------------------------------------------------- 1 | 'bcrypt', 19 | 20 | /* 21 | |-------------------------------------------------------------------------- 22 | | Bcrypt Options 23 | |-------------------------------------------------------------------------- 24 | | 25 | | Here you may specify the configuration options that should be used when 26 | | passwords are hashed using the Bcrypt algorithm. This will allow you 27 | | to control the amount of time it takes to hash the given password. 28 | | 29 | */ 30 | 31 | 'bcrypt' => [ 32 | 'rounds' => env('BCRYPT_ROUNDS', 10), 33 | ], 34 | 35 | /* 36 | |-------------------------------------------------------------------------- 37 | | Argon Options 38 | |-------------------------------------------------------------------------- 39 | | 40 | | Here you may specify the configuration options that should be used when 41 | | passwords are hashed using the Argon algorithm. These will allow you 42 | | to control the amount of time it takes to hash the given password. 43 | | 44 | */ 45 | 46 | 'argon' => [ 47 | 'memory' => 65536, 48 | 'threads' => 1, 49 | 'time' => 4, 50 | ], 51 | 52 | ]; 53 | -------------------------------------------------------------------------------- /config/inertia.php: -------------------------------------------------------------------------------- 1 | [ 23 | 24 | 'enabled' => true, 25 | 26 | 'url' => 'http://127.0.0.1:13714', 27 | 28 | // 'bundle' => base_path('bootstrap/ssr/ssr.mjs'), 29 | 30 | ], 31 | 32 | /* 33 | |-------------------------------------------------------------------------- 34 | | Testing 35 | |-------------------------------------------------------------------------- 36 | | 37 | | The values described here are used to locate Inertia components on the 38 | | filesystem. For instance, when using `assertInertia`, the assertion 39 | | attempts to locate the component as a file relative to any of the 40 | | paths AND with any of the extensions specified here. 41 | | 42 | */ 43 | 44 | 'testing' => [ 45 | 46 | 'ensure_pages_exist' => true, 47 | 48 | 'page_paths' => [ 49 | 50 | resource_path('ts/Pages'), 51 | 52 | ], 53 | 54 | 'page_extensions' => [ 55 | 56 | 'js', 57 | 'jsx', 58 | 'svelte', 59 | 'ts', 60 | 'tsx', 61 | 'vue', 62 | 63 | ], 64 | 65 | ], 66 | 67 | ]; 68 | -------------------------------------------------------------------------------- /config/services.php: -------------------------------------------------------------------------------- 1 | [ 18 | 'domain' => env('MAILGUN_DOMAIN'), 19 | 'secret' => env('MAILGUN_SECRET'), 20 | 'endpoint' => env('MAILGUN_ENDPOINT', 'api.mailgun.net'), 21 | 'scheme' => 'https', 22 | ], 23 | 24 | 'postmark' => [ 25 | 'token' => env('POSTMARK_TOKEN'), 26 | ], 27 | 28 | 'ses' => [ 29 | 'key' => env('AWS_ACCESS_KEY_ID'), 30 | 'secret' => env('AWS_SECRET_ACCESS_KEY'), 31 | 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'), 32 | ], 33 | 34 | ]; 35 | -------------------------------------------------------------------------------- /config/view.php: -------------------------------------------------------------------------------- 1 | [ 17 | resource_path('views'), 18 | ], 19 | 20 | /* 21 | |-------------------------------------------------------------------------- 22 | | Compiled View Path 23 | |-------------------------------------------------------------------------- 24 | | 25 | | This option determines where all the compiled Blade templates will be 26 | | stored for your application. Typically, this is within the storage 27 | | directory. However, as usual, you are free to change this value. 28 | | 29 | */ 30 | 31 | 'compiled' => env( 32 | 'VIEW_COMPILED_PATH', 33 | realpath(storage_path('framework/views')) 34 | ), 35 | 36 | ]; 37 | -------------------------------------------------------------------------------- /database/.gitignore: -------------------------------------------------------------------------------- 1 | *.sqlite* 2 | -------------------------------------------------------------------------------- /database/factories/ContactMessageFactory.php: -------------------------------------------------------------------------------- 1 | 10 | */ 11 | class ContactMessageFactory extends Factory 12 | { 13 | /** 14 | * Define the model's default state. 15 | * 16 | * @return array 17 | */ 18 | public function definition(): array 19 | { 20 | $userId = null; 21 | $applyUser = $this->faker->boolean(); 22 | 23 | if($applyUser) { 24 | $userId = User::inRandomOrder()->first()->id ?? null; 25 | } 26 | 27 | return [ 28 | 'user_id' => $userId, 29 | 'name' => $this->faker->name(), 30 | 'email' => $this->faker->email(), 31 | 'phone' => $this->faker->phoneNumber(), 32 | 'subject' => $this->faker->text(), 33 | 'body' => $this->faker->paragraph(1), 34 | 'ip_address' => $this->faker->ipv4(), 35 | 'site_domain' => env('APP_URL'), 36 | ]; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /database/factories/UserFactory.php: -------------------------------------------------------------------------------- 1 | 24 | */ 25 | public function definition(): array 26 | { 27 | $firstName = $this->faker->firstName(); 28 | $lastName = $this->faker->lastName(); 29 | 30 | return [ 31 | 'name' => Str::slug("$firstName $lastName"), 32 | 'email' => $this->faker->unique()->safeEmail(), 33 | 'email_verified_at' => now(), 34 | 'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password 35 | 'remember_token' => Str::random(10), 36 | 'status' => User::STATUS_ACTIVE, 37 | 'created_at' => $this->faker->dateTimeBetween('-3 years', 'now'), 38 | 'first_name' => $firstName, 39 | 'last_name' => $lastName, 40 | 'phone' => $this->faker->phoneNumber(), 41 | 'role' => User::ROLES[rand(0, count(User::ROLES) -1)] 42 | ]; 43 | } 44 | 45 | /** 46 | * Indicate that the model's email address should be unverified. 47 | */ 48 | public function unverified(): static 49 | { 50 | return $this->state(function (array $attributes) { 51 | return [ 52 | 'email_verified_at' => null, 53 | ]; 54 | }); 55 | } 56 | 57 | /** 58 | * Configure the model factory. 59 | * 60 | * @return $this 61 | */ 62 | public function configure() 63 | { 64 | return $this->afterMaking(function (User $user) { 65 | // 66 | })->afterCreating(function (User $user) { 67 | // 68 | }); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /database/maxmind/GeoLite2-City.mmdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syntaxlexx/laravelte/e857ac623e3fc0d867b3ca6373d7c8af6219ec4b/database/maxmind/GeoLite2-City.mmdb -------------------------------------------------------------------------------- /database/maxmind/GeoLite2-Country.mmdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syntaxlexx/laravelte/e857ac623e3fc0d867b3ca6373d7c8af6219ec4b/database/maxmind/GeoLite2-Country.mmdb -------------------------------------------------------------------------------- /database/migrations/2014_10_12_000000_create_users_table.php: -------------------------------------------------------------------------------- 1 | id(); 16 | $table->string('name'); 17 | $table->string('email')->unique(); 18 | $table->timestamp('email_verified_at')->nullable(); 19 | $table->string('password'); 20 | $table->rememberToken(); 21 | $table->foreignId('current_team_id')->nullable(); 22 | $table->string('profile_photo_path', 2048)->nullable(); 23 | $table->timestamps(); 24 | }); 25 | 26 | if(env('DB_CONNECTION') != 'sqlite') { 27 | $index = rand(2344, 8988); 28 | DB::statement("ALTER TABLE users AUTO_INCREMENT = $index"); 29 | } 30 | } 31 | 32 | /** 33 | * Reverse the migrations. 34 | */ 35 | public function down(): void 36 | { 37 | Schema::dropIfExists('users'); 38 | } 39 | }; 40 | -------------------------------------------------------------------------------- /database/migrations/2014_10_12_100000_create_password_reset_tokens_table.php: -------------------------------------------------------------------------------- 1 | string('email')->primary(); 16 | $table->string('token'); 17 | $table->timestamp('created_at')->nullable(); 18 | }); 19 | } 20 | 21 | /** 22 | * Reverse the migrations. 23 | */ 24 | public function down(): void 25 | { 26 | Schema::dropIfExists('password_reset_tokens'); 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /database/migrations/2019_08_19_000000_create_failed_jobs_table.php: -------------------------------------------------------------------------------- 1 | id(); 16 | $table->string('uuid')->unique(); 17 | $table->text('connection'); 18 | $table->text('queue'); 19 | $table->longText('payload'); 20 | $table->longText('exception'); 21 | $table->timestamp('failed_at')->useCurrent(); 22 | }); 23 | } 24 | 25 | /** 26 | * Reverse the migrations. 27 | */ 28 | public function down(): void 29 | { 30 | Schema::dropIfExists('failed_jobs'); 31 | } 32 | }; 33 | -------------------------------------------------------------------------------- /database/migrations/2019_12_14_000001_create_personal_access_tokens_table.php: -------------------------------------------------------------------------------- 1 | id(); 16 | $table->morphs('tokenable'); 17 | $table->string('name'); 18 | $table->string('token', 64)->unique(); 19 | $table->text('abilities')->nullable(); 20 | $table->timestamp('last_used_at')->nullable(); 21 | $table->timestamp('expires_at')->nullable(); 22 | $table->timestamps(); 23 | }); 24 | } 25 | 26 | /** 27 | * Reverse the migrations. 28 | */ 29 | public function down(): void 30 | { 31 | Schema::dropIfExists('personal_access_tokens'); 32 | } 33 | }; 34 | -------------------------------------------------------------------------------- /database/migrations/2023_03_29_173045_create_sessions_table.php: -------------------------------------------------------------------------------- 1 | string('id')->primary(); 16 | $table->foreignId('user_id')->nullable()->index(); 17 | $table->string('ip_address', 45)->nullable(); 18 | $table->text('user_agent')->nullable(); 19 | $table->longText('payload'); 20 | $table->integer('last_activity')->index(); 21 | }); 22 | } 23 | 24 | /** 25 | * Reverse the migrations. 26 | */ 27 | public function down(): void 28 | { 29 | Schema::dropIfExists('sessions'); 30 | } 31 | }; 32 | -------------------------------------------------------------------------------- /database/migrations/2023_03_30_185913_create_notifications_table.php: -------------------------------------------------------------------------------- 1 | uuid('id')->primary(); 16 | $table->string('type'); 17 | $table->morphs('notifiable'); 18 | $table->text('data'); 19 | $table->timestamp('read_at')->nullable(); 20 | $table->timestamps(); 21 | }); 22 | } 23 | 24 | /** 25 | * Reverse the migrations. 26 | */ 27 | public function down(): void 28 | { 29 | Schema::dropIfExists('notifications'); 30 | } 31 | }; 32 | -------------------------------------------------------------------------------- /database/migrations/2023_03_30_190907_create_configurations_table.php: -------------------------------------------------------------------------------- 1 | id(); 17 | $table->string('name')->unique(); 18 | $table->string('value')->nullable(); 19 | $table->string('type')->default('text')->comment(implode(', ', [Configuration::TYPE_BOOL,Configuration::TYPE_TEXT,Configuration::TYPE_NUMBER])); 20 | $table->string('description')->nullable(); 21 | $table->string('hint')->nullable()->comment('The hint to use for the setting'); 22 | $table->string('default')->nullable()->comment('default value. Good for routes with parameters'); 23 | $table->timestamps(); 24 | }); 25 | } 26 | 27 | /** 28 | * Reverse the migrations. 29 | */ 30 | public function down(): void 31 | { 32 | Schema::dropIfExists('configurations'); 33 | } 34 | }; 35 | -------------------------------------------------------------------------------- /database/migrations/2023_04_05_234427_create_user_logins_table.php: -------------------------------------------------------------------------------- 1 | id(); 16 | $table->foreignId('user_id'); 17 | $table->string('ip_address')->nullable(); 18 | $table->string('user_agent')->nullable(); 19 | $table->string('referer')->nullable(); 20 | $table->string('host')->nullable(); 21 | $table->text('notes')->nullable(); 22 | 23 | $table->timestamps(); 24 | $table->softDeletes(); 25 | }); 26 | } 27 | 28 | /** 29 | * Reverse the migrations. 30 | */ 31 | public function down(): void 32 | { 33 | Schema::dropIfExists('user_logins'); 34 | } 35 | }; 36 | -------------------------------------------------------------------------------- /database/migrations/2023_04_08_144736_create_contact_messages_table.php: -------------------------------------------------------------------------------- 1 | id(); 16 | $table->foreignId('user_id')->nullable()->comment('The sender. Could be null because '); 17 | $table->string('name'); 18 | $table->string('email')->nullable(); 19 | $table->string('phone')->nullable(); 20 | $table->string('subject')->nullable(); 21 | $table->text('body')->nullable(); 22 | $table->string('site_domain')->nullable(); 23 | $table->string('ip_address')->nullable(); 24 | $table->timestamp('last_read_at')->nullable(); 25 | 26 | $table->timestamps(); 27 | $table->softDeletes(); 28 | }); 29 | } 30 | 31 | /** 32 | * Reverse the migrations. 33 | */ 34 | public function down(): void 35 | { 36 | Schema::dropIfExists('contact_messages'); 37 | } 38 | }; 39 | -------------------------------------------------------------------------------- /database/migrations/2023_04_28_140325_create_login_tokens_table.php: -------------------------------------------------------------------------------- 1 | id(); 16 | $table->foreignId('user_id') 17 | ->constrained() 18 | ->cascadeOnUpdate() 19 | ->cascadeOnDelete(); 20 | $table->string('token')->unique(); 21 | $table->timestamp('consumed_at')->nullable(); 22 | $table->timestamp('expires_at'); 23 | $table->timestamps(); 24 | }); 25 | } 26 | 27 | /** 28 | * Reverse the migrations. 29 | */ 30 | public function down(): void 31 | { 32 | Schema::dropIfExists('login_tokens'); 33 | } 34 | }; 35 | -------------------------------------------------------------------------------- /database/seeders/DatabaseSeeder.php: -------------------------------------------------------------------------------- 1 | call(UserTableSeeder::class); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /database/seeders/DemoTableSeeder.php: -------------------------------------------------------------------------------- 1 | create(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /database/seeders/UserTableSeeder.php: -------------------------------------------------------------------------------- 1 | getDefaultUsers() as $user) { 21 | $exists = User::where('name', $user['name'])->first(); 22 | 23 | if(! $exists) { 24 | $savedUser = User::create($user); 25 | } 26 | } 27 | } 28 | 29 | /** 30 | * get default users 31 | */ 32 | public function getDefaultUsers() : array 33 | { 34 | return [ 35 | [ 36 | 'name' => 'acelords', 37 | 'email' => 'info@acelords.com', 38 | 'password' => bcrypt('acelords'), 39 | 'first_name' => 'AceLords', 40 | 'last_name' => 'LTD', 41 | 'status' => User::STATUS_ACTIVE, 42 | 'role' => User::ROLE_SUPERADMIN 43 | ], 44 | [ 45 | 'name' => 'admin', 46 | 'email' => 'admin@gmail.com', 47 | 'password' => bcrypt('admin'), 48 | 'first_name' => 'Admin', 49 | 'last_name' => 'Main', 50 | 'status' => User::STATUS_ACTIVE, 51 | 'role' => User::ROLE_ADMIN 52 | ], 53 | [ 54 | 'name' => 'user', 55 | 'email' => 'user@gmail.com', 56 | 'password' => bcrypt('user'), 57 | 'first_name' => 'User', 58 | 'last_name' => 'Customer', 59 | 'status' => User::STATUS_ACTIVE, 60 | 'role' => User::ROLE_USER 61 | ], 62 | ]; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /lang/en/auth.php: -------------------------------------------------------------------------------- 1 | 'These credentials do not match our records.', 17 | 'password' => 'The provided password is incorrect.', 18 | 'throttle' => 'Too many login attempts. Please try again in :seconds seconds.', 19 | 'failed' => 'These credentials do not match our records.', 20 | 'password' => 'The provided password is incorrect.', 21 | 'throttle' => 'Too many login attempts. Please try again in :seconds seconds.', 22 | 'failed_phone' => 'The phone number is invalid. Ensure it is formatied in international phone number standard (+)[country-code][number]', 23 | 'phone_starts_with' => 'The phone number must be in international phone number formatting standard (+)[country-code][number]', 24 | 'phone_taken' => 'That phone has already been taken!', 25 | 'phone_missing' => 'That phone number has not been registered!', 26 | 'email_name_required' => "You must provide at least the email or the username", 27 | 'otp_sent' => "We have sent an OTP code. Use it to login.", 28 | 'otp_expired' => 'The OTP code has expired!', 29 | 'otp_failed' => 'OTP Verification NOT successful!', 30 | 'logged_out_other_devices' => 'Logout from other devices success', 31 | 32 | 'registration_success' => "Registration Successful! You may proceed to login", 33 | 'registration_error' => "Registration could not be completed", 34 | 'registration_closed' => "Registration closed for new accounts", 35 | 'email_verified' => "Email has been verified", 36 | 'email_already_verified' => "Email is already verified", 37 | 'email_verification_sent' => "Verification link sent to the provided email", 38 | 'use_mobile_app' => "Use our mobile app to proceed", 39 | 'account_not_active' => "Account status not active!", 40 | 'unauthenticated' => "You need to be logged in!", 41 | ]; 42 | -------------------------------------------------------------------------------- /lang/en/pagination.php: -------------------------------------------------------------------------------- 1 | '« Previous', 17 | 'next' => 'Next »', 18 | 19 | ]; 20 | -------------------------------------------------------------------------------- /lang/en/passwords.php: -------------------------------------------------------------------------------- 1 | 'Your password has been reset.', 17 | 'sent' => 'We have emailed your password reset link.', 18 | 'throttled' => 'Please wait before retrying.', 19 | 'token' => 'This password reset token is invalid.', 20 | 'user' => "We can't find a user with that email address.", 21 | 22 | ]; 23 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "dev": "vite", 5 | "build": "vite build", 6 | "production": "npm run build", 7 | "watch": "npm run dev" 8 | }, 9 | "type": "module", 10 | "devDependencies": { 11 | "@sveltejs/vite-plugin-svelte": "^2.0.3", 12 | "@tailwindcss/forms": "^0.5.3", 13 | "@tailwindcss/typography": "^0.5.9", 14 | "@tsconfig/svelte": "^4.0.1", 15 | "@types/node": "^18.15.11", 16 | "@types/ziggy-js": "^1.3.2", 17 | "@typescript-eslint/eslint-plugin": "^5.57.0", 18 | "@typescript-eslint/parser": "^5.57.0", 19 | "autoprefixer": "^10.4.14", 20 | "axios": "^1.3.4", 21 | "laravel-vite-plugin": "^0.7.4", 22 | "postcss": "^8.4.21", 23 | "svelte": "^3.57.0", 24 | "svelte-check": "^3.1.4", 25 | "svelte-preprocess": "^5.0.3", 26 | "tailwindcss": "^3.3.0", 27 | "tslib": "^2.5.0", 28 | "typescript": "^5.0.2", 29 | "vite": "^4.2.1" 30 | }, 31 | "dependencies": { 32 | "@inertiajs/svelte": "^1.0.2", 33 | "dayjs": "^1.11.7", 34 | "numeral": "^2.0.6", 35 | "svelte-loading-spinners": "^0.3.4", 36 | "svelte-modals": "^1.2.1", 37 | "svelte-toasts": "^1.1.2", 38 | "sweetalert2": "^11.7.3" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | ./tests/Unit 10 | 11 | 12 | ./tests/Feature 13 | 14 | 15 | 16 | 17 | ./app 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /postcss.config.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } -------------------------------------------------------------------------------- /public/.htaccess: -------------------------------------------------------------------------------- 1 | 2 | 3 | Options -MultiViews -Indexes 4 | 5 | 6 | RewriteEngine On 7 | 8 | # Handle Authorization Header 9 | RewriteCond %{HTTP:Authorization} . 10 | RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] 11 | 12 | # Redirect Trailing Slashes If Not A Folder... 13 | RewriteCond %{REQUEST_FILENAME} !-d 14 | RewriteCond %{REQUEST_URI} (.+)/$ 15 | RewriteRule ^ %1 [L,R=301] 16 | 17 | # Send Requests To Front Controller... 18 | RewriteCond %{REQUEST_FILENAME} !-d 19 | RewriteCond %{REQUEST_FILENAME} !-f 20 | RewriteRule ^ index.php [L] 21 | 22 | -------------------------------------------------------------------------------- /public/android-chrome-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syntaxlexx/laravelte/e857ac623e3fc0d867b3ca6373d7c8af6219ec4b/public/android-chrome-96x96.png -------------------------------------------------------------------------------- /public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syntaxlexx/laravelte/e857ac623e3fc0d867b3ca6373d7c8af6219ec4b/public/apple-touch-icon.png -------------------------------------------------------------------------------- /public/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | #da532c 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /public/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syntaxlexx/laravelte/e857ac623e3fc0d867b3ca6373d7c8af6219ec4b/public/favicon-16x16.png -------------------------------------------------------------------------------- /public/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syntaxlexx/laravelte/e857ac623e3fc0d867b3ca6373d7c8af6219ec4b/public/favicon-32x32.png -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syntaxlexx/laravelte/e857ac623e3fc0d867b3ca6373d7c8af6219ec4b/public/favicon.ico -------------------------------------------------------------------------------- /public/fonts/boxicons/css/transformations.css: -------------------------------------------------------------------------------- 1 | .bx-rotate-90 2 | { 3 | transform: rotate(90deg); 4 | 5 | -ms-filter: 'progid:DXImageTransform.Microsoft.BasicImage(rotation=1)'; 6 | } 7 | .bx-rotate-180 8 | { 9 | transform: rotate(180deg); 10 | 11 | -ms-filter: 'progid:DXImageTransform.Microsoft.BasicImage(rotation=2)'; 12 | } 13 | .bx-rotate-270 14 | { 15 | transform: rotate(270deg); 16 | 17 | -ms-filter: 'progid:DXImageTransform.Microsoft.BasicImage(rotation=3)'; 18 | } 19 | .bx-flip-horizontal 20 | { 21 | transform: scaleX(-1); 22 | 23 | -ms-filter: 'progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)'; 24 | } 25 | .bx-flip-vertical 26 | { 27 | transform: scaleY(-1); 28 | 29 | -ms-filter: 'progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)'; 30 | } 31 | -------------------------------------------------------------------------------- /public/fonts/boxicons/fonts/boxicons.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syntaxlexx/laravelte/e857ac623e3fc0d867b3ca6373d7c8af6219ec4b/public/fonts/boxicons/fonts/boxicons.eot -------------------------------------------------------------------------------- /public/fonts/boxicons/fonts/boxicons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syntaxlexx/laravelte/e857ac623e3fc0d867b3ca6373d7c8af6219ec4b/public/fonts/boxicons/fonts/boxicons.ttf -------------------------------------------------------------------------------- /public/fonts/boxicons/fonts/boxicons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syntaxlexx/laravelte/e857ac623e3fc0d867b3ca6373d7c8af6219ec4b/public/fonts/boxicons/fonts/boxicons.woff -------------------------------------------------------------------------------- /public/fonts/boxicons/fonts/boxicons.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syntaxlexx/laravelte/e857ac623e3fc0d867b3ca6373d7c8af6219ec4b/public/fonts/boxicons/fonts/boxicons.woff2 -------------------------------------------------------------------------------- /public/img/gumroad-button.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syntaxlexx/laravelte/e857ac623e3fc0d867b3ca6373d7c8af6219ec4b/public/img/gumroad-button.jpg -------------------------------------------------------------------------------- /public/img/laravelte-dashboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syntaxlexx/laravelte/e857ac623e3fc0d867b3ca6373d7c8af6219ec4b/public/img/laravelte-dashboard.png -------------------------------------------------------------------------------- /public/img/laravelte-logo-full.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syntaxlexx/laravelte/e857ac623e3fc0d867b3ca6373d7c8af6219ec4b/public/img/laravelte-logo-full.png -------------------------------------------------------------------------------- /public/img/laravelte-logo-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syntaxlexx/laravelte/e857ac623e3fc0d867b3ca6373d7c8af6219ec4b/public/img/laravelte-logo-small.png -------------------------------------------------------------------------------- /public/img/laravelte-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syntaxlexx/laravelte/e857ac623e3fc0d867b3ca6373d7c8af6219ec4b/public/img/laravelte-logo.png -------------------------------------------------------------------------------- /public/img/laravelte-screenshot-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syntaxlexx/laravelte/e857ac623e3fc0d867b3ca6373d7c8af6219ec4b/public/img/laravelte-screenshot-1.jpg -------------------------------------------------------------------------------- /public/img/laravelte-screenshot-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syntaxlexx/laravelte/e857ac623e3fc0d867b3ca6373d7c8af6219ec4b/public/img/laravelte-screenshot-2.jpg -------------------------------------------------------------------------------- /public/img/laravelte-screenshot-3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syntaxlexx/laravelte/e857ac623e3fc0d867b3ca6373d7c8af6219ec4b/public/img/laravelte-screenshot-3.jpg -------------------------------------------------------------------------------- /public/img/laravelte-screenshot-4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syntaxlexx/laravelte/e857ac623e3fc0d867b3ca6373d7c8af6219ec4b/public/img/laravelte-screenshot-4.jpg -------------------------------------------------------------------------------- /public/img/laravelte-screenshot-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syntaxlexx/laravelte/e857ac623e3fc0d867b3ca6373d7c8af6219ec4b/public/img/laravelte-screenshot-5.png -------------------------------------------------------------------------------- /public/img/laravelte-screenshot-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syntaxlexx/laravelte/e857ac623e3fc0d867b3ca6373d7c8af6219ec4b/public/img/laravelte-screenshot-6.png -------------------------------------------------------------------------------- /public/img/laravelte-screenshot-7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syntaxlexx/laravelte/e857ac623e3fc0d867b3ca6373d7c8af6219ec4b/public/img/laravelte-screenshot-7.png -------------------------------------------------------------------------------- /public/img/no-data.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syntaxlexx/laravelte/e857ac623e3fc0d867b3ca6373d7c8af6219ec4b/public/img/no-data.png -------------------------------------------------------------------------------- /public/index.php: -------------------------------------------------------------------------------- 1 | make(Kernel::class); 50 | 51 | $response = $kernel->handle( 52 | $request = Request::capture() 53 | )->send(); 54 | 55 | $kernel->terminate($request, $response); 56 | -------------------------------------------------------------------------------- /public/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syntaxlexx/laravelte/e857ac623e3fc0d867b3ca6373d7c8af6219ec4b/public/mstile-150x150.png -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: 3 | -------------------------------------------------------------------------------- /public/site.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "name": "", 3 | "short_name": "", 4 | "icons": [ 5 | { 6 | "src": "/android-chrome-96x96.png", 7 | "sizes": "96x96", 8 | "type": "image/png" 9 | } 10 | ], 11 | "theme_color": "#ffffff", 12 | "background_color": "#ffffff", 13 | "display": "standalone" 14 | } 15 | -------------------------------------------------------------------------------- /resources/markdown/policy.md: -------------------------------------------------------------------------------- 1 | # Privacy Policy 2 | 3 | Edit this file to define the privacy policy for your application. 4 | -------------------------------------------------------------------------------- /resources/markdown/terms.md: -------------------------------------------------------------------------------- 1 | # Terms of Service 2 | 3 | Edit this file to define the terms of service for your application. 4 | -------------------------------------------------------------------------------- /resources/ts/Components/Alert.svelte: -------------------------------------------------------------------------------- 1 | 10 | -------------------------------------------------------------------------------- /resources/ts/Components/Circle.svelte: -------------------------------------------------------------------------------- 1 | 18 | 19 | 27 | 28 | 55 | -------------------------------------------------------------------------------- /resources/ts/Components/ComingSoon.svelte: -------------------------------------------------------------------------------- 1 |
2 |
5 | coming soon 6 |
7 | Coming Soon 8 |
9 |
10 | -------------------------------------------------------------------------------- /resources/ts/Components/DisplayErrors.svelte: -------------------------------------------------------------------------------- 1 | 9 | 10 | {#if formatedErrors} 11 |
12 |
13 |
14 | 27 |
28 |
29 | {#if title} 30 |

31 | {title} 32 |

33 | {/if} 34 | {#each formatedErrors as item} 35 |

{item}

36 | {/each} 37 |
38 |
39 |
40 | {/if} 41 | -------------------------------------------------------------------------------- /resources/ts/Components/Divider.svelte: -------------------------------------------------------------------------------- 1 |
2 | -------------------------------------------------------------------------------- /resources/ts/Components/Empty.svelte: -------------------------------------------------------------------------------- 1 |
2 |
3 |

4 | No data was found 5 |

6 | no-data 7 |
8 |
9 | -------------------------------------------------------------------------------- /resources/ts/Components/FancyButton.svelte: -------------------------------------------------------------------------------- 1 | 22 | 23 | 33 | 34 | 70 | -------------------------------------------------------------------------------- /resources/ts/Components/Icon.svelte: -------------------------------------------------------------------------------- 1 | 53 | 54 | 55 | 56 | 70 | -------------------------------------------------------------------------------- /resources/ts/Components/Loading.svelte: -------------------------------------------------------------------------------- 1 | 12 | 13 | {#if type == 'moon'} 14 | 15 | {:else if type == 'wave'} 16 | 17 | {/if} 18 | -------------------------------------------------------------------------------- /resources/ts/Components/Modal.svelte: -------------------------------------------------------------------------------- 1 | 20 | 21 | {#if isOpen} 22 | 38 | {/if} 39 | -------------------------------------------------------------------------------- /resources/ts/Components/ModalClose.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 | 20 | -------------------------------------------------------------------------------- /resources/ts/Components/PageHeader.svelte: -------------------------------------------------------------------------------- 1 | 17 | 18 | 29 | 30 | 45 | -------------------------------------------------------------------------------- /resources/ts/Components/Seo.svelte: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | {title} 8 | 9 | 10 | -------------------------------------------------------------------------------- /resources/ts/Components/SubscribeForm.svelte: -------------------------------------------------------------------------------- 1 | 10 | 11 | {#if ready} 12 | 13 | {/if} 14 | -------------------------------------------------------------------------------- /resources/ts/Components/Sweet.svelte: -------------------------------------------------------------------------------- 1 |
2 |

3 | Typescript + Actions = Sanity 4 |

5 |

It's the duo we've all been waiting for

6 | laravelte-screenshot-6 7 |
8 | -------------------------------------------------------------------------------- /resources/ts/Components/Textarea.svelte: -------------------------------------------------------------------------------- 1 | 19 | 20 |
21 | {#if label} 22 | 23 | {/if} 24 | 25 |