├── .gitignore ├── frontend ├── store │ ├── index.js │ ├── README.md │ └── courses.js ├── pages │ ├── auth │ │ ├── forgot.vue │ │ ├── index.vue │ │ ├── verify │ │ │ └── _verify.vue │ │ └── login.vue │ ├── README.md │ ├── index.vue │ ├── courses │ │ └── _slug.vue │ ├── lessons │ │ └── _slug.vue │ └── admin │ │ └── courses │ │ └── new.vue ├── assets │ ├── scss │ │ ├── abstracts │ │ │ ├── _mixins.scss │ │ │ ├── __abstract-dir.scss │ │ │ ├── _fonts.scss │ │ │ └── _variables.scss │ │ ├── base │ │ │ ├── _colours.scss │ │ │ ├── _typography.scss │ │ │ ├── __base_dir.scss │ │ │ └── _reset.scss │ │ ├── components │ │ │ ├── _input.scss │ │ │ ├── _modal.scss │ │ │ ├── _button.scss │ │ │ └── __components-dir.scss │ │ ├── layouts │ │ │ ├── _footer.scss │ │ │ ├── _sidebar.scss │ │ │ ├── __layouts-dir.scss │ │ │ └── _navbar.scss │ │ ├── vendor │ │ │ └── __vendor-dir.scss │ │ └── app.scss │ └── README.md ├── plugins │ ├── antd-ui.js │ └── README.md ├── layouts │ ├── admin.vue │ ├── Navbar │ │ ├── WINavItem.vue │ │ └── WINavBar.vue │ ├── README.md │ └── default.vue ├── components │ ├── README.md │ ├── Card.vue │ ├── Container.vue │ └── Logo.vue ├── .editorconfig ├── middleware │ ├── admin.js │ └── README.md ├── README.md ├── static │ └── README.md ├── package.json ├── .gitignore └── nuxt.config.js ├── backend ├── public │ ├── favicon.ico │ ├── robots.txt │ ├── .htaccess │ └── index.php ├── storage │ ├── logs │ │ └── .gitignore │ ├── app │ │ ├── public │ │ │ └── .gitignore │ │ └── .gitignore │ └── framework │ │ ├── sessions │ │ └── .gitignore │ │ ├── testing │ │ └── .gitignore │ │ ├── views │ │ └── .gitignore │ │ ├── cache │ │ ├── data │ │ │ └── .gitignore │ │ └── .gitignore │ │ └── .gitignore ├── bootstrap │ ├── cache │ │ └── .gitignore │ └── app.php ├── database │ ├── .gitignore │ ├── seeds │ │ └── DatabaseSeeder.php │ ├── migrations │ │ ├── 2020_05_09_121317_add_slug_to_lessons.php │ │ ├── 2020_05_17_222704_add_thumbnail_to_courses.php │ │ ├── 2020_05_17_222801_add_thumbnail_to_lessons.php │ │ ├── 2020_05_11_173422_add_privacy_to_courses.php │ │ ├── 2014_10_12_100000_create_password_resets_table.php │ │ ├── 2020_05_01_121713_create_courses_table.php │ │ ├── 2019_08_19_000000_create_failed_jobs_table.php │ │ ├── 2020_12_31_193754_create_sessions_table.php │ │ ├── 2019_12_14_000001_create_personal_access_tokens_table.php │ │ ├── 2014_10_12_000000_create_users_table.php │ │ ├── 2014_10_12_200000_add_two_factor_columns_to_users_table.php │ │ └── 2020_05_09_120622_create_lessons_table.php │ └── factories │ │ └── UserFactory.php ├── resources │ ├── js │ │ ├── app.js │ │ ├── components │ │ │ └── ExampleComponent.vue │ │ └── bootstrap.js │ ├── css │ │ └── app.css │ ├── views │ │ ├── api │ │ │ └── index.blade.php │ │ ├── emails │ │ │ └── verify.blade.php │ │ ├── dashboard.blade.php │ │ ├── home.blade.php │ │ ├── layouts │ │ │ ├── guest.blade.php │ │ │ └── app.blade.php │ │ ├── auth │ │ │ ├── verify.blade.php │ │ │ ├── forgot-password.blade.php │ │ │ ├── verify-email.blade.php │ │ │ ├── reset-password.blade.php │ │ │ ├── register.blade.php │ │ │ ├── login.blade.php │ │ │ ├── passwords │ │ │ │ ├── email.blade.php │ │ │ │ ├── confirm.blade.php │ │ │ │ └── reset.blade.php │ │ │ └── two-factor-challenge.blade.php │ │ ├── profile │ │ │ ├── show.blade.php │ │ │ ├── update-password-form.blade.php │ │ │ ├── delete-user-form.blade.php │ │ │ ├── update-profile-information-form.blade.php │ │ │ ├── two-factor-authentication-form.blade.php │ │ │ └── logout-other-browser-sessions-form.blade.php │ │ └── welcome.blade.php │ └── lang │ │ └── en │ │ ├── pagination.php │ │ ├── auth.php │ │ └── passwords.php ├── .gitattributes ├── webpack.config.js ├── .gitignore ├── tests │ ├── TestCase.php │ ├── Unit │ │ └── ExampleTest.php │ ├── Feature │ │ └── ExampleTest.php │ └── CreatesApplication.php ├── .styleci.yml ├── routes │ ├── web.php │ ├── channels.php │ ├── console.php │ └── api.php ├── .editorconfig ├── app │ ├── Models │ │ ├── Lesson.php │ │ ├── Course.php │ │ └── User.php │ ├── Http │ │ ├── Middleware │ │ │ ├── EncryptCookies.php │ │ │ ├── VerifyCsrfToken.php │ │ │ ├── CheckForMaintenanceMode.php │ │ │ ├── TrimStrings.php │ │ │ ├── TrustProxies.php │ │ │ ├── Authenticate.php │ │ │ ├── Admin.php │ │ │ └── RedirectIfAuthenticated.php │ │ ├── Controllers │ │ │ ├── Controller.php │ │ │ ├── Courses │ │ │ │ ├── LessonController.php │ │ │ │ └── CourseController.php │ │ │ ├── HomeController.php │ │ │ └── Auth │ │ │ │ ├── ForgotPasswordController.php │ │ │ │ ├── ResetPasswordController.php │ │ │ │ ├── LoginController.php │ │ │ │ ├── ConfirmPasswordController.php │ │ │ │ ├── VerificationController.php │ │ │ │ ├── RegisterUserController.php │ │ │ │ └── RegisterController.php │ │ ├── Resources │ │ │ ├── CourseResource.php │ │ │ └── LessonResource.php │ │ └── Kernel.php │ ├── View │ │ └── Components │ │ │ ├── AppLayout.php │ │ │ └── GuestLayout.php │ ├── Actions │ │ ├── Fortify │ │ │ ├── PasswordValidationRules.php │ │ │ ├── ResetUserPassword.php │ │ │ ├── CreateNewUser.php │ │ │ ├── UpdateUserPassword.php │ │ │ └── UpdateUserProfileInformation.php │ │ └── Jetstream │ │ │ └── DeleteUser.php │ ├── Providers │ │ ├── BroadcastServiceProvider.php │ │ ├── AppServiceProvider.php │ │ ├── AuthServiceProvider.php │ │ ├── EventServiceProvider.php │ │ ├── FortifyServiceProvider.php │ │ ├── JetstreamServiceProvider.php │ │ └── RouteServiceProvider.php │ ├── Mail │ │ └── VerifyEmail.php │ ├── Console │ │ └── Kernel.php │ └── Exceptions │ │ └── Handler.php ├── tailwind.config.js ├── server.php ├── webpack.mix.js ├── .env.example ├── config │ ├── cors.php │ ├── services.php │ ├── view.php │ ├── jetstream.php │ ├── hashing.php │ ├── broadcasting.php │ ├── sanctum.php │ ├── filesystems.php │ ├── queue.php │ ├── logging.php │ ├── cache.php │ ├── mail.php │ └── auth.php ├── phpunit.xml ├── package.json ├── artisan ├── composer.json └── README.md ├── .idea ├── codeStyles │ └── codeStyleConfig.xml ├── vcs.xml └── modules.xml ├── LICENSE.md └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | -------------------------------------------------------------------------------- /frontend/store/index.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/public/favicon.ico: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/pages/auth/forgot.vue: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/assets/scss/abstracts/_mixins.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/assets/scss/base/_colours.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/assets/scss/base/_typography.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/assets/scss/components/_input.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/assets/scss/components/_modal.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/assets/scss/layouts/_footer.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/assets/scss/layouts/_sidebar.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/assets/scss/components/_button.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/assets/scss/vendor/__vendor-dir.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/storage/logs/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /backend/bootstrap/cache/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /backend/public/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: 3 | -------------------------------------------------------------------------------- /backend/database/.gitignore: -------------------------------------------------------------------------------- 1 | *.sqlite 2 | *.sqlite-journal 3 | -------------------------------------------------------------------------------- /backend/storage/app/public/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /backend/storage/app/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !public/ 3 | !.gitignore 4 | -------------------------------------------------------------------------------- /backend/storage/framework/sessions/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /backend/storage/framework/testing/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /backend/storage/framework/views/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /backend/storage/framework/cache/data/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /frontend/assets/scss/layouts/__layouts-dir.scss: -------------------------------------------------------------------------------- 1 | @import "navbar"; 2 | -------------------------------------------------------------------------------- /backend/storage/framework/cache/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !data/ 3 | !.gitignore 4 | -------------------------------------------------------------------------------- /backend/resources/js/app.js: -------------------------------------------------------------------------------- 1 | require('./bootstrap'); 2 | 3 | require('alpinejs'); 4 | -------------------------------------------------------------------------------- /frontend/assets/scss/base/__base_dir.scss: -------------------------------------------------------------------------------- 1 | @import "reset"; 2 | @import "colours"; 3 | @import "typography"; 4 | -------------------------------------------------------------------------------- /frontend/assets/scss/abstracts/__abstract-dir.scss: -------------------------------------------------------------------------------- 1 | @import "variables"; 2 | @import "mixins"; 3 | @import "fonts"; 4 | -------------------------------------------------------------------------------- /frontend/assets/scss/components/__components-dir.scss: -------------------------------------------------------------------------------- 1 | @import "button"; 2 | @import "input"; 3 | @import "modal"; 4 | -------------------------------------------------------------------------------- /frontend/plugins/antd-ui.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Antd from 'ant-design-vue/lib' 3 | 4 | Vue.use(Antd) 5 | -------------------------------------------------------------------------------- /frontend/assets/scss/abstracts/_fonts.scss: -------------------------------------------------------------------------------- 1 | @import url("https://fonts.googleapis.com/css?family=Quicksand:300,500"); 2 | 3 | -------------------------------------------------------------------------------- /backend/resources/css/app.css: -------------------------------------------------------------------------------- 1 | @import 'tailwindcss/base'; 2 | @import 'tailwindcss/components'; 3 | @import 'tailwindcss/utilities'; 4 | -------------------------------------------------------------------------------- /backend/.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | *.css linguist-vendored 3 | *.scss linguist-vendored 4 | *.js linguist-vendored 5 | CHANGELOG.md export-ignore 6 | -------------------------------------------------------------------------------- /frontend/pages/auth/index.vue: -------------------------------------------------------------------------------- 1 | 4 | 9 | -------------------------------------------------------------------------------- /backend/storage/framework/.gitignore: -------------------------------------------------------------------------------- 1 | config.php 2 | routes.php 3 | schedule-* 4 | compiled.php 5 | services.json 6 | events.scanned.php 7 | routes.scanned.php 8 | down 9 | -------------------------------------------------------------------------------- /frontend/layouts/admin.vue: -------------------------------------------------------------------------------- 1 | 6 | 11 | -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /backend/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | module.exports = { 4 | resolve: { 5 | alias: { 6 | '@': path.resolve('resources/js'), 7 | }, 8 | }, 9 | }; 10 | -------------------------------------------------------------------------------- /frontend/assets/scss/app.scss: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | 3 | @import "abstracts/_abstract-dir"; 4 | @import "base/_base_dir"; 5 | @import "components/_components-dir"; 6 | @import "layouts/_layouts-dir"; 7 | @import "vendor/_vendor-dir"; 8 | -------------------------------------------------------------------------------- /backend/.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /public/hot 3 | /public/storage 4 | /storage/*.key 5 | /vendor 6 | .env 7 | .env.backup 8 | .phpunit.result.cache 9 | Homestead.json 10 | Homestead.yaml 11 | npm-debug.log 12 | yarn-error.log 13 | -------------------------------------------------------------------------------- /backend/tests/TestCase.php: -------------------------------------------------------------------------------- 1 | get('/dashboard', function () { 8 | return view('dashboard'); 9 | })->name('dashboard'); 10 | -------------------------------------------------------------------------------- /frontend/layouts/Navbar/WINavItem.vue: -------------------------------------------------------------------------------- 1 | 6 | 14 | -------------------------------------------------------------------------------- /frontend/.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /frontend/middleware/admin.js: -------------------------------------------------------------------------------- 1 | export default function ({store, redirect}) { 2 | if (store.state.auth.loggedIn) { 3 | if (store.state.auth.user.is_admin) { 4 | return; 5 | } else { 6 | return redirect('/'); 7 | } 8 | } else { 9 | return redirect('/'); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /backend/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | insert_final_newline = true 7 | indent_style = space 8 | indent_size = 4 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | 14 | [*.{yml,yaml}] 15 | indent_size = 2 16 | -------------------------------------------------------------------------------- /frontend/layouts/README.md: -------------------------------------------------------------------------------- 1 | # LAYOUTS 2 | 3 | **This directory is not required, you can delete it if you don't want to use it.** 4 | 5 | This directory contains your Application Layouts. 6 | 7 | More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/views#layouts). 8 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /frontend/pages/README.md: -------------------------------------------------------------------------------- 1 | # PAGES 2 | 3 | This directory contains your Application Views and Routes. 4 | The framework reads all the `*.vue` files inside this directory and creates the router of your application. 5 | 6 | More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/routing). 7 | -------------------------------------------------------------------------------- /backend/app/Models/Lesson.php: -------------------------------------------------------------------------------- 1 | belongsTo(Course::class); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /frontend/assets/README.md: -------------------------------------------------------------------------------- 1 | # ASSETS 2 | 3 | **This directory is not required, you can delete it if you don't want to use it.** 4 | 5 | This directory contains your un-compiled assets such as LESS, SASS, or JavaScript. 6 | 7 | More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/assets#webpacked). 8 | -------------------------------------------------------------------------------- /backend/database/seeds/DatabaseSeeder.php: -------------------------------------------------------------------------------- 1 | call(UserSeeder::class); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /frontend/plugins/README.md: -------------------------------------------------------------------------------- 1 | # PLUGINS 2 | 3 | **This directory is not required, you can delete it if you don't want to use it.** 4 | 5 | This directory contains Javascript plugins that you want to run before mounting the root Vue.js application. 6 | 7 | More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/plugins). 8 | -------------------------------------------------------------------------------- /backend/tests/Unit/ExampleTest.php: -------------------------------------------------------------------------------- 1 | assertTrue(true); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /backend/app/Models/Course.php: -------------------------------------------------------------------------------- 1 | hasMany(Lesson::class); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /backend/app/Http/Middleware/EncryptCookies.php: -------------------------------------------------------------------------------- 1 | 2 | 3 |

4 | {{ __('API Tokens') }} 5 |

6 |
7 | 8 |
9 |
10 | @livewire('api.api-token-manager') 11 |
12 |
13 | 14 | -------------------------------------------------------------------------------- /backend/resources/views/emails/verify.blade.php: -------------------------------------------------------------------------------- 1 | @component('mail::message') 2 | Hi, {{ $details['name'] }} 3 | 4 | Please verify your E-mail address by clicking the link below. 5 | 6 | @component('mail::button', ["url" => "http://localhost:3000/auth/verify/" . $details['email_verification_code'] . '-' . $details['id']]) 7 | Verify E-mail 8 | @endcomponent 9 | 10 | Thanks,
11 | {{ config('app.name') }} 12 | @endcomponent 13 | -------------------------------------------------------------------------------- /frontend/middleware/README.md: -------------------------------------------------------------------------------- 1 | # MIDDLEWARE 2 | 3 | **This directory is not required, you can delete it if you don't want to use it.** 4 | 5 | This directory contains your application middleware. 6 | Middleware let you define custom functions that can be run before rendering either a page or a group of pages. 7 | 8 | More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/routing#middleware). 9 | -------------------------------------------------------------------------------- /frontend/components/Card.vue: -------------------------------------------------------------------------------- 1 | 9 | 19 | -------------------------------------------------------------------------------- /backend/app/Http/Controllers/Controller.php: -------------------------------------------------------------------------------- 1 | get('/'); 18 | 19 | $response->assertStatus(200); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /frontend/README.md: -------------------------------------------------------------------------------- 1 | # frontend 2 | 3 | > My divine Nuxt.js project 4 | 5 | ## Build Setup 6 | 7 | ```bash 8 | # install dependencies 9 | $ npm install 10 | 11 | # serve with hot reload at localhost:3000 12 | $ npm run dev 13 | 14 | # build for production and launch server 15 | $ npm run build 16 | $ npm run start 17 | 18 | # generate static project 19 | $ npm run generate 20 | ``` 21 | 22 | For detailed explanation on how things work, check out [Nuxt.js docs](https://nuxtjs.org). 23 | -------------------------------------------------------------------------------- /frontend/static/README.md: -------------------------------------------------------------------------------- 1 | # STATIC 2 | 3 | **This directory is not required, you can delete it if you don't want to use it.** 4 | 5 | This directory contains your static files. 6 | Each file inside this directory is mapped to `/`. 7 | Thus you'd want to delete this README.md before deploying to production. 8 | 9 | Example: `/static/robots.txt` is mapped as `/robots.txt`. 10 | 11 | More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/assets#static). 12 | -------------------------------------------------------------------------------- /backend/tests/CreatesApplication.php: -------------------------------------------------------------------------------- 1 | make(Kernel::class)->bootstrap(); 19 | 20 | return $app; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /backend/app/Actions/Jetstream/DeleteUser.php: -------------------------------------------------------------------------------- 1 | deleteProfilePhoto(); 18 | $user->tokens->each->delete(); 19 | $user->delete(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /backend/app/Providers/BroadcastServiceProvider.php: -------------------------------------------------------------------------------- 1 | 2 | 3 |

4 | {{ __('Dashboard') }} 5 |

6 |
7 | 8 |
9 |
10 |
11 | 12 |
13 |
14 |
15 | 16 | -------------------------------------------------------------------------------- /backend/app/Http/Controllers/Courses/LessonController.php: -------------------------------------------------------------------------------- 1 | first()); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /backend/app/Http/Middleware/TrustProxies.php: -------------------------------------------------------------------------------- 1 | expectsJson()) { 18 | return route('login'); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /frontend/components/Container.vue: -------------------------------------------------------------------------------- 1 | 6 | 30 | -------------------------------------------------------------------------------- /frontend/assets/scss/abstracts/_variables.scss: -------------------------------------------------------------------------------- 1 | //Colours 2 | $primary: #4299e1; 3 | $success: #2E8A5C; 4 | $dark: #242240; 5 | $light: #fefcfc; 6 | $danger: #dc2f33; 7 | $warning: #dc6c2f; 8 | 9 | //Font Sizes & Family 10 | $font-family: 'Quicksand', sans-serif; 11 | 12 | $size-1: 3em; 13 | $size-2: 2.50em; 14 | $size-3: 2.25em; 15 | $size-4: 1.75em; 16 | $size-5: 1.50em; 17 | $size-6: 1.125em; 18 | $size-7: 1em; 19 | 20 | //Font Weight 21 | $weight-light: 300; 22 | $weight-normal: 400; 23 | $weight-medium: 500; 24 | $weight-semibold: 600; 25 | $weight-bold: 700; 26 | 27 | //Line Height 28 | $body-line-height: 1.50em; 29 | -------------------------------------------------------------------------------- /backend/app/Http/Controllers/HomeController.php: -------------------------------------------------------------------------------- 1 | middleware('auth'); 17 | } 18 | 19 | /** 20 | * Show the application dashboard. 21 | * 22 | * @return \Illuminate\Contracts\Support\Renderable 23 | */ 24 | public function index() 25 | { 26 | return view('home'); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /backend/app/Providers/AppServiceProvider.php: -------------------------------------------------------------------------------- 1 | '« Previous', 17 | 'next' => 'Next »', 18 | 19 | ]; 20 | -------------------------------------------------------------------------------- /backend/routes/channels.php: -------------------------------------------------------------------------------- 1 | id === (int) $id; 18 | }); 19 | -------------------------------------------------------------------------------- /backend/tailwind.config.js: -------------------------------------------------------------------------------- 1 | const defaultTheme = require('tailwindcss/defaultTheme'); 2 | 3 | module.exports = { 4 | purge: [ 5 | './vendor/laravel/jetstream/**/*.blade.php', 6 | './storage/framework/views/*.php', 7 | './resources/views/**/*.blade.php', 8 | ], 9 | 10 | theme: { 11 | extend: { 12 | fontFamily: { 13 | sans: ['Nunito', ...defaultTheme.fontFamily.sans], 14 | }, 15 | }, 16 | }, 17 | 18 | variants: { 19 | opacity: ['responsive', 'hover', 'focus', 'disabled'], 20 | }, 21 | 22 | plugins: [require('@tailwindcss/ui')], 23 | }; 24 | -------------------------------------------------------------------------------- /backend/app/Http/Middleware/Admin.php: -------------------------------------------------------------------------------- 1 | user()->is_admin) { 19 | return $next($request); 20 | } else { 21 | return response()->json(['errors' => [ 22 | 'root' => 'Page doesn\'t exist' 23 | ]]); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /backend/server.php: -------------------------------------------------------------------------------- 1 | 8 | */ 9 | 10 | $uri = urldecode( 11 | parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH) 12 | ); 13 | 14 | // This file allows us to emulate Apache's "mod_rewrite" functionality from the 15 | // built-in PHP web server. This provides a convenient way to test a Laravel 16 | // application without having installed a "real" web server software here. 17 | if ($uri !== '/' && file_exists(__DIR__.'/public'.$uri)) { 18 | return false; 19 | } 20 | 21 | require_once __DIR__.'/public/index.php'; 22 | -------------------------------------------------------------------------------- /frontend/store/courses.js: -------------------------------------------------------------------------------- 1 | export const state = () => ({ 2 | courses: [], 3 | course: [] 4 | }) 5 | 6 | export const mutations = { 7 | SET_COURSES(state, value) { 8 | state.courses = value 9 | }, 10 | SET_COURSE(state, value) { 11 | state.course = value 12 | } 13 | } 14 | 15 | export const actions = { 16 | async get({commit}) { 17 | await this.$axios.$get('/api/course/all').then(function (resp) { 18 | commit('SET_COURSES', resp.data.courses) 19 | }) 20 | }, 21 | async getCourse({commit}, slug) { 22 | await this.$axios.$get('/api/courses/' + slug).then(function (resp) { 23 | commit('SET_COURSE', resp.data) 24 | }) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /backend/routes/console.php: -------------------------------------------------------------------------------- 1 | comment(Inspiring::quote()); 19 | })->describe('Display an inspiring quote'); 20 | -------------------------------------------------------------------------------- /backend/resources/js/components/ExampleComponent.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 24 | -------------------------------------------------------------------------------- /backend/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 | -------------------------------------------------------------------------------- /backend/resources/lang/en/auth.php: -------------------------------------------------------------------------------- 1 | 'These credentials do not match our records.', 17 | 'throttle' => 'Too many login attempts. Please try again in :seconds seconds.', 18 | 19 | ]; 20 | -------------------------------------------------------------------------------- /backend/app/Http/Middleware/RedirectIfAuthenticated.php: -------------------------------------------------------------------------------- 1 | check()) { 22 | return redirect(RouteServiceProvider::HOME); 23 | } 24 | 25 | return $next($request); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /backend/app/Providers/AuthServiceProvider.php: -------------------------------------------------------------------------------- 1 | 'App\Policies\ModelPolicy', 17 | ]; 18 | 19 | /** 20 | * Register any authentication / authorization services. 21 | * 22 | * @return void 23 | */ 24 | public function boot() 25 | { 26 | $this->registerPolicies(); 27 | 28 | // 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /backend/resources/views/home.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.app') 2 | 3 | @section('content') 4 |
5 |
6 |
7 |
8 |
Dashboard
9 | 10 |
11 | @if (session('status')) 12 | 15 | @endif 16 | 17 | You are logged in! 18 |
19 |
20 |
21 |
22 |
23 | @endsection 24 | -------------------------------------------------------------------------------- /backend/webpack.mix.js: -------------------------------------------------------------------------------- 1 | const mix = require('laravel-mix'); 2 | 3 | /* 4 | |-------------------------------------------------------------------------- 5 | | Mix Asset Management 6 | |-------------------------------------------------------------------------- 7 | | 8 | | Mix provides a clean, fluent API for defining some Webpack build steps 9 | | for your Laravel applications. By default, we are compiling the CSS 10 | | file for the application as well as bundling up all the JS files. 11 | | 12 | */ 13 | 14 | mix.js('resources/js/app.js', 'public/js') 15 | .postCss('resources/css/app.css', 'public/css', [ 16 | require('postcss-import'), 17 | require('tailwindcss'), 18 | ]) 19 | .webpackConfig(require('./webpack.config')); 20 | -------------------------------------------------------------------------------- /frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "frontend", 3 | "version": "1.0.0", 4 | "description": "My divine Nuxt.js project", 5 | "author": "Matilde Enevoldsen", 6 | "private": true, 7 | "scripts": { 8 | "dev": "nuxt", 9 | "build": "nuxt build", 10 | "start": "nuxt start", 11 | "generate": "nuxt generate" 12 | }, 13 | "dependencies": { 14 | "@nuxtjs/auth": "^4.9.1", 15 | "@nuxtjs/axios": "^5.12.4", 16 | "@nuxtjs/dotenv": "^1.4.1", 17 | "@nuxtjs/pwa": "^3.3.3", 18 | "@nuxtjs/style-resources": "^1.0.0", 19 | "ant-design-vue": "^1.7.2", 20 | "node-sass": "^5.0.0", 21 | "nuxt": "^2.14.12", 22 | "sass-loader": "^10.1.0", 23 | "vue-core-video-player": "^0.2.0" 24 | }, 25 | "devDependencies": {} 26 | } 27 | -------------------------------------------------------------------------------- /frontend/pages/auth/verify/_verify.vue: -------------------------------------------------------------------------------- 1 | 4 | 29 | -------------------------------------------------------------------------------- /backend/app/Http/Resources/CourseResource.php: -------------------------------------------------------------------------------- 1 | $this->title, 19 | 'description' => $this->description, 20 | 'slug' => $this->slug, 21 | 'created_at' => $this->created_at->diffForHumans(), 22 | 'updated_at' => $this->updated_at->diffForHumans(), 23 | 'lessons' => $this->lessons->all(), 24 | ]; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /backend/app/Http/Controllers/Auth/ForgotPasswordController.php: -------------------------------------------------------------------------------- 1 | string('slug')->nullable(); 18 | }); 19 | } 20 | 21 | /** 22 | * Reverse the migrations. 23 | * 24 | * @return void 25 | */ 26 | public function down() 27 | { 28 | Schema::table('lessons', function (Blueprint $table) { 29 | // 30 | }); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /backend/database/migrations/2020_05_17_222704_add_thumbnail_to_courses.php: -------------------------------------------------------------------------------- 1 | string('thumbnail')->nullable(); 18 | }); 19 | } 20 | 21 | /** 22 | * Reverse the migrations. 23 | * 24 | * @return void 25 | */ 26 | public function down() 27 | { 28 | Schema::table('courses', function (Blueprint $table) { 29 | // 30 | }); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /backend/database/migrations/2020_05_17_222801_add_thumbnail_to_lessons.php: -------------------------------------------------------------------------------- 1 | string('thumbnail')->nullable(); 18 | }); 19 | } 20 | 21 | /** 22 | * Reverse the migrations. 23 | * 24 | * @return void 25 | */ 26 | public function down() 27 | { 28 | Schema::table('lessons', function (Blueprint $table) { 29 | // 30 | }); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /backend/database/migrations/2020_05_11_173422_add_privacy_to_courses.php: -------------------------------------------------------------------------------- 1 | boolean('is_private')->default(false)->nullable(); 18 | }); 19 | } 20 | 21 | /** 22 | * Reverse the migrations. 23 | * 24 | * @return void 25 | */ 26 | public function down() 27 | { 28 | Schema::table('courses', function (Blueprint $table) { 29 | // 30 | }); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /backend/app/Actions/Fortify/ResetUserPassword.php: -------------------------------------------------------------------------------- 1 | $this->passwordRules(), 24 | ])->validate(); 25 | 26 | $user->forceFill([ 27 | 'password' => Hash::make($input['password']), 28 | ])->save(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /backend/resources/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 | -------------------------------------------------------------------------------- /backend/database/migrations/2014_10_12_100000_create_password_resets_table.php: -------------------------------------------------------------------------------- 1 | string('email')->index(); 18 | $table->string('token'); 19 | $table->timestamp('created_at')->nullable(); 20 | }); 21 | } 22 | 23 | /** 24 | * Reverse the migrations. 25 | * 26 | * @return void 27 | */ 28 | public function down() 29 | { 30 | Schema::dropIfExists('password_resets'); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /frontend/layouts/Navbar/WINavBar.vue: -------------------------------------------------------------------------------- 1 | 22 | 37 | -------------------------------------------------------------------------------- /backend/app/Providers/EventServiceProvider.php: -------------------------------------------------------------------------------- 1 | [ 19 | SendEmailVerificationNotification::class, 20 | ], 21 | ]; 22 | 23 | /** 24 | * Register any events for your application. 25 | * 26 | * @return void 27 | */ 28 | public function boot() 29 | { 30 | parent::boot(); 31 | 32 | // 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /backend/database/migrations/2020_05_01_121713_create_courses_table.php: -------------------------------------------------------------------------------- 1 | id(); 18 | $table->string('title'); 19 | $table->string('description'); 20 | $table->string('slug')->unique(); 21 | $table->timestamps(); 22 | }); 23 | } 24 | 25 | /** 26 | * Reverse the migrations. 27 | * 28 | * @return void 29 | */ 30 | public function down() 31 | { 32 | Schema::dropIfExists('courses'); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /backend/app/Http/Resources/LessonResource.php: -------------------------------------------------------------------------------- 1 | $this->title, 19 | 'description' => $this->description, 20 | 'slug' => $this->slug, 21 | 'file' => $this->file, 22 | 'file_ext' => $this->file_ext, 23 | 'order' => $this->order, 24 | 'course_id' => $this->course_id, 25 | 'created_at' => $this->created_at->diffForHumans(), 26 | 'updated_at' => $this->updated_at->diffForHumans(), 27 | ]; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /frontend/pages/index.vue: -------------------------------------------------------------------------------- 1 | 14 | 32 | -------------------------------------------------------------------------------- /backend/resources/views/layouts/guest.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | {{ config('app.name', 'Laravel') }} 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 | {{ $slot }} 22 |
23 | 24 | 25 | -------------------------------------------------------------------------------- /backend/app/Mail/VerifyEmail.php: -------------------------------------------------------------------------------- 1 | details = $details; 25 | } 26 | 27 | /** 28 | * Build the message. 29 | * 30 | * @return $this 31 | */ 32 | public function build() 33 | { 34 | return $this->subject('Please verify your E-mail') 35 | ->from('info@wimm.media') 36 | ->to($this->details->email) 37 | ->markdown('emails.verify'); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /backend/database/migrations/2019_08_19_000000_create_failed_jobs_table.php: -------------------------------------------------------------------------------- 1 | id(); 18 | $table->text('connection'); 19 | $table->text('queue'); 20 | $table->longText('payload'); 21 | $table->longText('exception'); 22 | $table->timestamp('failed_at')->useCurrent(); 23 | }); 24 | } 25 | 26 | /** 27 | * Reverse the migrations. 28 | * 29 | * @return void 30 | */ 31 | public function down() 32 | { 33 | Schema::dropIfExists('failed_jobs'); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /backend/app/Http/Controllers/Auth/ResetPasswordController.php: -------------------------------------------------------------------------------- 1 | command('inspire')->hourly(); 28 | } 29 | 30 | /** 31 | * Register the commands for the application. 32 | * 33 | * @return void 34 | */ 35 | protected function commands() 36 | { 37 | $this->load(__DIR__.'/Commands'); 38 | 39 | require base_path('routes/console.php'); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /backend/database/factories/UserFactory.php: -------------------------------------------------------------------------------- 1 | define(User::class, function (Faker $faker) { 21 | return [ 22 | 'name' => $faker->name, 23 | 'email' => $faker->unique()->safeEmail, 24 | 'email_verified_at' => now(), 25 | 'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password 26 | 'remember_token' => Str::random(10), 27 | ]; 28 | }); 29 | -------------------------------------------------------------------------------- /backend/database/migrations/2020_12_31_193754_create_sessions_table.php: -------------------------------------------------------------------------------- 1 | string('id')->primary(); 18 | $table->foreignId('user_id')->nullable()->index(); 19 | $table->string('ip_address', 45)->nullable(); 20 | $table->text('user_agent')->nullable(); 21 | $table->text('payload'); 22 | $table->integer('last_activity')->index(); 23 | }); 24 | } 25 | 26 | /** 27 | * Reverse the migrations. 28 | * 29 | * @return void 30 | */ 31 | public function down() 32 | { 33 | Schema::dropIfExists('sessions'); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /backend/app/Actions/Fortify/CreateNewUser.php: -------------------------------------------------------------------------------- 1 | ['required', 'string', 'max:255'], 24 | 'email' => ['required', 'string', 'email', 'max:255', 'unique:users'], 25 | 'password' => $this->passwordRules(), 26 | ])->validate(); 27 | 28 | return User::create([ 29 | 'name' => $input['name'], 30 | 'email' => $input['email'], 31 | 'password' => Hash::make($input['password']), 32 | ]); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /backend/.env.example: -------------------------------------------------------------------------------- 1 | APP_NAME=Laravel 2 | APP_ENV=local 3 | APP_KEY=base64:Ewt/0xqiWydWphd7iUQOaRr4ROJd73wuqYXDTgKEpHg= 4 | APP_DEBUG=true 5 | APP_URL=http://localhost 6 | 7 | LOG_CHANNEL=stack 8 | 9 | DB_CONNECTION=mysql 10 | DB_HOST=127.0.0.1 11 | DB_PORT=3306 12 | DB_DATABASE=laravel 13 | DB_USERNAME=root 14 | DB_PASSWORD= 15 | 16 | BROADCAST_DRIVER=log 17 | CACHE_DRIVER=file 18 | QUEUE_CONNECTION=sync 19 | SESSION_DRIVER=database 20 | SESSION_LIFETIME=120 21 | SESSION_DOMAIN=localhost 22 | 23 | REDIS_HOST=127.0.0.1 24 | REDIS_PASSWORD=null 25 | REDIS_PORT=6379 26 | 27 | MAIL_MAILER=smtp 28 | MAIL_HOST=smtp.mailtrap.io 29 | MAIL_PORT=2525 30 | MAIL_USERNAME=null 31 | MAIL_PASSWORD=null 32 | MAIL_ENCRYPTION=null 33 | MAIL_FROM_ADDRESS=null 34 | MAIL_FROM_NAME="${APP_NAME}" 35 | 36 | AWS_ACCESS_KEY_ID= 37 | AWS_SECRET_ACCESS_KEY= 38 | AWS_DEFAULT_REGION=us-east-1 39 | AWS_BUCKET= 40 | 41 | PUSHER_APP_ID= 42 | PUSHER_APP_KEY= 43 | PUSHER_APP_SECRET= 44 | PUSHER_APP_CLUSTER=mt1 45 | 46 | MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}" 47 | MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}" 48 | -------------------------------------------------------------------------------- /backend/app/Providers/FortifyServiceProvider.php: -------------------------------------------------------------------------------- 1 | [ 19 | 'api/*', 20 | 'login', 21 | 'logout', 22 | 'sanctum/csrf-cookie' 23 | ], 24 | 25 | 'allowed_methods' => ['*'], 26 | 27 | 'allowed_origins' => ['*'], 28 | 29 | 'allowed_origins_patterns' => [], 30 | 31 | 'allowed_headers' => ['*'], 32 | 33 | 'exposed_headers' => [], 34 | 35 | 'max_age' => 0, 36 | 37 | 'supports_credentials' => true, 38 | 39 | ]; 40 | -------------------------------------------------------------------------------- /backend/config/services.php: -------------------------------------------------------------------------------- 1 | [ 18 | 'domain' => env('MAILGUN_DOMAIN'), 19 | 'secret' => env('MAILGUN_SECRET'), 20 | 'endpoint' => env('MAILGUN_ENDPOINT', 'api.mailgun.net'), 21 | ], 22 | 23 | 'postmark' => [ 24 | 'token' => env('POSTMARK_TOKEN'), 25 | ], 26 | 27 | 'ses' => [ 28 | 'key' => env('AWS_ACCESS_KEY_ID'), 29 | 'secret' => env('AWS_SECRET_ACCESS_KEY'), 30 | 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'), 31 | ], 32 | 33 | ]; 34 | -------------------------------------------------------------------------------- /backend/database/migrations/2019_12_14_000001_create_personal_access_tokens_table.php: -------------------------------------------------------------------------------- 1 | bigIncrements('id'); 18 | $table->morphs('tokenable'); 19 | $table->string('name'); 20 | $table->string('token', 64)->unique(); 21 | $table->text('abilities')->nullable(); 22 | $table->timestamp('last_used_at')->nullable(); 23 | $table->timestamps(); 24 | }); 25 | } 26 | 27 | /** 28 | * Reverse the migrations. 29 | * 30 | * @return void 31 | */ 32 | public function down() 33 | { 34 | Schema::dropIfExists('personal_access_tokens'); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2020 Matilde Wittrup Enevoldsen 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. -------------------------------------------------------------------------------- /backend/database/migrations/2014_10_12_000000_create_users_table.php: -------------------------------------------------------------------------------- 1 | id(); 18 | $table->string('name'); 19 | $table->string('email')->unique(); 20 | $table->timestamp('email_verified_at')->nullable(); 21 | $table->string('password'); 22 | $table->rememberToken(); 23 | $table->foreignId('current_team_id')->nullable(); 24 | $table->text('profile_photo_path')->nullable(); 25 | $table->timestamps(); 26 | }); 27 | } 28 | 29 | /** 30 | * Reverse the migrations. 31 | * 32 | * @return void 33 | */ 34 | public function down() 35 | { 36 | Schema::dropIfExists('users'); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /backend/database/migrations/2014_10_12_200000_add_two_factor_columns_to_users_table.php: -------------------------------------------------------------------------------- 1 | text('two_factor_secret') 18 | ->after('password') 19 | ->nullable(); 20 | 21 | $table->text('two_factor_recovery_codes') 22 | ->after('two_factor_secret') 23 | ->nullable(); 24 | }); 25 | } 26 | 27 | /** 28 | * Reverse the migrations. 29 | * 30 | * @return void 31 | */ 32 | public function down() 33 | { 34 | Schema::table('users', function (Blueprint $table) { 35 | $table->dropColumn('two_factor_secret', 'two_factor_recovery_codes'); 36 | }); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /backend/database/migrations/2020_05_09_120622_create_lessons_table.php: -------------------------------------------------------------------------------- 1 | id(); 18 | $table->string('title'); 19 | $table->string('description'); 20 | $table->string('file'); 21 | $table->string('file_ext'); 22 | $table->integer('order'); 23 | $table->biginteger('course_id')->unsigned()->index(); 24 | $table->timestamps(); 25 | 26 | $table->foreign('course_id')->references('id')->on('courses'); 27 | }); 28 | } 29 | 30 | /** 31 | * Reverse the migrations. 32 | * 33 | * @return void 34 | */ 35 | public function down() 36 | { 37 | Schema::dropIfExists('lessons'); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /frontend/components/Logo.vue: -------------------------------------------------------------------------------- 1 | 20 | 35 | -------------------------------------------------------------------------------- /backend/app/Http/Controllers/Auth/LoginController.php: -------------------------------------------------------------------------------- 1 | middleware('guest')->except('logout'); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /backend/app/Providers/JetstreamServiceProvider.php: -------------------------------------------------------------------------------- 1 | configurePermissions(); 29 | 30 | Jetstream::deleteUsersUsing(DeleteUser::class); 31 | } 32 | 33 | /** 34 | * Configure the permissions that are available within the application. 35 | * 36 | * @return void 37 | */ 38 | protected function configurePermissions() 39 | { 40 | Jetstream::defaultApiTokenPermissions(['read']); 41 | 42 | Jetstream::permissions([ 43 | 'create', 44 | 'read', 45 | 'update', 46 | 'delete', 47 | ]); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /backend/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 | -------------------------------------------------------------------------------- /backend/routes/api.php: -------------------------------------------------------------------------------- 1 | group(function () { 27 | Route::get('/user', function (Request $request) { 28 | return $request->user(); 29 | }); 30 | }); 31 | 32 | Route::middleware(['auth:sanctum', 'admin'])->group(function () { 33 | Route::post('/course/new', 'Courses\CourseController@store'); 34 | }); 35 | -------------------------------------------------------------------------------- /backend/config/jetstream.php: -------------------------------------------------------------------------------- 1 | 'livewire', 19 | 20 | /* 21 | |-------------------------------------------------------------------------- 22 | | Features 23 | |-------------------------------------------------------------------------- 24 | | 25 | | Some of Jetstream's features are optional. You may disable the features 26 | | by removing them from this array. You're free to only remove some of 27 | | these features or you can even remove all of these if you need to. 28 | | 29 | */ 30 | 31 | 'features' => [ 32 | // Features::profilePhotos(), 33 | // Features::api(), 34 | // Features::teams(), 35 | ], 36 | 37 | ]; 38 | -------------------------------------------------------------------------------- /backend/app/Actions/Fortify/UpdateUserPassword.php: -------------------------------------------------------------------------------- 1 | ['required', 'string'], 24 | 'password' => $this->passwordRules(), 25 | ])->after(function ($validator) use ($user, $input) { 26 | if (! Hash::check($input['current_password'], $user->password)) { 27 | $validator->errors()->add('current_password', __('The provided password does not match your current password.')); 28 | } 29 | })->validateWithBag('updatePassword'); 30 | 31 | $user->forceFill([ 32 | 'password' => Hash::make($input['password']), 33 | ])->save(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /backend/app/Http/Controllers/Auth/ConfirmPasswordController.php: -------------------------------------------------------------------------------- 1 | middleware('auth'); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /backend/resources/views/auth/verify.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.app') 2 | 3 | @section('content') 4 |
5 |
6 |
7 |
8 |
{{ __('Verify Your Email Address') }}
9 | 10 |
11 | @if (session('resent')) 12 | 15 | @endif 16 | 17 | {{ __('Before proceeding, please check your email for a verification link.') }} 18 | {{ __('If you did not receive the email') }}, 19 |
20 | @csrf 21 | . 22 |
23 |
24 |
25 |
26 |
27 |
28 | @endsection 29 | -------------------------------------------------------------------------------- /backend/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 | -------------------------------------------------------------------------------- /backend/app/Http/Controllers/Auth/VerificationController.php: -------------------------------------------------------------------------------- 1 | middleware('auth'); 39 | $this->middleware('signed')->only('verify'); 40 | $this->middleware('throttle:6,1')->only('verify', 'resend'); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /frontend/assets/scss/base/_reset.scss: -------------------------------------------------------------------------------- 1 | /* http://meyerweb.com/eric/tools/css/reset/ 2 | v2.0 | 20110126 3 | License: none (public domain) 4 | */ 5 | 6 | html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video { 7 | margin: 0; 8 | padding: 0; 9 | border: 0; 10 | font-size: 100%; 11 | font: inherit; 12 | vertical-align: baseline; } 13 | 14 | /* HTML5 display-role reset for older browsers */ 15 | 16 | article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section { 17 | display: block; } 18 | 19 | body { 20 | line-height: 1; } 21 | 22 | ol, ul { 23 | list-style: none; } 24 | 25 | blockquote, q { 26 | quotes: none; } 27 | 28 | blockquote { 29 | &:before, &:after { 30 | content: ''; 31 | content: none; } } 32 | 33 | q { 34 | &:before, &:after { 35 | content: ''; 36 | content: none; } } 37 | 38 | table { 39 | border-collapse: collapse; 40 | border-spacing: 0; } 41 | -------------------------------------------------------------------------------- /backend/app/Exceptions/Handler.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | {{ __('Forgot your password? No problem. Just let us know your email address and we will email you a password reset link that will allow you to choose a new one.') }} 9 |
10 | 11 | @if (session('status')) 12 |
13 | {{ session('status') }} 14 |
15 | @endif 16 | 17 | 18 | 19 |
20 | @csrf 21 | 22 |
23 | 24 | 25 |
26 | 27 |
28 | 29 | {{ __('Email Password Reset Link') }} 30 | 31 |
32 |
33 |
34 | 35 | -------------------------------------------------------------------------------- /backend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "dev": "npm run development", 5 | "development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js", 6 | "watch": "npm run development -- --watch", 7 | "watch-poll": "npm run watch -- --watch-poll", 8 | "hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js", 9 | "prod": "npm run production", 10 | "production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js" 11 | }, 12 | "devDependencies": { 13 | "@tailwindcss/ui": "^0.6.0", 14 | "alpinejs": "^2.7.3", 15 | "axios": "^0.21", 16 | "bootstrap": "^4.0.0", 17 | "cross-env": "^7.0", 18 | "jquery": "^3.2", 19 | "laravel-mix": "^5.0.1", 20 | "lodash": "^4.17.19", 21 | "popper.js": "^1.12", 22 | "postcss-import": "^12.0.1", 23 | "resolve-url-loader": "^2.3.1", 24 | "sass": "^1.20.1", 25 | "sass-loader": "^8.0.0", 26 | "tailwindcss": "^1.8.0", 27 | "vue": "^2.5.17", 28 | "vue-template-compiler": "^2.6.10" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /backend/resources/js/bootstrap.js: -------------------------------------------------------------------------------- 1 | window._ = require('lodash'); 2 | 3 | /** 4 | * We'll load jQuery and the Bootstrap jQuery plugin which provides support 5 | * for JavaScript based Bootstrap features such as modals and tabs. This 6 | * code may be modified to fit the specific needs of your application. 7 | */ 8 | 9 | try { 10 | window.Popper = require('popper.js').default; 11 | window.$ = window.jQuery = require('jquery'); 12 | 13 | require('bootstrap'); 14 | } catch (e) {} 15 | 16 | /** 17 | * We'll load the axios HTTP library which allows us to easily issue requests 18 | * to our Laravel back-end. This library automatically handles sending the 19 | * CSRF token as a header based on the value of the "XSRF" token cookie. 20 | */ 21 | 22 | window.axios = require('axios'); 23 | 24 | window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest'; 25 | 26 | /** 27 | * Echo exposes an expressive API for subscribing to channels and listening 28 | * for events that are broadcast by Laravel. Echo and event broadcasting 29 | * allows your team to easily build robust real-time web applications. 30 | */ 31 | 32 | // import Echo from 'laravel-echo'; 33 | 34 | // window.Pusher = require('pusher-js'); 35 | 36 | // window.Echo = new Echo({ 37 | // broadcaster: 'pusher', 38 | // key: process.env.MIX_PUSHER_APP_KEY, 39 | // cluster: process.env.MIX_PUSHER_APP_CLUSTER, 40 | // encrypted: true 41 | // }); 42 | -------------------------------------------------------------------------------- /backend/resources/views/layouts/app.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | {{ config('app.name', 'Laravel') }} 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | @livewireStyles 17 | 18 | 19 | 20 | 21 | 22 |
23 | @livewire('navigation-dropdown') 24 | 25 | 26 |
27 |
28 | {{ $header }} 29 |
30 |
31 | 32 | 33 |
34 | {{ $slot }} 35 |
36 |
37 | 38 | @stack('modals') 39 | 40 | @livewireScripts 41 | 42 | 43 | -------------------------------------------------------------------------------- /backend/app/Models/User.php: -------------------------------------------------------------------------------- 1 | 'datetime', 51 | ]; 52 | 53 | /** 54 | * The accessors to append to the model's array form. 55 | * 56 | * @var array 57 | */ 58 | protected $appends = [ 59 | 'profile_photo_url', 60 | ]; 61 | } 62 | -------------------------------------------------------------------------------- /backend/resources/views/profile/show.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 |

4 | {{ __('Profile') }} 5 |

6 |
7 | 8 |
9 |
10 | @if (Laravel\Fortify\Features::canUpdateProfileInformation()) 11 | @livewire('profile.update-profile-information-form') 12 | 13 | 14 | @endif 15 | 16 | @if (Laravel\Fortify\Features::enabled(Laravel\Fortify\Features::updatePasswords())) 17 |
18 | @livewire('profile.update-password-form') 19 |
20 | 21 | 22 | @endif 23 | 24 | @if (Laravel\Fortify\Features::canManageTwoFactorAuthentication()) 25 |
26 | @livewire('profile.two-factor-authentication-form') 27 |
28 | 29 | 30 | @endif 31 | 32 |
33 | @livewire('profile.logout-other-browser-sessions-form') 34 |
35 | 36 | 37 | 38 |
39 | @livewire('profile.delete-user-form') 40 |
41 |
42 |
43 |
44 | -------------------------------------------------------------------------------- /backend/resources/views/auth/verify-email.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | {{ __('Thanks for signing up! Before getting started, could you verify your email address by clicking on the link we just emailed to you? If you didn\'t receive the email, we will gladly send you another.') }} 9 |
10 | 11 | @if (session('status') == 'verification-link-sent') 12 |
13 | {{ __('A new verification link has been sent to the email address you provided during registration.') }} 14 |
15 | @endif 16 | 17 |
18 |
19 | @csrf 20 | 21 |
22 | 23 | {{ __('Resend Verification Email') }} 24 | 25 |
26 |
27 | 28 |
29 | @csrf 30 | 31 | 34 |
35 |
36 |
37 |
38 | -------------------------------------------------------------------------------- /backend/resources/views/auth/reset-password.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | @csrf 11 | 12 | 13 | 14 |
15 | 16 | 17 |
18 | 19 |
20 | 21 | 22 |
23 | 24 |
25 | 26 | 27 |
28 | 29 |
30 | 31 | {{ __('Reset Password') }} 32 | 33 |
34 |
35 |
36 |
37 | -------------------------------------------------------------------------------- /frontend/.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Node template 3 | # Logs 4 | /logs 5 | *.log 6 | npm-debug.log* 7 | yarn-debug.log* 8 | yarn-error.log* 9 | 10 | # Runtime data 11 | pids 12 | *.pid 13 | *.seed 14 | *.pid.lock 15 | 16 | # Directory for instrumented libs generated by jscoverage/JSCover 17 | lib-cov 18 | 19 | # Coverage directory used by tools like istanbul 20 | coverage 21 | 22 | # nyc test coverage 23 | .nyc_output 24 | 25 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 26 | .grunt 27 | 28 | # Bower dependency directory (https://bower.io/) 29 | bower_components 30 | 31 | # node-waf configuration 32 | .lock-wscript 33 | 34 | # Compiled binary addons (https://nodejs.org/api/addons.html) 35 | build/Release 36 | 37 | # Dependency directories 38 | node_modules/ 39 | jspm_packages/ 40 | 41 | # TypeScript v1 declaration files 42 | typings/ 43 | 44 | # Optional npm cache directory 45 | .npm 46 | 47 | # Optional eslint cache 48 | .eslintcache 49 | 50 | # Optional REPL history 51 | .node_repl_history 52 | 53 | # Output of 'npm pack' 54 | *.tgz 55 | 56 | # Yarn Integrity file 57 | .yarn-integrity 58 | 59 | # dotenv environment variables file 60 | .env 61 | 62 | # parcel-bundler cache (https://parceljs.org/) 63 | .cache 64 | 65 | # next.js build output 66 | .next 67 | 68 | # nuxt.js build output 69 | .nuxt 70 | 71 | # Nuxt generate 72 | dist 73 | 74 | # vuepress build output 75 | .vuepress/dist 76 | 77 | # Serverless directories 78 | .serverless 79 | 80 | # IDE / Editor 81 | .idea 82 | 83 | # Service worker 84 | sw.* 85 | 86 | # macOS 87 | .DS_Store 88 | 89 | # Vim swap files 90 | *.swp 91 | -------------------------------------------------------------------------------- /backend/config/hashing.php: -------------------------------------------------------------------------------- 1 | 'bcrypt', 19 | 20 | /* 21 | |-------------------------------------------------------------------------- 22 | | Bcrypt Options 23 | |-------------------------------------------------------------------------- 24 | | 25 | | Here you may specify the configuration options that should be used when 26 | | passwords are hashed using the Bcrypt algorithm. This will allow you 27 | | to control the amount of time it takes to hash the given password. 28 | | 29 | */ 30 | 31 | 'bcrypt' => [ 32 | 'rounds' => env('BCRYPT_ROUNDS', 10), 33 | ], 34 | 35 | /* 36 | |-------------------------------------------------------------------------- 37 | | Argon Options 38 | |-------------------------------------------------------------------------- 39 | | 40 | | Here you may specify the configuration options that should be used when 41 | | passwords are hashed using the Argon algorithm. These will allow you 42 | | to control the amount of time it takes to hash the given password. 43 | | 44 | */ 45 | 46 | 'argon' => [ 47 | 'memory' => 1024, 48 | 'threads' => 2, 49 | 'time' => 2, 50 | ], 51 | 52 | ]; 53 | -------------------------------------------------------------------------------- /backend/app/Http/Controllers/Courses/CourseController.php: -------------------------------------------------------------------------------- 1 | first()); 18 | } else { 19 | return response()->json(['data' => [ 20 | 'errors' => [ 21 | 'root' => 'This course does not exist.' 22 | ], 23 | 'redirect' => true 24 | ]]); 25 | } 26 | } 27 | 28 | public function all() 29 | { 30 | return response()->json(['data' => [ 31 | 'courses' => Course::all() 32 | ]]); 33 | } 34 | 35 | public function store(Request $request) 36 | { 37 | $request->validate([ 38 | 'title' => 'required|min:2', 39 | 'description' => 'required|min:2', 40 | 'slug' => 'required|min:2|unique:courses', 41 | 'is_private' => 'required' 42 | ]); 43 | 44 | $course = Course::create([ 45 | 'title' => $request->title, 46 | 'description' => $request->description, 47 | 'slug' => $request->slug, 48 | 'is_private' => $request->is_private 49 | ]); 50 | 51 | if ($course) { 52 | return response()->json(['data' => [ 53 | 'success' => true, 54 | 'course' => $course 55 | ]]); 56 | } 57 | } 58 | 59 | public function update(Request $request) 60 | { 61 | 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /backend/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 | -------------------------------------------------------------------------------- /backend/config/broadcasting.php: -------------------------------------------------------------------------------- 1 | env('BROADCAST_DRIVER', 'null'), 19 | 20 | /* 21 | |-------------------------------------------------------------------------- 22 | | Broadcast Connections 23 | |-------------------------------------------------------------------------- 24 | | 25 | | Here you may define all of the broadcast connections that will be used 26 | | to broadcast events to other systems or over websockets. Samples of 27 | | each available type of connection are provided inside this array. 28 | | 29 | */ 30 | 31 | 'connections' => [ 32 | 33 | 'pusher' => [ 34 | 'driver' => 'pusher', 35 | 'key' => env('PUSHER_APP_KEY'), 36 | 'secret' => env('PUSHER_APP_SECRET'), 37 | 'app_id' => env('PUSHER_APP_ID'), 38 | 'options' => [ 39 | 'cluster' => env('PUSHER_APP_CLUSTER'), 40 | 'useTLS' => true, 41 | ], 42 | ], 43 | 44 | 'redis' => [ 45 | 'driver' => 'redis', 46 | 'connection' => 'default', 47 | ], 48 | 49 | 'log' => [ 50 | 'driver' => 'log', 51 | ], 52 | 53 | 'null' => [ 54 | 'driver' => 'null', 55 | ], 56 | 57 | ], 58 | 59 | ]; 60 | -------------------------------------------------------------------------------- /backend/config/sanctum.php: -------------------------------------------------------------------------------- 1 | explode(',', env( 17 | 'SANCTUM_STATEFUL_DOMAINS', 18 | 'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1' 19 | )), 20 | 21 | /* 22 | |-------------------------------------------------------------------------- 23 | | Expiration Minutes 24 | |-------------------------------------------------------------------------- 25 | | 26 | | This value controls the number of minutes until an issued token will be 27 | | considered expired. If this value is null, personal access tokens do 28 | | not expire. This won't tweak the lifetime of first-party sessions. 29 | | 30 | */ 31 | 32 | 'expiration' => null, 33 | 34 | /* 35 | |-------------------------------------------------------------------------- 36 | | Sanctum Middleware 37 | |-------------------------------------------------------------------------- 38 | | 39 | | When authenticating your first-party SPA with Sanctum you may need to 40 | | customize some of the middleware Sanctum uses while processing the 41 | | request. You may change the middleware listed below as required. 42 | | 43 | */ 44 | 45 | 'middleware' => [ 46 | 'verify_csrf_token' => App\Http\Middleware\VerifyCsrfToken::class, 47 | 'encrypt_cookies' => App\Http\Middleware\EncryptCookies::class, 48 | ], 49 | 50 | ]; 51 | -------------------------------------------------------------------------------- /backend/resources/views/profile/update-password-form.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | {{ __('Update Password') }} 4 | 5 | 6 | 7 | {{ __('Ensure your account is using a long, random password to stay secure.') }} 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 |
16 | 17 |
18 | 19 | 20 | 21 |
22 | 23 |
24 | 25 | 26 | 27 |
28 |
29 | 30 | 31 | 32 | {{ __('Saved.') }} 33 | 34 | 35 | 36 | {{ __('Save') }} 37 | 38 | 39 |
40 | -------------------------------------------------------------------------------- /backend/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 | -------------------------------------------------------------------------------- /backend/app/Actions/Fortify/UpdateUserProfileInformation.php: -------------------------------------------------------------------------------- 1 | ['required', 'string', 'max:255'], 23 | 'email' => ['required', 'email', 'max:255', Rule::unique('users')->ignore($user->id)], 24 | 'photo' => ['nullable', 'image', 'max:1024'], 25 | ])->validateWithBag('updateProfileInformation'); 26 | 27 | if (isset($input['photo'])) { 28 | $user->updateProfilePhoto($input['photo']); 29 | } 30 | 31 | if ($input['email'] !== $user->email && 32 | $user instanceof MustVerifyEmail) { 33 | $this->updateVerifiedUser($user, $input); 34 | } else { 35 | $user->forceFill([ 36 | 'name' => $input['name'], 37 | 'email' => $input['email'], 38 | ])->save(); 39 | } 40 | } 41 | 42 | /** 43 | * Update the given verified user's profile information. 44 | * 45 | * @param mixed $user 46 | * @param array $input 47 | * @return void 48 | */ 49 | protected function updateVerifiedUser($user, array $input) 50 | { 51 | $user->forceFill([ 52 | 'name' => $input['name'], 53 | 'email' => $input['email'], 54 | 'email_verified_at' => null, 55 | ])->save(); 56 | 57 | $user->sendEmailVerificationNotification(); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /backend/resources/views/auth/register.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | @csrf 11 | 12 |
13 | 14 | 15 |
16 | 17 |
18 | 19 | 20 |
21 | 22 |
23 | 24 | 25 |
26 | 27 |
28 | 29 | 30 |
31 | 32 |
33 | 34 | {{ __('Already registered?') }} 35 | 36 | 37 | 38 | {{ __('Register') }} 39 | 40 |
41 |
42 |
43 |
44 | -------------------------------------------------------------------------------- /frontend/nuxt.config.js: -------------------------------------------------------------------------------- 1 | 2 | export default { 3 | mode: 'universal', 4 | /* 5 | ** Headers of the page 6 | */ 7 | head: { 8 | title: process.env.npm_package_name || '', 9 | meta: [ 10 | { charset: 'utf-8' }, 11 | { name: 'viewport', content: 'width=device-width, initial-scale=1' }, 12 | { hid: 'description', name: 'description', content: process.env.npm_package_description || '' } 13 | ], 14 | link: [ 15 | { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' } 16 | ] 17 | }, 18 | /* 19 | ** Customize the progress-bar color 20 | */ 21 | loading: { color: '#fff' }, 22 | /* 23 | ** Global CSS 24 | */ 25 | css: [ 26 | 'ant-design-vue/dist/antd.css', 27 | '@/assets/scss/app.scss', 28 | ], 29 | /* 30 | ** Plugins to load before mounting the App 31 | */ 32 | plugins: [ 33 | '@/plugins/antd-ui' 34 | ], 35 | /* 36 | ** Nuxt.js dev-modules 37 | */ 38 | buildModules: [ 39 | ], 40 | /* 41 | ** Nuxt.js modules 42 | */ 43 | modules: [ 44 | // Doc: https://axios.nuxtjs.org/usage 45 | '@nuxtjs/axios', 46 | '@nuxtjs/pwa', 47 | // Doc: https://github.com/nuxt-community/dotenv-module 48 | '@nuxtjs/dotenv', 49 | '@nuxtjs/auth' 50 | ], 51 | auth: { 52 | 53 | strategies: { 54 | local: { 55 | endpoints: { 56 | login: {url: '/login', method: 'post'}, 57 | logout: {url: '/logout', method: 'post'}, 58 | user: {url: '/api/user', method: 'get', propertyName: false} 59 | }, 60 | tokenRequired: false, 61 | tokenType: false, 62 | } 63 | } 64 | }, 65 | /* 66 | ** Axios module configuration 67 | ** See https://axios.nuxtjs.org/options 68 | */ 69 | axios: { 70 | baseURL: 'http://localhost:8000/', 71 | credentials: true 72 | }, 73 | /* 74 | ** Build configuration 75 | */ 76 | build: { 77 | /* 78 | ** You can extend webpack config here 79 | */ 80 | extend (config, ctx) { 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /frontend/layouts/default.vue: -------------------------------------------------------------------------------- 1 | 54 | 70 | -------------------------------------------------------------------------------- /backend/app/Providers/RouteServiceProvider.php: -------------------------------------------------------------------------------- 1 | mapApiRoutes(); 46 | 47 | $this->mapWebRoutes(); 48 | 49 | // 50 | } 51 | 52 | /** 53 | * Define the "web" routes for the application. 54 | * 55 | * These routes all receive session state, CSRF protection, etc. 56 | * 57 | * @return void 58 | */ 59 | protected function mapWebRoutes() 60 | { 61 | Route::middleware('web') 62 | ->namespace($this->namespace) 63 | ->group(base_path('routes/web.php')); 64 | } 65 | 66 | /** 67 | * Define the "api" routes for the application. 68 | * 69 | * These routes are typically stateless. 70 | * 71 | * @return void 72 | */ 73 | protected function mapApiRoutes() 74 | { 75 | Route::prefix('api') 76 | ->middleware('api') 77 | ->namespace($this->namespace) 78 | ->group(base_path('routes/api.php')); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /backend/resources/views/auth/login.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | @if (session('status')) 10 |
11 | {{ session('status') }} 12 |
13 | @endif 14 | 15 |
16 | @csrf 17 | 18 |
19 | 20 | 21 |
22 | 23 |
24 | 25 | 26 |
27 | 28 |
29 | 33 |
34 | 35 |
36 | @if (Route::has('password.request')) 37 | 38 | {{ __('Forgot your password?') }} 39 | 40 | @endif 41 | 42 | 43 | {{ __('Login') }} 44 | 45 |
46 |
47 |
48 |
49 | -------------------------------------------------------------------------------- /backend/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "laravel/laravel", 3 | "type": "project", 4 | "description": "The Laravel Framework.", 5 | "keywords": [ 6 | "framework", 7 | "laravel" 8 | ], 9 | "license": "MIT", 10 | "require": { 11 | "php": "^7.2.5", 12 | "fideloper/proxy": "^4.2", 13 | "fruitcake/laravel-cors": "^1.0", 14 | "guzzlehttp/guzzle": "^7.0.1", 15 | "laravel/framework": "^v8.0.4", 16 | "laravel/jetstream": "^1.6", 17 | "laravel/legacy-factories": "^1.1", 18 | "laravel/sanctum": "^2.6", 19 | "laravel/tinker": "^2.0", 20 | "laravel/ui": "^v3.1.0", 21 | "livewire/livewire": "^2.0" 22 | }, 23 | "require-dev": { 24 | "facade/ignition": "^2.3.8", 25 | "fzaninotto/faker": "^1.9.1", 26 | "mockery/mockery": "^1.3.1", 27 | "nunomaduro/collision": "^v5.1.0", 28 | "phpunit/phpunit": "^9.5.0" 29 | }, 30 | "config": { 31 | "optimize-autoloader": true, 32 | "preferred-install": "dist", 33 | "sort-packages": true 34 | }, 35 | "extra": { 36 | "laravel": { 37 | "dont-discover": [] 38 | } 39 | }, 40 | "autoload": { 41 | "psr-4": { 42 | "App\\": "app/" 43 | }, 44 | "classmap": [ 45 | "database/seeds", 46 | "database/factories" 47 | ] 48 | }, 49 | "autoload-dev": { 50 | "psr-4": { 51 | "Tests\\": "tests/" 52 | } 53 | }, 54 | "minimum-stability": "dev", 55 | "prefer-stable": true, 56 | "scripts": { 57 | "post-autoload-dump": [ 58 | "Illuminate\\Foundation\\ComposerScripts::postAutoloadDump", 59 | "@php artisan package:discover --ansi" 60 | ], 61 | "post-root-package-install": [ 62 | "@php -r \"file_exists('.env') || copy('.env.example', '.env');\"" 63 | ], 64 | "post-create-project-cmd": [ 65 | "@php artisan key:generate --ansi" 66 | ] 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /backend/public/index.php: -------------------------------------------------------------------------------- 1 | 8 | */ 9 | 10 | define('LARAVEL_START', microtime(true)); 11 | 12 | /* 13 | |-------------------------------------------------------------------------- 14 | | Register The Auto Loader 15 | |-------------------------------------------------------------------------- 16 | | 17 | | Composer provides a convenient, automatically generated class loader for 18 | | our application. We just need to utilize it! We'll simply require it 19 | | into the script here so that we don't have to worry about manual 20 | | loading any of our classes later on. It feels great to relax. 21 | | 22 | */ 23 | 24 | require __DIR__.'/../vendor/autoload.php'; 25 | 26 | /* 27 | |-------------------------------------------------------------------------- 28 | | Turn On The Lights 29 | |-------------------------------------------------------------------------- 30 | | 31 | | We need to illuminate PHP development, so let us turn on the lights. 32 | | This bootstraps the framework and gets it ready for use, then it 33 | | will load up this application so that we can run it and send 34 | | the responses back to the browser and delight our users. 35 | | 36 | */ 37 | 38 | $app = require_once __DIR__.'/../bootstrap/app.php'; 39 | 40 | /* 41 | |-------------------------------------------------------------------------- 42 | | Run The Application 43 | |-------------------------------------------------------------------------- 44 | | 45 | | Once we have the application, we can handle the incoming request 46 | | through the kernel, and send the associated response back to 47 | | the client's browser allowing them to enjoy the creative 48 | | and wonderful application we have prepared for them. 49 | | 50 | */ 51 | 52 | $kernel = $app->make(Illuminate\Contracts\Http\Kernel::class); 53 | 54 | $response = $kernel->handle( 55 | $request = Illuminate\Http\Request::capture() 56 | ); 57 | 58 | $response->send(); 59 | 60 | $kernel->terminate($request, $response); 61 | -------------------------------------------------------------------------------- /backend/app/Http/Controllers/Auth/RegisterUserController.php: -------------------------------------------------------------------------------- 1 | validate([ 18 | 'name' => ['required', 'string', 'max:255'], 19 | 'country' => ['required'], 20 | 'email' => ['required', 'string', 'email', 'max:255', 'unique:users'], 21 | 'password' => ['required', 'string', 'min:8', 'confirmed'], 22 | ]); 23 | 24 | $user = User::create([ 25 | 'name' => $request['name'], 26 | 'country' => $request['country'], 27 | 'email' => $request['email'], 28 | 'email_verification_code' => md5(rand(0, 6)), 29 | 'password' => Hash::make($request['password']), 30 | ]); 31 | 32 | if ($user) { 33 | Mail::send(new VerifyEmail($user)); 34 | 35 | return response()->json(['data' => [ 36 | 'success' => true, 37 | ]]); 38 | } else { 39 | return response()->json(['errors' => [ 40 | 'root' => 'Cannot create user.' 41 | ]]); 42 | } 43 | } 44 | 45 | public function verify(Request $request) 46 | { 47 | $request->validate([ 48 | 'id' => 'required', 49 | 'token' => 'required' 50 | ]); 51 | 52 | $user = User::find($request->id); 53 | if ($user && $request->token == $user->email_verification_code) { 54 | $user->email_verified_at = now(); 55 | $user->email_verification_code = md5(rand(0, 6)); 56 | 57 | $user->save(); 58 | 59 | return response()->json(['data' => [ 60 | 'success' => true 61 | ]]); 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /backend/resources/views/auth/passwords/email.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.app') 2 | 3 | @section('content') 4 |
5 |
6 |
7 |
8 |
{{ __('Reset Password') }}
9 | 10 |
11 | @if (session('status')) 12 | 15 | @endif 16 | 17 |
18 | @csrf 19 | 20 |
21 | 22 | 23 |
24 | 25 | 26 | @error('email') 27 | 28 | {{ $message }} 29 | 30 | @enderror 31 |
32 |
33 | 34 |
35 |
36 | 39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | @endsection 48 | -------------------------------------------------------------------------------- /frontend/pages/courses/_slug.vue: -------------------------------------------------------------------------------- 1 | 22 | 49 | 76 | -------------------------------------------------------------------------------- /frontend/pages/lessons/_slug.vue: -------------------------------------------------------------------------------- 1 | 22 | 49 | 76 | -------------------------------------------------------------------------------- /backend/app/Http/Controllers/Auth/RegisterController.php: -------------------------------------------------------------------------------- 1 | middleware('guest'); 42 | } 43 | 44 | /** 45 | * Get a validator for an incoming registration request. 46 | * 47 | * @param array $data 48 | * @return \Illuminate\Contracts\Validation\Validator 49 | */ 50 | protected function validator(array $data) 51 | { 52 | return Validator::make($data, [ 53 | 'name' => ['required', 'string', 'max:255'], 54 | 'email' => ['required', 'string', 'email', 'max:255', 'unique:users'], 55 | 'password' => ['required', 'string', 'min:8', 'confirmed'], 56 | ]); 57 | } 58 | 59 | /** 60 | * Create a new user instance after a valid registration. 61 | * 62 | * @param array $data 63 | * @return \App\User 64 | */ 65 | protected function create(array $data) 66 | { 67 | return User::create([ 68 | 'name' => $data['name'], 69 | 'email' => $data['email'], 70 | 'password' => Hash::make($data['password']), 71 | ]); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /backend/resources/views/auth/passwords/confirm.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.app') 2 | 3 | @section('content') 4 |
5 |
6 |
7 |
8 |
{{ __('Confirm Password') }}
9 | 10 |
11 | {{ __('Please confirm your password before continuing.') }} 12 | 13 |
14 | @csrf 15 | 16 |
17 | 18 | 19 |
20 | 21 | 22 | @error('password') 23 | 24 | {{ $message }} 25 | 26 | @enderror 27 |
28 |
29 | 30 |
31 |
32 | 35 | 36 | @if (Route::has('password.request')) 37 | 38 | {{ __('Forgot Your Password?') }} 39 | 40 | @endif 41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 | @endsection 50 | -------------------------------------------------------------------------------- /backend/resources/views/profile/delete-user-form.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | {{ __('Delete Account') }} 4 | 5 | 6 | 7 | {{ __('Permanently delete your account.') }} 8 | 9 | 10 | 11 |
12 | {{ __('Once your account is deleted, all of its resources and data will be permanently deleted. Before deleting your account, please download any data or information that you wish to retain.') }} 13 |
14 | 15 |
16 | 17 | {{ __('Delete Account') }} 18 | 19 |
20 | 21 | 22 | 23 | 24 | {{ __('Delete Account') }} 25 | 26 | 27 | 28 | {{ __('Are you sure you want to delete your account? Once your account is deleted, all of its resources and data will be permanently deleted. Please enter your password to confirm you would like to permanently delete your account.') }} 29 | 30 |
31 | 35 | 36 | 37 |
38 |
39 | 40 | 41 | 42 | {{ __('Nevermind') }} 43 | 44 | 45 | 46 | {{ __('Delete Account') }} 47 | 48 | 49 |
50 |
51 |
52 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Course Platform 2 | 3 | Course platform built with Laravel 8 and NuxtJS. This is the official repo for [How to build a course platform with NuxtJS, Laravel 8 and Stripe](https://www.youtube.com/watch?v=xS4Om2ZSu2o&list=PLjCZ5YN4Hlacehn798-qep4yXDcL4oF-x). 4 | 5 | ## Getting Started 6 | To get started please ensure you have the following installed: 7 | 8 | - Composer 9 | - NPM and NodeJS 10 | - PHP 7.2.5 or newer. 11 | 12 | # Installing 13 | 14 | ## Backend 15 | In order to install it please clone the repo. Then in the backend directory run these commands and ensure to have set up database configuration in .env file: 16 | 17 | ``` 18 | composer install 19 | php artisan migrate 20 | ``` 21 | 22 | To run the backend code please use Laravel's in-built ``php artisan serve`` function to run it locally. 23 | 24 | ### .env File 25 | Please ensure that you copy .env.example and configure the database and email settings to your preference. Additionally, you should add ``SESSION_DOMAIN=localhost`` for local hosting and change it to your backend domain name when published. 26 | 27 | ### Are you upgrading from Laravel 7 to 8? 28 | 29 | I'm aware certain subscribers of my channel might not have upgraded to Laravel 8, and while composer.json reflects the upgrades in here you might not want to clone the project to disrupt changes you have made. Therefore, I am providing a step-by-step guide on YouTube as well as in the README file: 30 | 31 | - 1st) Follow all these steps in here https://laravel.com/docs/8.x/upgrade, perhaps copy and paste composer.json file from here. 32 | - 2nd) If you haven't already installed jetstream please run this command ``composer require laravel/jetstream`` 33 | - 3rd) Install livewire ``php artisan jetstream:install livewire`` 34 | - 4th) You might encounter a bug if you don't add the following code to ``App/Providers/AppServiceProvider.php``: 35 | Inside the file add: 36 | ```php 37 | use Illuminate\Support\Facades\Schema; //Add below namespace 38 | 39 | public function boot() 40 | { 41 | Schema::defaultstringLength(191); 42 | } 43 | ``` 44 | - 5th) Migrate changes to reflect on your database ``php artisan migrate`` 45 | 46 | 47 | ## Frontend 48 | 49 | In order to setup the frontend code please install the dependinces using ``npm install``. To run the frontend please use ``npm run dev`` 50 | ### Built With 51 | 52 | - [Laravel 8](https://laravel.com/docs/8.x) - backend framework. 53 | - [NuxtJS](http://nuxtjs.org/) - frontend framework. 54 | - Designed with [Ant Design Vue](https://www.antdv.com/). 55 | 56 | ### Authors 57 | 58 | *Matilde Wittrup* - Initial Work - Wimm Media and coding tutorials on [YouTube](youtube.com/c/matildewittrup). 59 | 60 | ### License 61 | 62 | This project is licensed under the MIT license - see the [LICENSE.MD](https://github.com/Matildevoldsen/course-platform/blob/master/LICENSE.md) for details. 63 | -------------------------------------------------------------------------------- /backend/app/Http/Kernel.php: -------------------------------------------------------------------------------- 1 | [ 33 | \App\Http\Middleware\EncryptCookies::class, 34 | \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class, 35 | \Illuminate\Session\Middleware\StartSession::class, 36 | \Laravel\Jetstream\Http\Middleware\AuthenticateSession::class, 37 | \Illuminate\View\Middleware\ShareErrorsFromSession::class, 38 | \App\Http\Middleware\VerifyCsrfToken::class, 39 | \Illuminate\Routing\Middleware\SubstituteBindings::class, 40 | ], 41 | 42 | 'api' => [ 43 | EnsureFrontendRequestsAreStateful::class, 44 | 'throttle:60,1', 45 | \Illuminate\Routing\Middleware\SubstituteBindings::class, 46 | ], 47 | ]; 48 | 49 | /** 50 | * The application's route middleware. 51 | * 52 | * These middleware may be assigned to groups or used individually. 53 | * 54 | * @var array 55 | */ 56 | protected $routeMiddleware = [ 57 | 'admin' => \App\Http\Middleware\Admin::class, 58 | 'auth' => \App\Http\Middleware\Authenticate::class, 59 | 'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class, 60 | 'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class, 61 | 'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class, 62 | 'can' => \Illuminate\Auth\Middleware\Authorize::class, 63 | 'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class, 64 | 'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class, 65 | 'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class, 66 | 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class, 67 | 'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class, 68 | ]; 69 | } 70 | -------------------------------------------------------------------------------- /backend/resources/views/auth/two-factor-challenge.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 |
9 | {{ __('Please confirm access to your account by entering the authentication code provided by your authenticator application.') }} 10 |
11 | 12 |
13 | {{ __('Please confirm access to your account by entering one of your emergency recovery codes.') }} 14 |
15 | 16 | 17 | 18 |
19 | @csrf 20 | 21 |
22 | 23 | 24 |
25 | 26 |
27 | 28 | 29 |
30 | 31 |
32 | 40 | 41 | 49 | 50 | 51 | {{ __('Login') }} 52 | 53 |
54 |
55 |
56 |
57 |
58 | -------------------------------------------------------------------------------- /backend/config/filesystems.php: -------------------------------------------------------------------------------- 1 | env('FILESYSTEM_DRIVER', 'local'), 17 | 18 | /* 19 | |-------------------------------------------------------------------------- 20 | | Default Cloud Filesystem Disk 21 | |-------------------------------------------------------------------------- 22 | | 23 | | Many applications store files both locally and in the cloud. For this 24 | | reason, you may specify a default "cloud" driver here. This driver 25 | | will be bound as the Cloud disk implementation in the container. 26 | | 27 | */ 28 | 29 | 'cloud' => env('FILESYSTEM_CLOUD', 's3'), 30 | 31 | /* 32 | |-------------------------------------------------------------------------- 33 | | Filesystem Disks 34 | |-------------------------------------------------------------------------- 35 | | 36 | | Here you may configure as many filesystem "disks" as you wish, and you 37 | | may even configure multiple disks of the same driver. Defaults have 38 | | been setup for each driver as an example of the required options. 39 | | 40 | | Supported Drivers: "local", "ftp", "sftp", "s3" 41 | | 42 | */ 43 | 44 | 'disks' => [ 45 | 46 | 'local' => [ 47 | 'driver' => 'local', 48 | 'root' => storage_path('app'), 49 | ], 50 | 51 | 'public' => [ 52 | 'driver' => 'local', 53 | 'root' => storage_path('app/public'), 54 | 'url' => env('APP_URL').'/storage', 55 | 'visibility' => 'public', 56 | ], 57 | 58 | 's3' => [ 59 | 'driver' => 's3', 60 | 'key' => env('AWS_ACCESS_KEY_ID'), 61 | 'secret' => env('AWS_SECRET_ACCESS_KEY'), 62 | 'region' => env('AWS_DEFAULT_REGION'), 63 | 'bucket' => env('AWS_BUCKET'), 64 | 'url' => env('AWS_URL'), 65 | 'endpoint' => env('AWS_ENDPOINT'), 66 | ], 67 | 68 | ], 69 | 70 | /* 71 | |-------------------------------------------------------------------------- 72 | | Symbolic Links 73 | |-------------------------------------------------------------------------- 74 | | 75 | | Here you may configure the symbolic links that will be created when the 76 | | `storage:link` Artisan command is executed. The array keys should be 77 | | the locations of the links and the values should be their targets. 78 | | 79 | */ 80 | 81 | 'links' => [ 82 | public_path('storage') => storage_path('app/public'), 83 | ], 84 | 85 | ]; 86 | -------------------------------------------------------------------------------- /frontend/pages/auth/login.vue: -------------------------------------------------------------------------------- 1 | 48 | 78 | 88 | -------------------------------------------------------------------------------- /backend/config/queue.php: -------------------------------------------------------------------------------- 1 | env('QUEUE_CONNECTION', 'sync'), 17 | 18 | /* 19 | |-------------------------------------------------------------------------- 20 | | Queue Connections 21 | |-------------------------------------------------------------------------- 22 | | 23 | | Here you may configure the connection information for each server that 24 | | is used by your application. A default configuration has been added 25 | | for each back-end shipped with Laravel. You are free to add more. 26 | | 27 | | Drivers: "sync", "database", "beanstalkd", "sqs", "redis", "null" 28 | | 29 | */ 30 | 31 | 'connections' => [ 32 | 33 | 'sync' => [ 34 | 'driver' => 'sync', 35 | ], 36 | 37 | 'database' => [ 38 | 'driver' => 'database', 39 | 'table' => 'jobs', 40 | 'queue' => 'default', 41 | 'retry_after' => 90, 42 | ], 43 | 44 | 'beanstalkd' => [ 45 | 'driver' => 'beanstalkd', 46 | 'host' => 'localhost', 47 | 'queue' => 'default', 48 | 'retry_after' => 90, 49 | 'block_for' => 0, 50 | ], 51 | 52 | 'sqs' => [ 53 | 'driver' => 'sqs', 54 | 'key' => env('AWS_ACCESS_KEY_ID'), 55 | 'secret' => env('AWS_SECRET_ACCESS_KEY'), 56 | 'prefix' => env('SQS_PREFIX', 'https://sqs.us-east-1.amazonaws.com/your-account-id'), 57 | 'queue' => env('SQS_QUEUE', 'your-queue-name'), 58 | 'suffix' => env('SQS_SUFFIX'), 59 | 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'), 60 | ], 61 | 62 | 'redis' => [ 63 | 'driver' => 'redis', 64 | 'connection' => 'default', 65 | 'queue' => env('REDIS_QUEUE', 'default'), 66 | 'retry_after' => 90, 67 | 'block_for' => null, 68 | ], 69 | 70 | ], 71 | 72 | /* 73 | |-------------------------------------------------------------------------- 74 | | Failed Queue Jobs 75 | |-------------------------------------------------------------------------- 76 | | 77 | | These options configure the behavior of failed queue job logging so you 78 | | can control which database and table are used to store the jobs that 79 | | have failed. You may change them to any database / table you wish. 80 | | 81 | */ 82 | 83 | 'failed' => [ 84 | 'driver' => env('QUEUE_FAILED_DRIVER', 'database'), 85 | 'database' => env('DB_CONNECTION', 'mysql'), 86 | 'table' => 'failed_jobs', 87 | ], 88 | 89 | ]; 90 | -------------------------------------------------------------------------------- /frontend/assets/scss/layouts/_navbar.scss: -------------------------------------------------------------------------------- 1 | .navbar { 2 | width: 100%; 3 | background: #fff; 4 | display: flex; 5 | align-items: center; 6 | padding: 10px 50px; 7 | box-sizing: border-box; 8 | height: 90px; 9 | font-size: 1.1em; 10 | box-shadow: 0px 4px 20px 0px rgba(0, 0, 0, .05); 11 | 12 | .navbar-container { 13 | width: 100%; 14 | } 15 | 16 | .logo { 17 | padding-right: 20px; 18 | min-width: 100px; 19 | } 20 | 21 | .backdrop { 22 | display: none; 23 | animation: 0.4s ease-in-out fadeIn forwards; 24 | position: absolute; 25 | top: 0; 26 | bottom: 0; 27 | right: 0; 28 | left: 0; 29 | background: rgba(0, 0, 0, 0); 30 | cursor: pointer; 31 | } 32 | 33 | 34 | .navbar-items { 35 | display: flex; 36 | list-style: none; 37 | flex: 1; 38 | margin-bottom: 0 !important; 39 | align-items: center; 40 | justify-content: space-between; 41 | 42 | .nav-left { 43 | justify-content: flex-start; 44 | } 45 | 46 | .nav-right { 47 | justify-content: flex-end; 48 | } 49 | 50 | .nav-left, .nav-right { 51 | li { 52 | margin-right: 24px; 53 | float: left; 54 | 55 | a { 56 | text-decoration: none; 57 | color: #575757; 58 | letter-spacing: -0.5px; 59 | 60 | &:hover { 61 | color: #000; 62 | } 63 | } 64 | } 65 | } 66 | } 67 | } 68 | 69 | .icon, 70 | .close-btn { 71 | display: none; 72 | font-size: 1.2em; 73 | cursor: pointer; 74 | } 75 | 76 | #toggler { 77 | display: none; 78 | } 79 | 80 | @keyframes fadeIn { 81 | to { 82 | background: rgba(0, 0, 0, 0.8); 83 | } 84 | } 85 | 86 | /* Mobile view */ 87 | @media (max-width: 675px) { 88 | .navbar { 89 | padding: 10px 30px; 90 | } 91 | 92 | .navbar-items { 93 | justify-content: center !important; 94 | position: absolute; 95 | top: 0; 96 | height: 100%; 97 | width: 90%; 98 | right: -90%; 99 | background: #fff; 100 | flex-direction: column; 101 | text-align: center; 102 | z-index: 2; 103 | margin-bottom: 0 !important; 104 | transition: 0.3s ease-in-out; 105 | } 106 | 107 | .icon, 108 | .close-btn { 109 | display: block; 110 | cursor: pointer; 111 | } 112 | .icon { 113 | position: absolute; 114 | right: 24px; 115 | } 116 | 117 | .navbar-items li { 118 | float: none !important; 119 | margin-right: 0; 120 | margin-bottom: 20px; 121 | font-size: 1.5em; 122 | } 123 | .close-btn { 124 | position: absolute; 125 | top: 24px; 126 | right: -90vh; 127 | color: #575757; 128 | font-size: 2em; 129 | z-index: 3; 130 | transition: 0.3s ease-in-out; 131 | } 132 | .close-btn:hover { 133 | color: #000; 134 | cursor: pointer; 135 | } 136 | 137 | input#toggler:checked ~ .navbar-container .navbar-items { 138 | right: 0; 139 | } 140 | input#toggler:checked ~ .navbar-container .close-btn { 141 | right: 32px; 142 | } 143 | input#toggler:checked ~ .navbar-container .backdrop { 144 | display: block; 145 | } 146 | } 147 | 148 | -------------------------------------------------------------------------------- /backend/resources/views/auth/passwords/reset.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.app') 2 | 3 | @section('content') 4 |
5 |
6 |
7 |
8 |
{{ __('Reset Password') }}
9 | 10 |
11 |
12 | @csrf 13 | 14 | 15 | 16 |
17 | 18 | 19 |
20 | 21 | 22 | @error('email') 23 | 24 | {{ $message }} 25 | 26 | @enderror 27 |
28 |
29 | 30 |
31 | 32 | 33 |
34 | 35 | 36 | @error('password') 37 | 38 | {{ $message }} 39 | 40 | @enderror 41 |
42 |
43 | 44 |
45 | 46 | 47 |
48 | 49 |
50 |
51 | 52 |
53 |
54 | 57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 | @endsection 66 | -------------------------------------------------------------------------------- /backend/config/logging.php: -------------------------------------------------------------------------------- 1 | env('LOG_CHANNEL', 'stack'), 21 | 22 | /* 23 | |-------------------------------------------------------------------------- 24 | | Log Channels 25 | |-------------------------------------------------------------------------- 26 | | 27 | | Here you may configure the log channels for your application. Out of 28 | | the box, Laravel uses the Monolog PHP logging library. This gives 29 | | you a variety of powerful log handlers / formatters to utilize. 30 | | 31 | | Available Drivers: "single", "daily", "slack", "syslog", 32 | | "errorlog", "monolog", 33 | | "custom", "stack" 34 | | 35 | */ 36 | 37 | 'channels' => [ 38 | 'stack' => [ 39 | 'driver' => 'stack', 40 | 'channels' => ['single'], 41 | 'ignore_exceptions' => false, 42 | ], 43 | 44 | 'single' => [ 45 | 'driver' => 'single', 46 | 'path' => storage_path('logs/laravel.log'), 47 | 'level' => 'debug', 48 | ], 49 | 50 | 'daily' => [ 51 | 'driver' => 'daily', 52 | 'path' => storage_path('logs/laravel.log'), 53 | 'level' => 'debug', 54 | 'days' => 14, 55 | ], 56 | 57 | 'slack' => [ 58 | 'driver' => 'slack', 59 | 'url' => env('LOG_SLACK_WEBHOOK_URL'), 60 | 'username' => 'Laravel Log', 61 | 'emoji' => ':boom:', 62 | 'level' => 'critical', 63 | ], 64 | 65 | 'papertrail' => [ 66 | 'driver' => 'monolog', 67 | 'level' => 'debug', 68 | 'handler' => SyslogUdpHandler::class, 69 | 'handler_with' => [ 70 | 'host' => env('PAPERTRAIL_URL'), 71 | 'port' => env('PAPERTRAIL_PORT'), 72 | ], 73 | ], 74 | 75 | 'stderr' => [ 76 | 'driver' => 'monolog', 77 | 'handler' => StreamHandler::class, 78 | 'formatter' => env('LOG_STDERR_FORMATTER'), 79 | 'with' => [ 80 | 'stream' => 'php://stderr', 81 | ], 82 | ], 83 | 84 | 'syslog' => [ 85 | 'driver' => 'syslog', 86 | 'level' => 'debug', 87 | ], 88 | 89 | 'errorlog' => [ 90 | 'driver' => 'errorlog', 91 | 'level' => 'debug', 92 | ], 93 | 94 | 'null' => [ 95 | 'driver' => 'monolog', 96 | 'handler' => NullHandler::class, 97 | ], 98 | 99 | 'emergency' => [ 100 | 'path' => storage_path('logs/laravel.log'), 101 | ], 102 | ], 103 | 104 | ]; 105 | -------------------------------------------------------------------------------- /backend/resources/views/welcome.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Laravel 8 | 9 | 10 | 11 | 12 | 13 | 65 | 66 | 67 |
68 | @if (Route::has('login')) 69 | 80 | @endif 81 | 82 |
83 |
84 | Laravel 85 |
86 | 87 | 97 |
98 |
99 | 100 | 101 | -------------------------------------------------------------------------------- /backend/config/cache.php: -------------------------------------------------------------------------------- 1 | env('CACHE_DRIVER', 'file'), 22 | 23 | /* 24 | |-------------------------------------------------------------------------- 25 | | Cache Stores 26 | |-------------------------------------------------------------------------- 27 | | 28 | | Here you may define all of the cache "stores" for your application as 29 | | well as their drivers. You may even define multiple stores for the 30 | | same cache driver to group types of items stored in your caches. 31 | | 32 | */ 33 | 34 | 'stores' => [ 35 | 36 | 'apc' => [ 37 | 'driver' => 'apc', 38 | ], 39 | 40 | 'array' => [ 41 | 'driver' => 'array', 42 | 'serialize' => false, 43 | ], 44 | 45 | 'database' => [ 46 | 'driver' => 'database', 47 | 'table' => 'cache', 48 | 'connection' => null, 49 | ], 50 | 51 | 'file' => [ 52 | 'driver' => 'file', 53 | 'path' => storage_path('framework/cache/data'), 54 | ], 55 | 56 | 'memcached' => [ 57 | 'driver' => 'memcached', 58 | 'persistent_id' => env('MEMCACHED_PERSISTENT_ID'), 59 | 'sasl' => [ 60 | env('MEMCACHED_USERNAME'), 61 | env('MEMCACHED_PASSWORD'), 62 | ], 63 | 'options' => [ 64 | // Memcached::OPT_CONNECT_TIMEOUT => 2000, 65 | ], 66 | 'servers' => [ 67 | [ 68 | 'host' => env('MEMCACHED_HOST', '127.0.0.1'), 69 | 'port' => env('MEMCACHED_PORT', 11211), 70 | 'weight' => 100, 71 | ], 72 | ], 73 | ], 74 | 75 | 'redis' => [ 76 | 'driver' => 'redis', 77 | 'connection' => 'cache', 78 | ], 79 | 80 | 'dynamodb' => [ 81 | 'driver' => 'dynamodb', 82 | 'key' => env('AWS_ACCESS_KEY_ID'), 83 | 'secret' => env('AWS_SECRET_ACCESS_KEY'), 84 | 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'), 85 | 'table' => env('DYNAMODB_CACHE_TABLE', 'cache'), 86 | 'endpoint' => env('DYNAMODB_ENDPOINT'), 87 | ], 88 | 89 | ], 90 | 91 | /* 92 | |-------------------------------------------------------------------------- 93 | | Cache Key Prefix 94 | |-------------------------------------------------------------------------- 95 | | 96 | | When utilizing a RAM based store such as APC or Memcached, there might 97 | | be other applications utilizing the same cache. So, we'll specify a 98 | | value to get prefixed to all our keys so we can avoid collisions. 99 | | 100 | */ 101 | 102 | 'prefix' => env('CACHE_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_cache'), 103 | 104 | ]; 105 | -------------------------------------------------------------------------------- /backend/resources/views/profile/update-profile-information-form.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | {{ __('Profile Information') }} 4 | 5 | 6 | 7 | {{ __('Update your account\'s profile information and email address.') }} 8 | 9 | 10 | 11 | 12 | @if (Laravel\Jetstream\Jetstream::managesProfilePhotos()) 13 |
14 | 15 | 26 | 27 | 28 | 29 | 30 |
31 | {{ $this->user->name }} 32 |
33 | 34 | 35 |
36 | 38 | 39 |
40 | 41 | 42 | {{ __('Select A New Photo') }} 43 | 44 | 45 | @if ($this->user->profile_photo_path) 46 | 47 | {{ __('Remove Photo') }} 48 | 49 | @endif 50 | 51 | 52 |
53 | @endif 54 | 55 | 56 |
57 | 58 | 59 | 60 |
61 | 62 | 63 |
64 | 65 | 66 | 67 |
68 |
69 | 70 | 71 | 72 | {{ __('Saved.') }} 73 | 74 | 75 | 76 | {{ __('Save') }} 77 | 78 | 79 |
80 | -------------------------------------------------------------------------------- /frontend/pages/admin/courses/new.vue: -------------------------------------------------------------------------------- 1 | 54 | 96 | 108 | -------------------------------------------------------------------------------- /backend/config/mail.php: -------------------------------------------------------------------------------- 1 | env('MAIL_MAILER', 'smtp'), 17 | 18 | /* 19 | |-------------------------------------------------------------------------- 20 | | Mailer Configurations 21 | |-------------------------------------------------------------------------- 22 | | 23 | | Here you may configure all of the mailers used by your application plus 24 | | their respective settings. Several examples have been configured for 25 | | you and you are free to add your own as your application requires. 26 | | 27 | | Laravel supports a variety of mail "transport" drivers to be used while 28 | | sending an e-mail. You will specify which one you are using for your 29 | | mailers below. You are free to add additional mailers as required. 30 | | 31 | | Supported: "smtp", "sendmail", "mailgun", "ses", 32 | | "postmark", "log", "array" 33 | | 34 | */ 35 | 36 | 'mailers' => [ 37 | 'smtp' => [ 38 | 'transport' => 'smtp', 39 | 'host' => env('MAIL_HOST', 'smtp.mailgun.org'), 40 | 'port' => env('MAIL_PORT', 587), 41 | 'encryption' => env('MAIL_ENCRYPTION', 'tls'), 42 | 'username' => env('MAIL_USERNAME'), 43 | 'password' => env('MAIL_PASSWORD'), 44 | 'timeout' => null, 45 | ], 46 | 47 | 'ses' => [ 48 | 'transport' => 'ses', 49 | ], 50 | 51 | 'mailgun' => [ 52 | 'transport' => 'mailgun', 53 | ], 54 | 55 | 'postmark' => [ 56 | 'transport' => 'postmark', 57 | ], 58 | 59 | 'sendmail' => [ 60 | 'transport' => 'sendmail', 61 | 'path' => '/usr/sbin/sendmail -bs', 62 | ], 63 | 64 | 'log' => [ 65 | 'transport' => 'log', 66 | 'channel' => env('MAIL_LOG_CHANNEL'), 67 | ], 68 | 69 | 'array' => [ 70 | 'transport' => 'array', 71 | ], 72 | ], 73 | 74 | /* 75 | |-------------------------------------------------------------------------- 76 | | Global "From" Address 77 | |-------------------------------------------------------------------------- 78 | | 79 | | You may wish for all e-mails sent by your application to be sent from 80 | | the same address. Here, you may specify a name and address that is 81 | | used globally for all e-mails that are sent by your application. 82 | | 83 | */ 84 | 85 | 'from' => [ 86 | 'address' => env('MAIL_FROM_ADDRESS', 'hello@example.com'), 87 | 'name' => env('MAIL_FROM_NAME', 'Example'), 88 | ], 89 | 90 | /* 91 | |-------------------------------------------------------------------------- 92 | | Markdown Mail Settings 93 | |-------------------------------------------------------------------------- 94 | | 95 | | If you are using Markdown based email rendering, you may configure your 96 | | theme and component paths here, allowing you to customize the design 97 | | of the emails. Or, you may simply stick with the Laravel defaults! 98 | | 99 | */ 100 | 101 | 'markdown' => [ 102 | 'theme' => 'default', 103 | 104 | 'paths' => [ 105 | resource_path('views/vendor/mail'), 106 | ], 107 | ], 108 | 109 | ]; 110 | -------------------------------------------------------------------------------- /backend/resources/views/profile/two-factor-authentication-form.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | {{ __('Two Factor Authentication') }} 4 | 5 | 6 | 7 | {{ __('Add additional security to your account using two factor authentication.') }} 8 | 9 | 10 | 11 |

12 | @if ($this->enabled) 13 | {{ __('You have enabled two factor authentication.') }} 14 | @else 15 | {{ __('You have not enabled two factor authentication.') }} 16 | @endif 17 |

18 | 19 |
20 |

21 | {{ __('When two factor authentication is enabled, you will be prompted for a secure, random token during authentication. You may retrieve this token from your phone\'s Google Authenticator application.') }} 22 |

23 |
24 | 25 | @if ($this->enabled) 26 | @if ($showingQrCode) 27 |
28 |

29 | {{ __('Two factor authentication is now enabled. Scan the following QR code using your phone\'s authenticator application.') }} 30 |

31 |
32 | 33 |
34 | {!! $this->user->twoFactorQrCodeSvg() !!} 35 |
36 | @endif 37 | 38 | @if ($showingRecoveryCodes) 39 |
40 |

41 | {{ __('Store these recovery codes in a secure password manager. They can be used to recover access to your account if your two factor authentication device is lost.') }} 42 |

43 |
44 | 45 |
46 | @foreach (json_decode(decrypt($this->user->two_factor_recovery_codes), true) as $code) 47 |
{{ $code }}
48 | @endforeach 49 |
50 | @endif 51 | @endif 52 | 53 |
54 | @if (! $this->enabled) 55 | 56 | 57 | {{ __('Enable') }} 58 | 59 | 60 | @else 61 | @if ($showingRecoveryCodes) 62 | 63 | 64 | {{ __('Regenerate Recovery Codes') }} 65 | 66 | 67 | @else 68 | 69 | 70 | {{ __('Show Recovery Codes') }} 71 | 72 | 73 | @endif 74 | 75 | 76 | 77 | {{ __('Disable') }} 78 | 79 | 80 | @endif 81 |
82 |
83 |
84 | -------------------------------------------------------------------------------- /backend/config/auth.php: -------------------------------------------------------------------------------- 1 | [ 17 | 'guard' => 'web', 18 | 'passwords' => 'users', 19 | ], 20 | 21 | /* 22 | |-------------------------------------------------------------------------- 23 | | Authentication Guards 24 | |-------------------------------------------------------------------------- 25 | | 26 | | Next, you may define every authentication guard for your application. 27 | | Of course, a great default configuration has been defined for you 28 | | here which uses session storage and the Eloquent user provider. 29 | | 30 | | All authentication drivers have a user provider. This defines how the 31 | | users are actually retrieved out of your database or other storage 32 | | mechanisms used by this application to persist your user's data. 33 | | 34 | | Supported: "session", "token" 35 | | 36 | */ 37 | 38 | 'guards' => [ 39 | 'web' => [ 40 | 'driver' => 'session', 41 | 'provider' => 'users', 42 | ], 43 | 44 | 'api' => [ 45 | 'driver' => 'token', 46 | 'provider' => 'users', 47 | 'hash' => false, 48 | ], 49 | ], 50 | 51 | /* 52 | |-------------------------------------------------------------------------- 53 | | User Providers 54 | |-------------------------------------------------------------------------- 55 | | 56 | | All authentication drivers have a user provider. This defines how the 57 | | users are actually retrieved out of your database or other storage 58 | | mechanisms used by this application to persist your user's data. 59 | | 60 | | If you have multiple user tables or models you may configure multiple 61 | | sources which represent each model / table. These sources may then 62 | | be assigned to any extra authentication guards you have defined. 63 | | 64 | | Supported: "database", "eloquent" 65 | | 66 | */ 67 | 68 | 'providers' => [ 69 | 'users' => [ 70 | 'driver' => 'eloquent', 71 | 'model' => App\Models\User::class, 72 | ], 73 | 74 | // 'users' => [ 75 | // 'driver' => 'database', 76 | // 'table' => 'users', 77 | // ], 78 | ], 79 | 80 | /* 81 | |-------------------------------------------------------------------------- 82 | | Resetting Passwords 83 | |-------------------------------------------------------------------------- 84 | | 85 | | You may specify multiple password reset configurations if you have more 86 | | than one user table or model in the application and you want to have 87 | | separate password reset settings based on the specific user types. 88 | | 89 | | The expire time is the number of minutes that the reset token should be 90 | | considered valid. This security feature keeps tokens short-lived so 91 | | they have less time to be guessed. You may change this as needed. 92 | | 93 | */ 94 | 95 | 'passwords' => [ 96 | 'users' => [ 97 | 'provider' => 'users', 98 | 'table' => 'password_resets', 99 | 'expire' => 60, 100 | 'throttle' => 60, 101 | ], 102 | ], 103 | 104 | /* 105 | |-------------------------------------------------------------------------- 106 | | Password Confirmation Timeout 107 | |-------------------------------------------------------------------------- 108 | | 109 | | Here you may define the amount of seconds before a password confirmation 110 | | times out and the user is prompted to re-enter their password via the 111 | | confirmation screen. By default, the timeout lasts for three hours. 112 | | 113 | */ 114 | 115 | 'password_timeout' => 10800, 116 | 117 | ]; 118 | -------------------------------------------------------------------------------- /backend/README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | Build Status 5 | Total Downloads 6 | Latest Stable Version 7 | License 8 |

9 | 10 | ## About Laravel 11 | 12 | Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experience to be truly fulfilling. Laravel takes the pain out of development by easing common tasks used in many web projects, such as: 13 | 14 | - [Simple, fast routing engine](https://laravel.com/docs/routing). 15 | - [Powerful dependency injection container](https://laravel.com/docs/container). 16 | - Multiple back-ends for [session](https://laravel.com/docs/session) and [cache](https://laravel.com/docs/cache) storage. 17 | - Expressive, intuitive [database ORM](https://laravel.com/docs/eloquent). 18 | - Database agnostic [schema migrations](https://laravel.com/docs/migrations). 19 | - [Robust background job processing](https://laravel.com/docs/queues). 20 | - [Real-time event broadcasting](https://laravel.com/docs/broadcasting). 21 | 22 | Laravel is accessible, powerful, and provides tools required for large, robust applications. 23 | 24 | ## Learning Laravel 25 | 26 | Laravel has the most extensive and thorough [documentation](https://laravel.com/docs) and video tutorial library of all modern web application frameworks, making it a breeze to get started with the framework. 27 | 28 | If you don't feel like reading, [Laracasts](https://laracasts.com) can help. Laracasts contains over 1500 video tutorials on a range of topics including Laravel, modern PHP, unit testing, and JavaScript. Boost your skills by digging into our comprehensive video library. 29 | 30 | ## Laravel Sponsors 31 | 32 | We would like to extend our thanks to the following sponsors for funding Laravel development. If you are interested in becoming a sponsor, please visit the Laravel [Patreon page](https://patreon.com/taylorotwell). 33 | 34 | - **[Vehikl](https://vehikl.com/)** 35 | - **[Tighten Co.](https://tighten.co)** 36 | - **[Kirschbaum Development Group](https://kirschbaumdevelopment.com)** 37 | - **[64 Robots](https://64robots.com)** 38 | - **[Cubet Techno Labs](https://cubettech.com)** 39 | - **[Cyber-Duck](https://cyber-duck.co.uk)** 40 | - **[British Software Development](https://www.britishsoftware.co)** 41 | - **[Webdock, Fast VPS Hosting](https://www.webdock.io/en)** 42 | - **[DevSquad](https://devsquad.com)** 43 | - [UserInsights](https://userinsights.com) 44 | - [Fragrantica](https://www.fragrantica.com) 45 | - [SOFTonSOFA](https://softonsofa.com/) 46 | - [User10](https://user10.com) 47 | - [Soumettre.fr](https://soumettre.fr/) 48 | - [CodeBrisk](https://codebrisk.com) 49 | - [1Forge](https://1forge.com) 50 | - [TECPRESSO](https://tecpresso.co.jp/) 51 | - [Runtime Converter](http://runtimeconverter.com/) 52 | - [WebL'Agence](https://weblagence.com/) 53 | - [Invoice Ninja](https://www.invoiceninja.com) 54 | - [iMi digital](https://www.imi-digital.de/) 55 | - [Earthlink](https://www.earthlink.ro/) 56 | - [Steadfast Collective](https://steadfastcollective.com/) 57 | - [We Are The Robots Inc.](https://watr.mx/) 58 | - [Understand.io](https://www.understand.io/) 59 | - [Abdel Elrafa](https://abdelelrafa.com) 60 | - [Hyper Host](https://hyper.host) 61 | - [Appoly](https://www.appoly.co.uk) 62 | - [OP.GG](https://op.gg) 63 | - [云软科技](http://www.yunruan.ltd/) 64 | 65 | ## Contributing 66 | 67 | Thank you for considering contributing to the Laravel framework! The contribution guide can be found in the [Laravel documentation](https://laravel.com/docs/contributions). 68 | 69 | ## Code of Conduct 70 | 71 | In order to ensure that the Laravel community is welcoming to all, please review and abide by the [Code of Conduct](https://laravel.com/docs/contributions#code-of-conduct). 72 | 73 | ## Security Vulnerabilities 74 | 75 | If you discover a security vulnerability within Laravel, please send an e-mail to Taylor Otwell via [taylor@laravel.com](mailto:taylor@laravel.com). All security vulnerabilities will be promptly addressed. 76 | 77 | ## License 78 | 79 | The Laravel framework is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT). 80 | -------------------------------------------------------------------------------- /backend/resources/views/profile/logout-other-browser-sessions-form.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | {{ __('Browser Sessions') }} 4 | 5 | 6 | 7 | {{ __('Manage and logout your active sessions on other browsers and devices.') }} 8 | 9 | 10 | 11 |
12 | {{ __('If necessary, you may logout of all of your other browser sessions across all of your devices. Some of your recent sessions are listed below; however, this list may not be exhaustive. If you feel your account has been compromised, you should also update your password.') }} 13 |
14 | 15 | @if (count($this->sessions) > 0) 16 |
17 | 18 | @foreach ($this->sessions as $session) 19 |
20 |
21 | @if ($session->agent->isDesktop()) 22 | 23 | 24 | 25 | @else 26 | 27 | 28 | 29 | @endif 30 |
31 | 32 |
33 |
34 | {{ $session->agent->platform() }} - {{ $session->agent->browser() }} 35 |
36 | 37 |
38 |
39 | {{ $session->ip_address }}, 40 | 41 | @if ($session->is_current_device) 42 | {{ __('This device') }} 43 | @else 44 | {{ __('Last active') }} {{ $session->last_active }} 45 | @endif 46 |
47 |
48 |
49 |
50 | @endforeach 51 |
52 | @endif 53 | 54 |
55 | 56 | {{ __('Logout Other Browser Sessions') }} 57 | 58 | 59 | 60 | {{ __('Done.') }} 61 | 62 |
63 | 64 | 65 | 66 | 67 | {{ __('Logout Other Browser Sessions') }} 68 | 69 | 70 | 71 | {{ __('Please enter your password to confirm you would like to logout of your other browser sessions across all of your devices.') }} 72 | 73 |
74 | 78 | 79 | 80 |
81 |
82 | 83 | 84 | 85 | {{ __('Nevermind') }} 86 | 87 | 88 | 89 | {{ __('Logout Other Browser Sessions') }} 90 | 91 | 92 |
93 |
94 |
95 | --------------------------------------------------------------------------------