├── .editorconfig
├── .example.env
├── .gitattributes
├── .gitignore
├── .styleci.yml
├── .vscode
└── settings.json
├── LICENSE
├── Procfile
├── README.md
├── app
├── Category.php
├── Console
│ ├── Commands
│ │ ├── EcommerceInstall.php
│ │ └── HerokuSetup.php
│ └── Kernel.php
├── CountryVisit.php
├── Coupon.php
├── Exceptions
│ └── Handler.php
├── Http
│ ├── Controllers
│ │ ├── Auth
│ │ │ ├── ConfirmPasswordController.php
│ │ │ ├── ForgotPasswordController.php
│ │ │ ├── LoginController.php
│ │ │ ├── RegisterController.php
│ │ │ ├── ResetPasswordController.php
│ │ │ └── VerificationController.php
│ │ ├── CartController.php
│ │ ├── CheckoutController.php
│ │ ├── Controller.php
│ │ ├── CouponsController.php
│ │ ├── HomeController.php
│ │ ├── ShopController.php
│ │ ├── VisitsController.php
│ │ ├── Voyager
│ │ │ └── OrdersController.php
│ │ └── WelcomePageController.php
│ ├── Kernel.php
│ ├── Middleware
│ │ ├── AdminMiddleware.php
│ │ ├── Authenticate.php
│ │ ├── CheckForMaintenanceMode.php
│ │ ├── EncryptCookies.php
│ │ ├── RedirectIfAuthenticated.php
│ │ ├── TrimStrings.php
│ │ ├── TrustProxies.php
│ │ ├── VerifyCsrfToken.php
│ │ └── VisitsMiddleware.php
│ └── Requests
│ │ └── CheckoutRequest.php
├── Mail
│ └── OrderPlaced.php
├── Order.php
├── OrderProduct.php
├── Product.php
├── ProductTag.php
├── Providers
│ ├── AppServiceProvider.php
│ ├── AuthServiceProvider.php
│ ├── BroadcastServiceProvider.php
│ ├── EventServiceProvider.php
│ └── RouteServiceProvider.php
├── Tag.php
├── User.php
└── library
│ └── helper.php
├── artisan
├── bootstrap
├── app.php
└── cache
│ └── .gitignore
├── composer.json
├── composer.lock
├── config
├── app.php
├── auth.php
├── broadcasting.php
├── cache.php
├── cart.php
├── database.php
├── filesystems.php
├── geoip.php
├── hashing.php
├── hooks.php
├── image.php
├── logging.php
├── mail.php
├── queue.php
├── scout.php
├── services.php
├── session.php
├── view.php
├── voyager-hooks.php
└── voyager.php
├── database
├── .gitignore
├── factories
│ └── UserFactory.php
├── migrations
│ ├── 2014_10_12_000000_create_users_table.php
│ ├── 2014_10_12_100000_create_password_resets_table.php
│ ├── 2019_08_19_000000_create_failed_jobs_table.php
│ ├── 2019_10_16_185424_create_products_table.php
│ ├── 2019_10_17_195112_create_categories_table.php
│ ├── 2019_10_17_195227_add_category_id_to_products_table.php
│ ├── 2019_10_18_002421_create_coupons_table.php
│ ├── 2019_10_19_145706_add_images_column_to_products.php
│ ├── 2019_10_20_114921_create_tags_table.php
│ ├── 2019_10_20_115306_create_products_tags_table.php
│ ├── 2019_10_22_185425_create_orders_table.php
│ ├── 2019_10_22_190613_create_order_product_table.php
│ ├── 2019_11_09_002942_add_quantity_to_products_table.php
│ └── 2020_06_27_012504_create_visits_table.php
└── seeds
│ ├── CategoriesTableSeeder.php
│ ├── CategoryTableSeeder.php
│ ├── CouponsTableSeeder.php
│ ├── DataRowsTableSeeder.php
│ ├── DataRowsTableSeederCustom.php
│ ├── DataTypesTableSeeder.php
│ ├── DataTypesTableSeederCustom.php
│ ├── DatabaseSeeder.php
│ ├── MenuItemsTableSeeder.php
│ ├── MenuItemsTableSeederCustom.php
│ ├── MenusTableSeeder.php
│ ├── MenusTableSeederCustom.php
│ ├── OrderProductTableSeeder.php
│ ├── OrdersTableSeeder.php
│ ├── PagesTableSeeder.php
│ ├── PermissionRoleTableSeeder.php
│ ├── PermissionRoleTableSeederCustom.php
│ ├── PermissionsTableSeeder.php
│ ├── PermissionsTableSeederCustom.php
│ ├── PostsTableSeeder.php
│ ├── ProductTagSeeder.php
│ ├── ProductsTableSeeder.php
│ ├── RolesTableSeeder.php
│ ├── SettingsTableSeeder.php
│ ├── SettingsTableSeederCustom.php
│ ├── TagsTableSeeder.php
│ ├── TranslationsTableSeeder.php
│ ├── UsersTableSeeder.php
│ ├── VoyagerDatabaseSeeder.php
│ ├── VoyagerDatabaseSeederCustom.php
│ └── VoyagerDummyDatabaseSeeder.php
├── hooks
└── hooks.json
├── package-lock.json
├── package.json
├── phpunit.xml
├── public
├── .htaccess
├── css
│ └── app.css
├── favicon.ico
├── fonts
│ ├── themify.eot
│ ├── themify.svg
│ ├── themify.ttf
│ ├── themify.woff
│ └── vendor
│ │ └── font-awesome
│ │ ├── fontawesome-webfont.eot
│ │ ├── fontawesome-webfont.svg
│ │ ├── fontawesome-webfont.ttf
│ │ ├── fontawesome-webfont.woff
│ │ └── fontawesome-webfont.woff2
├── images
│ ├── cover.jpg
│ ├── not-found.jpg
│ ├── products
│ │ └── dummy
│ │ │ ├── image0.jpg
│ │ │ ├── image1.jpg
│ │ │ ├── image2.jpg
│ │ │ ├── image3.jpg
│ │ │ ├── image4.jpg
│ │ │ └── image5.jpg
│ └── users
│ │ └── default.png
├── index.php
├── js
│ └── app.js
├── mix-manifest.json
├── robots.txt
└── storage
├── resources
├── js
│ ├── app.js
│ ├── bootstrap.js
│ └── main.js
├── lang
│ └── en
│ │ ├── auth.php
│ │ ├── pagination.php
│ │ ├── passwords.php
│ │ └── validation.php
├── sass
│ ├── _cart.scss
│ ├── _checkout.scss
│ ├── _main.scss
│ ├── _product.scss
│ ├── _shop.scss
│ ├── _variables.scss
│ ├── _welcome.scss
│ ├── aos.css
│ ├── app.scss
│ └── cover.jpg
└── views
│ ├── admin
│ └── visits.blade.php
│ ├── auth
│ ├── login.blade.php
│ ├── passwords
│ │ ├── email.blade.php
│ │ └── reset.blade.php
│ ├── register.blade.php
│ └── verify.blade.php
│ ├── cart.blade.php
│ ├── checkout.blade.php
│ ├── emails
│ └── orders
│ │ └── placed.blade.php
│ ├── errors
│ ├── 401.blade.php
│ ├── 403.blade.php
│ ├── 404.blade.php
│ ├── 419.blade.php
│ ├── 429.blade.php
│ ├── 500.blade.php
│ ├── 503.blade.php
│ ├── illustrated-layout.blade.php
│ ├── layout.blade.php
│ └── minimal.blade.php
│ ├── home.blade.php
│ ├── layouts
│ └── app.blade.php
│ ├── partials
│ ├── errors.blade.php
│ ├── footer.blade.php
│ ├── head.blade.php
│ ├── menu
│ │ └── main.blade.php
│ ├── might-like.blade.php
│ ├── nav.blade.php
│ └── session.blade.php
│ ├── product.blade.php
│ ├── search.blade.php
│ ├── shop.blade.php
│ ├── vendor
│ └── voyager
│ │ └── orders
│ │ ├── browse.blade.php
│ │ └── read.blade.php
│ └── welcome.blade.php
├── routes
├── api.php
├── channels.php
├── console.php
└── web.php
├── server.php
├── storage
├── app
│ ├── .gitignore
│ └── public
│ │ ├── products
│ │ ├── September2020
│ │ │ ├── 7bmQiRD5DOS6QZTrprlb.jpg
│ │ │ ├── DKCbwzXCrbgRjlUJjlko.jpg
│ │ │ ├── FHyZzRWZ0Ze0CAqiURkx.jpg
│ │ │ ├── gMuKbTUCz2AW9OS2Gqv1.jpg
│ │ │ ├── nx65t4W6tw17XFoPnfrb.jpg
│ │ │ └── xWLnSwcwkH4r7yhDn00F.jpg
│ │ └── dummy
│ │ │ ├── image0.jpg
│ │ │ ├── image1.jpg
│ │ │ ├── image2.jpg
│ │ │ ├── image3.jpg
│ │ │ ├── image4.jpg
│ │ │ └── image5.jpg
│ │ └── users
│ │ └── default.png
├── debugbar
│ └── .gitignore
├── framework
│ ├── .gitignore
│ ├── cache
│ │ ├── .gitignore
│ │ └── data
│ │ │ └── .gitignore
│ ├── sessions
│ │ └── .gitignore
│ ├── testing
│ │ └── .gitignore
│ └── views
│ │ └── .gitignore
└── logs
│ └── .gitignore
├── tests
├── CreatesApplication.php
├── Feature
│ └── ExampleTest.php
├── TestCase.php
└── Unit
│ └── ExampleTest.php
└── webpack.mix.js
/.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 |
--------------------------------------------------------------------------------
/.example.env:
--------------------------------------------------------------------------------
1 | APP_NAME=Ecommerce
2 | APP_ENV=local
3 | APP_KEY=
4 | APP_DEBUG=true
5 | APP_URL=http://localhost:8000
6 |
7 | LOG_CHANNEL=stack
8 |
9 | DB_CONNECTION=mysql
10 | DB_HOST=127.0.0.1
11 | DB_PORT=3306
12 | DB_DATABASE=
13 | DB_USERNAME=
14 | DB_PASSWORD=
15 |
16 | BROADCAST_DRIVER=log
17 | CACHE_DRIVER=file
18 | QUEUE_CONNECTION=sync
19 | SESSION_DRIVER=file
20 | SESSION_LIFETIME=120
21 |
22 | REDIS_HOST=127.0.0.1
23 | REDIS_PASSWORD=null
24 | REDIS_PORT=6379
25 |
26 | MAIL_DRIVER=smtp
27 | MAIL_HOST=smtp.mailtrap.io
28 | MAIL_PORT=2525
29 | MAIL_USERNAME=
30 | MAIL_PASSWORD=
31 | MAIL_ENCRYPTION=null
32 |
33 | AWS_ACCESS_KEY_ID=
34 | AWS_SECRET_ACCESS_KEY=
35 | AWS_DEFAULT_REGION=us-east-1
36 | AWS_BUCKET=
37 |
38 | PUSHER_APP_ID=
39 | PUSHER_APP_KEY=
40 | PUSHER_APP_SECRET=
41 | PUSHER_APP_CLUSTER=mt1
42 |
43 | MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
44 | MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
45 |
46 | VOYAGER_ADMIN_PASSWORD=password
47 |
48 | STRIPE_KEY=
49 | STRIPE_SECRET=
50 |
51 | MAIL_FROM_ADDRESS=
52 | MAIL_FROM_NAME=
53 |
54 | ALGOLIA_APP_ID=
55 | ALGOLIA_SECRET=
56 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto
2 | *.css linguist-vendored
3 | *.scss linguist-vendored
4 | *.js linguist-vendored
5 | CHANGELOG.md export-ignore
6 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules
2 | /public/hot
3 | /storage/*.key
4 | /vendor
5 | .env
6 | .env.backup
7 | .phpunit.result.cache
8 | Homestead.json
9 | Homestead.yaml
10 | npm-debug.log
11 | yarn-error.log
12 |
--------------------------------------------------------------------------------
/.styleci.yml:
--------------------------------------------------------------------------------
1 | php:
2 | preset: laravel
3 | enabled:
4 | - alpha_ordered_imports
5 | disabled:
6 | - length_ordered_imports
7 | - unused_use
8 | finder:
9 | not-name:
10 | - index.php
11 | - server.php
12 | js:
13 | finder:
14 | not-name:
15 | - webpack.mix.js
16 | css: true
17 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "cSpell.words": [
3 | "Aloglia"
4 | ],
5 | "cSpell.ignoreWords": [
6 | "aloglia"
7 | ]
8 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Mohammed Omer
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Procfile:
--------------------------------------------------------------------------------
1 | web: vendor/bin/heroku-php-apache2 public/
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ecommerce-laravel-fullstack
2 |
3 | # Link : http://vampireecommerce.herokuapp.com
4 |
5 | This repo is based on the [youtube series](https://www.youtube.com/playlist?list=PLEhEHUEU3x5oPTli631ZX9cxl6cU_sDaR) by [@drehimself](https://github.com/drehimself)
6 |
7 | ## Features
8 |
9 | - Fully functional E-commerce website front-end and back-end built from scratch.
10 | - Using laravel voyager as an admin panel for the site.
11 | - javascript, jquery, bootstrap and css for the front-end.
12 | - Intelligent searching mechanism for products.
13 | - Awesome Cart package that uses session.
14 | - An artisan command to seed the database with all neccessary dummy data, even for voyager tables (php artisan ecommerce:install).
15 | - Different user roles and privileges.
16 | - Categories, tags and price filtering for easier search for products.
17 | - And much more features.
18 |
19 | ---
20 |
21 | ## Installation Guide
22 |
23 | 1. clone this repo to your local machine: `git clone https://github.com/mhmdomer/ecommerce-laravel.git && cd ecommerce-laravel`
24 | 1. copy `.example.env` to `.env` file: `cp .example.env .env`
25 | 1. create a new database and add the database credentials to your `.env` file
26 | 1. run `composer install`
27 | 1. run `npm install && npm run dev`
28 | 1. run `php artisan key:generate`
29 | 1. run `php artisan ecommerce:install`
30 | 1. run `php artisan serve` and then visit `http://127.0.0.1:8000/`
31 | 1. credentials to access admin panel (email: `admin@admin.com`, password: `password`)
32 | 1. after you login as admin, you can access the admin page from `http://127.0.0.1:8000/admin`
33 | - Home Page
34 |
35 | 
36 |
37 | - Shopping Page
38 |
39 | 
40 |
41 | - Cart Page
42 |
43 | 
44 |
45 | - Checkout page
46 |
47 | 
48 |
49 | - Admin Orders BREAD
50 |
51 | 
52 |
53 | - Admin Products BREAD
54 |
55 | 
56 |
--------------------------------------------------------------------------------
/app/Category.php:
--------------------------------------------------------------------------------
1 | hasMany('App\Product');
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/app/Console/Commands/EcommerceInstall.php:
--------------------------------------------------------------------------------
1 | option('force')) {
42 | $this->proceed();
43 | } else if($this->confirm('This will delete all your current data and database and install the default dummy data Are You Sure?')) {
44 | $this->proceed();
45 | }
46 | }
47 |
48 | protected function proceed() {
49 | $linkFile = public_path('storage');
50 | if(file_exists($linkFile)) {
51 | if(is_link($linkFile)){
52 | unlink($linkFile);
53 | }
54 | }
55 | if(!file_exists(storage_path('app/public'))) {
56 | mkdir(storage_path('app/public/'));
57 | }
58 | $this->call('storage:link');
59 | $copySuccess1 = File::copyDirectory(public_path('/images/products/dummy'), public_path('storage/products/dummy'));
60 | $copySuccess2 = File::copyDirectory(public_path('/images/users'), public_path('storage/users'));
61 | if($copySuccess1 && $copySuccess2) {
62 | $this->info('Images successfully moved to storage folder');
63 | }
64 | $this->call('migrate:fresh', [
65 | '--seed' => true
66 | ]);
67 | $this->info('cleared the database and seeded basic tables successfully');
68 | $this->call('db:seed', [
69 | '--class' => 'VoyagerDatabaseSeeder'
70 | ]);
71 | $this->call('db:seed', [
72 | '--class' => 'VoyagerDummyDatabaseSeeder'
73 | ]);
74 | $this->call('db:seed', [
75 | '--class' => 'VoyagerDatabaseSeederCustom'
76 | ]);
77 | $this->call('db:seed', [
78 | '--class' => 'OrdersTableSeeder'
79 | ]);
80 | $this->call('db:seed', [
81 | '--class' => 'OrderProductTableSeeder'
82 | ]);
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/app/Console/Commands/HerokuSetup.php:
--------------------------------------------------------------------------------
1 | option('force')) {
42 | $this->proceed();
43 | } else if($this->confirm('This will delete all your current data and database and install the default dummy data Are You Sure?')) {
44 | $this->proceed();
45 | }
46 | }
47 |
48 | protected function proceed() {
49 | File::deleteDirectory(public_path('storage/products/dummy'));
50 | File::deleteDirectory(public_path('storage/users'));
51 | $this->info(file_exists(public_path('/images/products')));
52 | $this->callSilent('storage:link');
53 | $copySuccess1 = File::copyDirectory(public_path('/images/products'), public_path('storage/products/dummy'));
54 | $copySuccess2 = File::copyDirectory(public_path('/images/users'), public_path('storage/users'));
55 | if($copySuccess1 && $copySuccess2) {
56 | $this->info('Images successfully moved to storage folder');
57 | }
58 | // $this->call('migrate:refresh', [
59 | // '--seed' => true
60 | // ]);
61 | // $this->info('cleared the database and seeded basic tables successfully');
62 | // $this->call('db:seed', [
63 | // '--class' => 'VoyagerDatabaseSeeder'
64 | // ]);
65 | // $this->call('db:seed', [
66 | // '--class' => 'VoyagerDummyDatabaseSeeder'
67 | // ]);
68 | // $this->call('db:seed', [
69 | // '--class' => 'DataTypesTableSeederCustom'
70 | // ]);
71 | // $this->call('db:seed', [
72 | // '--class' => 'DataRowsTableSeederCustom'
73 | // ]);
74 | // $this->call('db:seed', [
75 | // '--class' => 'MenusTableSeederCustom'
76 | // ]);
77 | // $this->call('db:seed', [
78 | // '--class' => 'MenuItemsTableSeederCustom'
79 | // ]);
80 | // $this->call('db:seed', [
81 | // '--class' => 'PermissionsTableSeederCustom'
82 | // ]);
83 | // $this->call('db:seed', [
84 | // '--class' => 'PermissionRoleTableSeederCustom'
85 | // ]);
86 | // $this->call('db:seed', [
87 | // '--class' => 'SettingsTableSeederCustom'
88 | // ]);
89 | // $this->call('db:seed', [
90 | // '--class' => 'OrdersTableSeeder'
91 | // ]);
92 | // $this->call('db:seed', [
93 | // '--class' => 'OrderProductTableSeeder'
94 | // ]);
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/app/Console/Kernel.php:
--------------------------------------------------------------------------------
1 | command('inspire')
28 | // ->hourly();
29 | }
30 |
31 | /**
32 | * Register the commands for the application.
33 | *
34 | * @return void
35 | */
36 | protected function commands()
37 | {
38 | $this->load(__DIR__.'/Commands');
39 |
40 | require base_path('routes/console.php');
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/app/CountryVisit.php:
--------------------------------------------------------------------------------
1 | increment('visits');
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/app/Coupon.php:
--------------------------------------------------------------------------------
1 | first();
12 | }
13 |
14 | public function discount($total) {
15 | if($this->type == 'fixed') {
16 | return $this->value;
17 | } else if($this->type == 'percent') {
18 | return ($this->percent_off / 100) * $total;
19 | } else {
20 | return 0;
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/app/Exceptions/Handler.php:
--------------------------------------------------------------------------------
1 | middleware('auth');
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Auth/ForgotPasswordController.php:
--------------------------------------------------------------------------------
1 | middleware('guest')->except('logout');
40 | }
41 |
42 | /**
43 | * Redirect the user to the GitHub authentication page.
44 | *
45 | * @return \Illuminate\Http\Response
46 | */
47 | public function redirectToProvider()
48 | {
49 | return Socialite::driver(request()->provider)->redirect();
50 | }
51 |
52 | /**
53 | * Obtain the user information from GitHub.
54 | *
55 | * @return \Illuminate\Http\Response
56 | */
57 | public function handleProviderCallback()
58 | {
59 | $provider = request()->provider;
60 | $providerUser = Socialite::driver($provider)->user();
61 | if($providerUser->getEmail() == null) {
62 | $user = User::where($provider . '_id', $providerUser->getId())->first();
63 | } else {
64 | $user = User::where('email', $providerUser->getEmail())->first();
65 | }
66 | if($user && $user->$provider . '_id' == null) {
67 | $user->update([$provider . '_id' => $providerUser->getId()]);
68 | }
69 | if(!$user) {
70 | $user = User::create([
71 | 'email' => $providerUser->getEmail(),
72 | 'name' => $providerUser->getName(),
73 | $provider . '_id' => $providerUser->getId(),
74 | ]);
75 | }
76 |
77 | auth()->login($user, true);
78 |
79 | return redirect($this->redirectTo);
80 |
81 | // $user->token;
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Auth/RegisterController.php:
--------------------------------------------------------------------------------
1 | middleware('guest');
41 | }
42 |
43 | /**
44 | * Get a validator for an incoming registration request.
45 | *
46 | * @param array $data
47 | * @return \Illuminate\Contracts\Validation\Validator
48 | */
49 | protected function validator(array $data)
50 | {
51 | return Validator::make($data, [
52 | 'name' => ['required', 'string', 'max:255'],
53 | 'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
54 | 'password' => ['required', 'string', 'min:8', 'confirmed'],
55 | ]);
56 | }
57 |
58 | /**
59 | * Create a new user instance after a valid registration.
60 | *
61 | * @param array $data
62 | * @return \App\User
63 | */
64 | protected function create(array $data)
65 | {
66 | return User::create([
67 | 'name' => $data['name'],
68 | 'email' => $data['email'],
69 | 'password' => Hash::make($data['password']),
70 | ]);
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Auth/ResetPasswordController.php:
--------------------------------------------------------------------------------
1 | middleware('auth');
38 | $this->middleware('signed')->only('verify');
39 | $this->middleware('throttle:6,1')->only('verify', 'resend');
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/app/Http/Controllers/CartController.php:
--------------------------------------------------------------------------------
1 | get();
14 | return view('cart')->with('mightLike', $mightLike);
15 | }
16 |
17 | public function store() {
18 | session()->forget('coupon');
19 | $duplicates = Cart::instance('default')->search(function($cartItem, $rowId) {
20 | return $cartItem->id == request()->id;
21 | });
22 | $duplicatesLater = Cart::instance('saveForLater')->search(function($cartItem, $rowId) {
23 | return $cartItem->id == request()->id;
24 | });
25 | if($duplicates->isNotEmpty()) {
26 | session()->flash('success', 'Item is already in your cart');
27 | return redirect()->route('cart.index');
28 | } else if($duplicatesLater->isNotEmpty()) {
29 | Cart::instance('saveForLater')->remove($duplicatesLater->first()->rowId);
30 | }
31 | Cart::instance('default')->add(request()->id, request()->name, 1, request()->price)->associate('App\Product');
32 | session()->flash('success', 'product added to the cart');
33 | return redirect()->route('cart.index');
34 | }
35 |
36 | public function update($id) {
37 | session()->forget('coupon');
38 | if(request()->productQuantity >= request()->quantity) {
39 | Cart::instance('default')->update($id, request()->quantity);
40 | session()->flash('success', 'quantity updated successfully!');
41 | return response()->json(['success' => ''], 200);
42 | }
43 | session()->flash('error', 'not enough products');
44 | return response()->json(['error' => ''], 405);
45 | }
46 |
47 | public function destroy($id, $cart) {
48 | if($cart == 'default')
49 | Cart::instance('default')->remove($id);
50 | else if($cart = 'saveForLater')
51 | Cart::instance('saveForLater')->remove($id);
52 | session()->flash('success', 'item has been removed');
53 | return back();
54 | }
55 |
56 | public function saveLater($id) {
57 | session()->forget('coupon');
58 | $item = Cart::get($id);
59 | Cart::remove($id);
60 | $duplicates = Cart::instance('saveForLater')->search(function($cartItem, $rowId) use ($id) {
61 | return $rowId == $id;
62 | });
63 | if($duplicates->isNotEmpty()) {
64 | session()->flash('success', 'Item is already saved for later');
65 | return redirect()->route('cart.index');
66 | }
67 | Cart::instance('saveForLater')->add($item->id, $item->name, 1, $item->price)->associate('App\Product');
68 | session()->flash('success', 'Item has been saved for later');
69 | return redirect()->route('cart.index');
70 | }
71 |
72 | public function addToCart($id) {
73 | session()->forget('coupon');
74 | $item = Cart::instance('saveForLater')->get($id);
75 | Cart::instance('saveForLater')->remove($id);
76 | $exist = Cart::instance('default')->search(function($cartItem, $rowId) use($item) {
77 | return $cartItem->id == $item->id;
78 | });
79 | if($exist->isNotEmpty()) {
80 | session()->flash('success', 'Item is already in the cart');
81 | return redirect()->route('cart.index');
82 | }
83 | Cart::instance('default')->add($item->id, $item->name, 1, $item->price)->associate('App\Product');
84 | session()->flash('success', 'item added to the cart');
85 | return redirect()->route('cart.index');
86 | }
87 |
88 | }
89 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Controller.php:
--------------------------------------------------------------------------------
1 | validate($request, [
14 | 'coupon_code' => 'required'
15 | ]);
16 | $coupon = Coupon::where('code', $request->coupon_code)->first();
17 | if(!$coupon) return redirect()->route('checkout.index')->with('error', 'Invalid Coupon Code');
18 | session()->put('coupon', [
19 | 'code' => $coupon->code,
20 | 'discount' => $coupon->discount(Cart::instance('default')->subtotal())
21 | ]);
22 |
23 | return redirect()->route('checkout.index')->withSuccess('Coupon applied successfully!');
24 | }
25 |
26 |
27 | public function destroy()
28 | {
29 | session()->forget('coupon');
30 | return redirect()->route('checkout.index')->with('success', 'Coupon has been removed');
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/app/Http/Controllers/ShopController.php:
--------------------------------------------------------------------------------
1 | category) {
17 | $category = Category::where('slug', request()->category)->get()->first();
18 | $products = Product::where('category_id', $category->id);
19 | $categoryName = $category->name;
20 | } else if(request()->tag) {
21 | $tag = Tag::where('slug', request()->tag)->get()->first();
22 | $products = $tag->products();
23 | $tagName = $tag->name;
24 | } else {
25 | $products = Product::where('featured', true);
26 | $categoryName = 'Featured';
27 | }
28 | if(request()->sort == 'low_high') {
29 | $products = $products->orderBy('price')->paginate($pagination);
30 | } else if(request()->sort == 'high_low') {
31 | $products = $products->orderBy('price', 'desc')->paginate($pagination);
32 | } else {
33 | $products = $products->inRandomOrder()->paginate($pagination);
34 | }
35 | $categories = Category::all();
36 | $tags = Tag::all();
37 | return view('shop')->with([
38 | 'products' => $products,
39 | 'categories'=> $categories,
40 | 'tags'=> $tags,
41 | 'categoryName' => $categoryName ?? null,
42 | 'tagName' => $tagName ?? null
43 | ]);
44 | }
45 |
46 | public function show($slug) {
47 | $product = Product::where('slug', $slug)->firstOrFail();
48 | $images = json_decode($product->images);
49 | $mightLike = Product::where('slug', '!=', $product->slug)->mightAlsoLike()->get();
50 | $stockLevel = getStockLevel($product->quantity);
51 | return view('product')->with([
52 | 'product' => $product,
53 | 'mightLike' => $mightLike,
54 | 'images' => $images,
55 | 'stockLevel' => $stockLevel
56 | ]);
57 | }
58 |
59 | public function search($query) {
60 | if(strlen($query) < 3) return back()->with('error', 'minimum query length is 3');
61 | $products = Product::search($query)->paginate(10);
62 | return view('search')->with(['products' => $products, 'query' => $query]);
63 | }
64 |
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/app/Http/Controllers/VisitsController.php:
--------------------------------------------------------------------------------
1 | limit(10)
13 | ->select('country', 'visits')->get();
14 |
15 | $CountryVisit = CountryVisit::orderBy('visits', 'desc')->paginate(10);
16 | return view('admin.visits')->with([
17 | 'CountryVisit' => $CountryVisit,
18 | 'topCountries' => $topCountries,
19 | ]);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Voyager/OrdersController.php:
--------------------------------------------------------------------------------
1 | getSlug($request);
35 |
36 | $dataType = Voyager::model('DataType')->where('slug', '=', $slug)->first();
37 |
38 | $isSoftDeleted = false;
39 |
40 | if (strlen($dataType->model_name) != 0) {
41 | $model = app($dataType->model_name);
42 |
43 | // Use withTrashed() if model uses SoftDeletes and if toggle is selected
44 | if ($model && in_array(SoftDeletes::class, class_uses($model))) {
45 | $model = $model->withTrashed();
46 | }
47 | if ($dataType->scope && $dataType->scope != '' && method_exists($model, 'scope'.ucfirst($dataType->scope))) {
48 | $model = $model->{$dataType->scope}();
49 | }
50 | $dataTypeContent = call_user_func([$model, 'findOrFail'], $id);
51 | if ($dataTypeContent->deleted_at) {
52 | $isSoftDeleted = true;
53 | }
54 | } else {
55 | // If Model doest exist, get data from table name
56 | $dataTypeContent = DB::table($dataType->name)->where('id', $id)->first();
57 | }
58 |
59 | // Replace relationships' keys for labels and create READ links if a slug is provided.
60 | $dataTypeContent = $this->resolveRelations($dataTypeContent, $dataType, true);
61 |
62 | // If a column has a relationship associated with it, we do not want to show that field
63 | $this->removeRelationshipField($dataType, 'read');
64 |
65 | // Check permission
66 | $this->authorize('read', $dataTypeContent);
67 |
68 | // Check if BREAD is Translatable
69 | $isModelTranslatable = is_bread_translatable($dataTypeContent);
70 |
71 | $view = 'voyager::bread.read';
72 |
73 | if (view()->exists("voyager::$slug.read")) {
74 | $view = "voyager::$slug.read";
75 | }
76 |
77 | $products = Order::find($id)->products;
78 |
79 | return Voyager::view($view, compact('dataType', 'dataTypeContent', 'isModelTranslatable', 'isSoftDeleted', 'products'));
80 | }
81 |
82 | }
--------------------------------------------------------------------------------
/app/Http/Controllers/WelcomePageController.php:
--------------------------------------------------------------------------------
1 | take(6)->get();
13 | $hotProducts = Product::inRandomOrder()->take(3)->get();
14 | return view('welcome')->with([
15 | 'products'=> $products,
16 | 'hotProducts' => $hotProducts
17 | ]);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/app/Http/Kernel.php:
--------------------------------------------------------------------------------
1 | [
32 | \App\Http\Middleware\EncryptCookies::class,
33 | \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
34 | \Illuminate\Session\Middleware\StartSession::class,
35 | // \Illuminate\Session\Middleware\AuthenticateSession::class,
36 | \Illuminate\View\Middleware\ShareErrorsFromSession::class,
37 | \App\Http\Middleware\VerifyCsrfToken::class,
38 | \Illuminate\Routing\Middleware\SubstituteBindings::class,
39 | \App\Http\Middleware\VisitsMiddleware::class,
40 | ],
41 |
42 | 'api' => [
43 | 'throttle:60,1',
44 | 'bindings',
45 | ],
46 | ];
47 |
48 | /**
49 | * The application's route middleware.
50 | *
51 | * These middleware may be assigned to groups or used individually.
52 | *
53 | * @var array
54 | */
55 | protected $routeMiddleware = [
56 | 'auth' => \App\Http\Middleware\Authenticate::class,
57 | 'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
58 | 'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
59 | 'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
60 | 'can' => \Illuminate\Auth\Middleware\Authorize::class,
61 | 'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
62 | 'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
63 | 'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
64 | 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
65 | 'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
66 | 'admin' => AdminMiddleware::class,
67 | ];
68 |
69 | /**
70 | * The priority-sorted list of middleware.
71 | *
72 | * This forces non-global middleware to always be in the given order.
73 | *
74 | * @var array
75 | */
76 | protected $middlewarePriority = [
77 | \Illuminate\Session\Middleware\StartSession::class,
78 | \Illuminate\View\Middleware\ShareErrorsFromSession::class,
79 | \App\Http\Middleware\Authenticate::class,
80 | \Illuminate\Routing\Middleware\ThrottleRequests::class,
81 | \Illuminate\Session\Middleware\AuthenticateSession::class,
82 | \Illuminate\Routing\Middleware\SubstituteBindings::class,
83 | \Illuminate\Auth\Middleware\Authorize::class,
84 | ];
85 | }
86 |
--------------------------------------------------------------------------------
/app/Http/Middleware/AdminMiddleware.php:
--------------------------------------------------------------------------------
1 | check() || !auth()->user()->role->name == 'admin') {
19 | abort(403, 'Sorry, You don\'t have permission to access this page');
20 | }
21 | return $next($request);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/app/Http/Middleware/Authenticate.php:
--------------------------------------------------------------------------------
1 | expectsJson()) {
18 | return route('login');
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/app/Http/Middleware/CheckForMaintenanceMode.php:
--------------------------------------------------------------------------------
1 | check()) {
21 | return redirect('/');
22 | }
23 |
24 | return $next($request);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/Http/Middleware/TrimStrings.php:
--------------------------------------------------------------------------------
1 | country;
28 | $visit = CountryVisit::firstOrCreate([
29 | 'country' => $country
30 | ]);
31 | $visit->incrementVisits();
32 | session(['visited' => 'visited']);
33 | Session::save();
34 | }
35 | return $next($request);
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/app/Http/Requests/CheckoutRequest.php:
--------------------------------------------------------------------------------
1 | user() ? 'required|email' : 'required|email|unique:users';
27 | return [
28 | 'email' => $emailValidation,
29 | 'name' => 'required|max:255|min:3',
30 | 'address' => 'required',
31 | 'city' => 'required',
32 | 'province' => 'required',
33 | 'postal_code' => 'required',
34 | 'phone' => 'required'
35 | ];
36 | }
37 |
38 | public function messages() {
39 | return [
40 | 'email.unique,users,email' => "You already have an account with this email address, Please Login"
41 | ];
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/app/Mail/OrderPlaced.php:
--------------------------------------------------------------------------------
1 | order = $order;
24 | }
25 |
26 | /**
27 | * Build the message.
28 | *
29 | * @return $this
30 | */
31 | public function build()
32 | {
33 | return $this->markdown('emails.orders.placed');
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/app/Order.php:
--------------------------------------------------------------------------------
1 | belongsTo('App\User');
17 | }
18 |
19 | public function products() {
20 | // adding another field on the collection when accessing the order's products
21 | return $this->belongsToMany('App\Product')->withPivot('quantity');
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/app/OrderProduct.php:
--------------------------------------------------------------------------------
1 | [
16 | 'products.name' => 6,
17 | 'products.details' => 3,
18 | 'products.description' => 2,
19 | ],
20 | ];
21 |
22 | protected $guarded = [];
23 |
24 | public function scopeMightAlsoLike($query) {
25 | return $query->inRandomOrder()->take(3);
26 | }
27 |
28 | public function category() {
29 | return $this->belongsTo('App\Category');
30 | }
31 |
32 | public function tags() {
33 | return $this->belongsToMany('App\Tag');
34 | }
35 |
36 | public function toSearchableArray() {
37 | $array = $this->toArray();
38 | $extraFields = [
39 | 'category' => $this->category->name
40 | ];
41 | return array_merge($array, $extraFields);
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/app/ProductTag.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 |
--------------------------------------------------------------------------------
/app/Providers/BroadcastServiceProvider.php:
--------------------------------------------------------------------------------
1 | [
19 | SendEmailVerificationNotification::class,
20 | ],
21 | ];
22 |
23 | /**
24 | * Register any events for your application.
25 | *
26 | * @return void
27 | */
28 | public function boot()
29 | {
30 | parent::boot();
31 |
32 | //
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/app/Providers/RouteServiceProvider.php:
--------------------------------------------------------------------------------
1 | mapApiRoutes();
39 |
40 | $this->mapWebRoutes();
41 |
42 | //
43 | }
44 |
45 | /**
46 | * Define the "web" routes for the application.
47 | *
48 | * These routes all receive session state, CSRF protection, etc.
49 | *
50 | * @return void
51 | */
52 | protected function mapWebRoutes()
53 | {
54 | Route::middleware('web')
55 | ->namespace($this->namespace)
56 | ->group(base_path('routes/web.php'));
57 | }
58 |
59 | /**
60 | * Define the "api" routes for the application.
61 | *
62 | * These routes are typically stateless.
63 | *
64 | * @return void
65 | */
66 | protected function mapApiRoutes()
67 | {
68 | Route::prefix('api')
69 | ->middleware('api')
70 | ->namespace($this->namespace)
71 | ->group(base_path('routes/api.php'));
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/app/Tag.php:
--------------------------------------------------------------------------------
1 | belongsToMany('App\Product');
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/app/User.php:
--------------------------------------------------------------------------------
1 | 'datetime',
38 | ];
39 |
40 | public function orders() {
41 | return $this->hasMany('App\Order');
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/app/library/helper.php:
--------------------------------------------------------------------------------
1 | $limit ? substr($string, 0, $limit) . ' ...' : $string;
21 | }
22 |
23 | function getStockLevel($quantity) {
24 | if($quantity > setting('site.stock_threshold')) {
25 | return 'In Stock';
26 | } else if($quantity <= setting('site.stock_threshold') && $quantity > 0) {
27 | return 'Low Stock';
28 | } else {
29 | return 'Out Of Stock';
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/artisan:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env php
2 | make(Illuminate\Contracts\Console\Kernel::class);
34 |
35 | $status = $kernel->handle(
36 | $input = new Symfony\Component\Console\Input\ArgvInput,
37 | new Symfony\Component\Console\Output\ConsoleOutput
38 | );
39 |
40 | /*
41 | |--------------------------------------------------------------------------
42 | | Shutdown The Application
43 | |--------------------------------------------------------------------------
44 | |
45 | | Once Artisan has finished running, we will fire off the shutdown events
46 | | so that any final work may be done by the application before we shut
47 | | down the process. This is the last thing to happen to the request.
48 | |
49 | */
50 |
51 | $kernel->terminate($input, $status);
52 |
53 | exit($status);
54 |
--------------------------------------------------------------------------------
/bootstrap/app.php:
--------------------------------------------------------------------------------
1 | singleton(
30 | Illuminate\Contracts\Http\Kernel::class,
31 | App\Http\Kernel::class
32 | );
33 |
34 | $app->singleton(
35 | Illuminate\Contracts\Console\Kernel::class,
36 | App\Console\Kernel::class
37 | );
38 |
39 | $app->singleton(
40 | Illuminate\Contracts\Debug\ExceptionHandler::class,
41 | App\Exceptions\Handler::class
42 | );
43 |
44 | /*
45 | |--------------------------------------------------------------------------
46 | | Return The Application
47 | |--------------------------------------------------------------------------
48 | |
49 | | This script returns the application instance. The instance is given to
50 | | the calling script so we can separate the building of the instances
51 | | from the actual running of the application and sending responses.
52 | |
53 | */
54 |
55 | return $app;
56 |
--------------------------------------------------------------------------------
/bootstrap/cache/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "laravel/laravel",
3 | "type": "project",
4 | "description": "The Laravel Framework.",
5 | "keywords": [
6 | "framework",
7 | "laravel"
8 | ],
9 | "license": "MIT",
10 | "require": {
11 | "php": "^8.0.2",
12 | "bumbummen99/shoppingcart": "^4.2",
13 | "cartalyst/stripe-laravel": "^14.0",
14 | "fideloper/proxy": "^4.0",
15 | "fzaninotto/faker": "^1.4",
16 | "laravel/framework": "^9.0",
17 | "laravel/socialite": "^5.0",
18 | "laravel/tinker": "^2.0",
19 | "laravel/ui": "^3.0",
20 | "mhmdomer/laravel-database-backup": "^1.1.0",
21 | "nicolaslopezj/searchable": "^1.12",
22 | "predis/predis": "^1.1",
23 | "rap2hpoutre/laravel-log-viewer": "^2.3",
24 | "tcg/voyager": "^1.3",
25 | "torann/geoip": "^3.0"
26 | },
27 | "require-dev": {
28 | "barryvdh/laravel-debugbar": "^3.3",
29 | "spatie/laravel-ignition": "^1.0",
30 | "mockery/mockery": "^1.0",
31 | "nunomaduro/collision": "^6.1",
32 | "phpunit/phpunit": "^9.0"
33 | },
34 | "config": {
35 | "optimize-autoloader": true,
36 | "preferred-install": "dist",
37 | "sort-packages": true
38 | },
39 | "extra": {
40 | "laravel": {
41 | "dont-discover": []
42 | }
43 | },
44 | "autoload": {
45 | "files": [
46 | "app/library/helper.php"
47 | ],
48 | "psr-4": {
49 | "App\\": "app/",
50 | "Database\\Factories\\": "database/factories/",
51 | "Database\\Seeders\\": "database/seeds/"
52 | },
53 | "classmap": [
54 | "database/seeds",
55 | "database/factories"
56 | ]
57 | },
58 | "autoload-dev": {
59 | "psr-4": {
60 | "Tests\\": "tests/"
61 | }
62 | },
63 | "minimum-stability": "dev",
64 | "prefer-stable": true,
65 | "scripts": {
66 | "post-autoload-dump": [
67 | "Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
68 | "@php artisan package:discover --ansi"
69 | ],
70 | "post-root-package-install": [
71 | "@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
72 | ],
73 | "post-create-project-cmd": [
74 | "@php artisan key:generate --ansi"
75 | ]
76 | },
77 | "repositories": {
78 | "hooks": {
79 | "type": "composer",
80 | "url": "https://larapack.io"
81 | }
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/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\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 | ],
101 | ],
102 |
103 | /*
104 | |--------------------------------------------------------------------------
105 | | Password Confirmation Timeout
106 | |--------------------------------------------------------------------------
107 | |
108 | | Here you may define the amount of seconds before a password confirmation
109 | | times out and the user is prompted to re-enter their password via the
110 | | confirmation screen. By default, the timeout lasts for three hours.
111 | |
112 | */
113 |
114 | 'password_timeout' => 10800,
115 |
116 | ];
117 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 | ],
43 |
44 | 'database' => [
45 | 'driver' => 'database',
46 | 'table' => 'cache',
47 | 'connection' => null,
48 | ],
49 |
50 | 'file' => [
51 | 'driver' => 'file',
52 | 'path' => storage_path('framework/cache/data'),
53 | ],
54 |
55 | 'memcached' => [
56 | 'driver' => 'memcached',
57 | 'persistent_id' => env('MEMCACHED_PERSISTENT_ID'),
58 | 'sasl' => [
59 | env('MEMCACHED_USERNAME'),
60 | env('MEMCACHED_PASSWORD'),
61 | ],
62 | 'options' => [
63 | // Memcached::OPT_CONNECT_TIMEOUT => 2000,
64 | ],
65 | 'servers' => [
66 | [
67 | 'host' => env('MEMCACHED_HOST', '127.0.0.1'),
68 | 'port' => env('MEMCACHED_PORT', 11211),
69 | 'weight' => 100,
70 | ],
71 | ],
72 | ],
73 |
74 | 'redis' => [
75 | 'driver' => 'redis',
76 | 'connection' => 'cache',
77 | ],
78 |
79 | 'dynamodb' => [
80 | 'driver' => 'dynamodb',
81 | 'key' => env('AWS_ACCESS_KEY_ID'),
82 | 'secret' => env('AWS_SECRET_ACCESS_KEY'),
83 | 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
84 | 'table' => env('DYNAMODB_CACHE_TABLE', 'cache'),
85 | 'endpoint' => env('DYNAMODB_ENDPOINT'),
86 | ],
87 |
88 | ],
89 |
90 | /*
91 | |--------------------------------------------------------------------------
92 | | Cache Key Prefix
93 | |--------------------------------------------------------------------------
94 | |
95 | | When utilizing a RAM based store such as APC or Memcached, there might
96 | | be other applications utilizing the same cache. So, we'll specify a
97 | | value to get prefixed to all our keys so we can avoid collisions.
98 | |
99 | */
100 |
101 | 'prefix' => env('CACHE_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_cache'),
102 |
103 | ];
104 |
--------------------------------------------------------------------------------
/config/cart.php:
--------------------------------------------------------------------------------
1 | 21,
16 |
17 | /*
18 | |--------------------------------------------------------------------------
19 | | Shoppingcart database settings
20 | |--------------------------------------------------------------------------
21 | |
22 | | Here you can set the connection that the shoppingcart should use when
23 | | storing and restoring a cart.
24 | |
25 | */
26 |
27 | 'database' => [
28 |
29 | 'connection' => null,
30 |
31 | 'table' => 'shoppingcart',
32 |
33 | ],
34 |
35 | /*
36 | |--------------------------------------------------------------------------
37 | | Destroy the cart on user logout
38 | |--------------------------------------------------------------------------
39 | |
40 | | When this option is set to 'true' the cart will automatically
41 | | destroy all cart instances when the user logs out.
42 | |
43 | */
44 |
45 | 'destroy_on_logout' => false,
46 |
47 | /*
48 | |--------------------------------------------------------------------------
49 | | Default number format
50 | |--------------------------------------------------------------------------
51 | |
52 | | This defaults will be used for the formatted numbers if you don't
53 | | set them in the method call.
54 | |
55 | */
56 |
57 | 'format' => [
58 |
59 | 'decimals' => 0,
60 |
61 | 'decimal_point' => '',
62 |
63 | 'thousand_separator' => '',
64 |
65 | ],
66 |
67 | ];
68 |
--------------------------------------------------------------------------------
/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 | ],
66 |
67 | ],
68 |
69 | ];
70 |
--------------------------------------------------------------------------------
/config/hashing.php:
--------------------------------------------------------------------------------
1 | 'bcrypt',
19 |
20 | /*
21 | |--------------------------------------------------------------------------
22 | | Bcrypt Options
23 | |--------------------------------------------------------------------------
24 | |
25 | | Here you may specify the configuration options that should be used when
26 | | passwords are hashed using the Bcrypt algorithm. This will allow you
27 | | to control the amount of time it takes to hash the given password.
28 | |
29 | */
30 |
31 | 'bcrypt' => [
32 | 'rounds' => env('BCRYPT_ROUNDS', 10),
33 | ],
34 |
35 | /*
36 | |--------------------------------------------------------------------------
37 | | Argon Options
38 | |--------------------------------------------------------------------------
39 | |
40 | | Here you may specify the configuration options that should be used when
41 | | passwords are hashed using the Argon algorithm. These will allow you
42 | | to control the amount of time it takes to hash the given password.
43 | |
44 | */
45 |
46 | 'argon' => [
47 | 'memory' => 1024,
48 | 'threads' => 2,
49 | 'time' => 2,
50 | ],
51 |
52 | ];
53 |
--------------------------------------------------------------------------------
/config/hooks.php:
--------------------------------------------------------------------------------
1 | env('HOOKS_ENABLED', true),
6 |
7 | ];
8 |
--------------------------------------------------------------------------------
/config/image.php:
--------------------------------------------------------------------------------
1 | 'gd'
19 |
20 | ];
21 |
--------------------------------------------------------------------------------
/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' => ['daily'],
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 |
100 | ];
101 |
--------------------------------------------------------------------------------
/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 | 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
59 | ],
60 |
61 | 'redis' => [
62 | 'driver' => 'redis',
63 | 'connection' => 'default',
64 | 'queue' => env('REDIS_QUEUE', 'default'),
65 | 'retry_after' => 90,
66 | 'block_for' => null,
67 | ],
68 |
69 | ],
70 |
71 | /*
72 | |--------------------------------------------------------------------------
73 | | Failed Queue Jobs
74 | |--------------------------------------------------------------------------
75 | |
76 | | These options configure the behavior of failed queue job logging so you
77 | | can control which database and table are used to store the jobs that
78 | | have failed. You may change them to any database / table you wish.
79 | |
80 | */
81 |
82 | 'failed' => [
83 | 'driver' => env('QUEUE_FAILED_DRIVER', 'database'),
84 | 'database' => env('DB_CONNECTION', 'mysql'),
85 | 'table' => 'failed_jobs',
86 | ],
87 |
88 | ];
89 |
--------------------------------------------------------------------------------
/config/scout.php:
--------------------------------------------------------------------------------
1 | env('SCOUT_DRIVER', 'algolia'),
19 |
20 | /*
21 | |--------------------------------------------------------------------------
22 | | Index Prefix
23 | |--------------------------------------------------------------------------
24 | |
25 | | Here you may specify a prefix that will be applied to all search index
26 | | names used by Scout. This prefix may be useful if you have multiple
27 | | "tenants" or applications sharing the same search infrastructure.
28 | |
29 | */
30 |
31 | 'prefix' => env('SCOUT_PREFIX', ''),
32 |
33 | /*
34 | |--------------------------------------------------------------------------
35 | | Queue Data Syncing
36 | |--------------------------------------------------------------------------
37 | |
38 | | This option allows you to control if the operations that sync your data
39 | | with your search engines are queued. When this is set to "true" then
40 | | all automatic data syncing will get queued for better performance.
41 | |
42 | */
43 |
44 | 'queue' => env('SCOUT_QUEUE', false),
45 |
46 | /*
47 | |--------------------------------------------------------------------------
48 | | Chunk Sizes
49 | |--------------------------------------------------------------------------
50 | |
51 | | These options allow you to control the maximum chunk size when you are
52 | | mass importing data into the search engine. This allows you to fine
53 | | tune each of these chunk sizes based on the power of the servers.
54 | |
55 | */
56 |
57 | 'chunk' => [
58 | 'searchable' => 500,
59 | 'unsearchable' => 500,
60 | ],
61 |
62 | /*
63 | |--------------------------------------------------------------------------
64 | | Soft Deletes
65 | |--------------------------------------------------------------------------
66 | |
67 | | This option allows to control whether to keep soft deleted records in
68 | | the search indexes. Maintaining soft deleted records can be useful
69 | | if your application still needs to search for the records later.
70 | |
71 | */
72 |
73 | 'soft_delete' => false,
74 |
75 | /*
76 | |--------------------------------------------------------------------------
77 | | Algolia Configuration
78 | |--------------------------------------------------------------------------
79 | |
80 | | Here you may configure your Algolia settings. Algolia is a cloud hosted
81 | | search engine which works great with Scout out of the box. Just plug
82 | | in your application ID and admin API key to get started searching.
83 | |
84 | */
85 |
86 | 'algolia' => [
87 | 'id' => env('ALGOLIA_APP_ID', ''),
88 | 'secret' => env('ALGOLIA_SECRET', ''),
89 | ],
90 |
91 | ];
92 |
--------------------------------------------------------------------------------
/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 | 'stripe' => [
34 | 'model' => App\User::class,
35 | 'key' => env('STRIPE_KEY'),
36 | 'secret' => env('STRIPE_SECRET'),
37 | ],
38 |
39 | 'github' => [
40 | 'client_id' => env('GITHUB_CLIENT_ID'),
41 | 'client_secret' => env('GITHUB_CLIENT_SECRET'),
42 | 'redirect' => env('GITHUB_CALLBACK'),
43 | ],
44 |
45 | 'facebook' => [
46 | 'client_id' => env('FACEBOOK_CLIENT_ID'),
47 | 'client_secret' => env('FACEBOOK_CLIENT_SECRET'),
48 | 'redirect' => env('FACEBOOK_CALLBACK'),
49 | ],
50 |
51 | ];
52 |
--------------------------------------------------------------------------------
/config/view.php:
--------------------------------------------------------------------------------
1 | [
17 | resource_path('views'),
18 | ],
19 |
20 | /*
21 | |--------------------------------------------------------------------------
22 | | Compiled View Path
23 | |--------------------------------------------------------------------------
24 | |
25 | | This option determines where all the compiled Blade templates will be
26 | | stored for your application. Typically, this is within the storage
27 | | directory. However, as usual, you are free to change this value.
28 | |
29 | */
30 |
31 | 'compiled' => env(
32 | 'VIEW_COMPILED_PATH',
33 | realpath(storage_path('framework/views'))
34 | ),
35 |
36 | ];
37 |
--------------------------------------------------------------------------------
/config/voyager-hooks.php:
--------------------------------------------------------------------------------
1 | env('HOOKS_ENABLED', true),
6 |
7 | 'add-route' => true,
8 | 'add-hook-menu-item' => true,
9 | 'add-hook-permissions' => true,
10 | 'publish-vendor-files' => true,
11 |
12 | ];
13 |
--------------------------------------------------------------------------------
/database/.gitignore:
--------------------------------------------------------------------------------
1 | *.sqlite
2 | *.sqlite-journal
3 |
--------------------------------------------------------------------------------
/database/factories/UserFactory.php:
--------------------------------------------------------------------------------
1 | define(User::class, function (Faker $faker) {
20 | return [
21 | 'name' => $faker->name,
22 | 'email' => $faker->unique()->safeEmail,
23 | 'email_verified_at' => now(),
24 | 'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
25 | 'remember_token' => Str::random(10),
26 | ];
27 | });
28 |
--------------------------------------------------------------------------------
/database/migrations/2014_10_12_000000_create_users_table.php:
--------------------------------------------------------------------------------
1 | bigIncrements('id');
16 | $table->string('name');
17 | $table->string('email')->unique();
18 | $table->timestamp('email_verified_at')->nullable();
19 | $table->string('github_id')->nullable();
20 | $table->string('facebook_id')->nullable();
21 | $table->string('google_id')->nullable();
22 | $table->string('password')->nullable();
23 | $table->rememberToken();
24 | $table->timestamps();
25 | });
26 | }
27 | /**
28 | * Reverse the migrations.
29 | *
30 | * @return void
31 | */
32 | public function down()
33 | {
34 | Schema::dropIfExists('users');
35 | }
36 | }
--------------------------------------------------------------------------------
/database/migrations/2014_10_12_100000_create_password_resets_table.php:
--------------------------------------------------------------------------------
1 | string('email')->index();
16 | $table->string('token');
17 | $table->timestamp('created_at')->nullable();
18 | });
19 | }
20 | /**
21 | * Reverse the migrations.
22 | *
23 | * @return void
24 | */
25 | public function down()
26 | {
27 | Schema::dropIfExists('password_resets');
28 | }
29 | }
--------------------------------------------------------------------------------
/database/migrations/2019_08_19_000000_create_failed_jobs_table.php:
--------------------------------------------------------------------------------
1 | bigIncrements('id');
16 | $table->text('connection');
17 | $table->text('queue');
18 | $table->longText('payload');
19 | $table->longText('exception');
20 | $table->timestamp('failed_at')->useCurrent();
21 | });
22 | }
23 | /**
24 | * Reverse the migrations.
25 | *
26 | * @return void
27 | */
28 | public function down()
29 | {
30 | Schema::dropIfExists('failed_jobs');
31 | }
32 | }
--------------------------------------------------------------------------------
/database/migrations/2019_10_16_185424_create_products_table.php:
--------------------------------------------------------------------------------
1 | bigIncrements('id');
18 | $table->string('name')->unique();
19 | $table->string('slug')->unique();
20 | $table->string('details')->nullable();
21 | $table->integer('price');
22 | $table->text('description');
23 | $table->timestamps();
24 | });
25 | }
26 |
27 | /**
28 | * Reverse the migrations.
29 | *
30 | * @return void
31 | */
32 | public function down()
33 | {
34 | Schema::dropIfExists('products');
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/database/migrations/2019_10_17_195112_create_categories_table.php:
--------------------------------------------------------------------------------
1 | bigIncrements('id');
18 | $table->string('name')->unique();
19 | $table->string('slug')->unique();
20 | $table->timestamps();
21 | });
22 | }
23 |
24 | /**
25 | * Reverse the migrations.
26 | *
27 | * @return void
28 | */
29 | public function down()
30 | {
31 | Schema::dropIfExists('category');
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/database/migrations/2019_10_17_195227_add_category_id_to_products_table.php:
--------------------------------------------------------------------------------
1 | string('image')->after('price');
18 | $table->boolean('featured')->default(false)->after('image');
19 | $table->unsignedBigInteger('category_id')->after('featured');
20 | $table->foreign('category_id')->references('id')->on('category')->onDelete('cascade');
21 | });
22 | }
23 |
24 | /**
25 | * Reverse the migrations.
26 | *
27 | * @return void
28 | */
29 | public function down()
30 | {
31 | Schema::table('products', function (Blueprint $table) {
32 | $table->dropForeign('products_category_id_foreign');
33 | $table->dropColumn('image');
34 | $table->dropColumn('category_id');
35 | });
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/database/migrations/2019_10_18_002421_create_coupons_table.php:
--------------------------------------------------------------------------------
1 | bigIncrements('id');
18 | $table->string('code')->unique();
19 | $table->string('type');
20 | $table->integer('value')->nullable();
21 | $table->integer('percent_off')->nullable();
22 | $table->timestamps();
23 | });
24 | }
25 |
26 | /**
27 | * Reverse the migrations.
28 | *
29 | * @return void
30 | */
31 | public function down()
32 | {
33 | Schema::dropIfExists('coupons');
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/database/migrations/2019_10_19_145706_add_images_column_to_products.php:
--------------------------------------------------------------------------------
1 | text('images')->nullable()->after('image');
18 | });
19 | }
20 |
21 | /**
22 | * Reverse the migrations.
23 | *
24 | * @return void
25 | */
26 | public function down()
27 | {
28 | Schema::table('products', function (Blueprint $table) {
29 | $table->dropColumn('images');
30 | });
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/database/migrations/2019_10_20_114921_create_tags_table.php:
--------------------------------------------------------------------------------
1 | bigIncrements('id');
18 | $table->string('name')->unique();
19 | $table->string('slug')->unique();
20 | $table->timestamps();
21 | });
22 | }
23 |
24 | /**
25 | * Reverse the migrations.
26 | *
27 | * @return void
28 | */
29 | public function down()
30 | {
31 | Schema::dropIfExists('tags');
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/database/migrations/2019_10_20_115306_create_products_tags_table.php:
--------------------------------------------------------------------------------
1 | bigIncrements('id');
18 | $table->unsignedBigInteger('product_id');
19 | $table->foreign('product_id')->references('id')->on('products')->onDelete('cascade');
20 | $table->unsignedBigInteger('tag_id');
21 | $table->foreign('tag_id')->references('id')->on('tags')->onDelete('cascade');
22 | $table->timestamps();
23 | });
24 | }
25 |
26 | /**
27 | * Reverse the migrations.
28 | *
29 | * @return void
30 | */
31 | public function down()
32 | {
33 | Schema::dropIfExists('product_tag');
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/database/migrations/2019_10_22_185425_create_orders_table.php:
--------------------------------------------------------------------------------
1 | bigIncrements('id');
18 | $table->unsignedBigInteger('user_id')->nullable();
19 | $table->foreign('user_id')->references('id')->on('users')
20 | ->onUpdate('cascade')->onDelete('set null');
21 | $table->string('billing_email');
22 | $table->string('billing_name');
23 | $table->string('billing_address');
24 | $table->string('billing_city');
25 | $table->string('billing_province');
26 | $table->string('billing_postalcode');
27 | $table->string('billing_phone');
28 | $table->string('billing_name_on_card');
29 | $table->integer('billing_discount')->default(0);
30 | $table->string('billing_discount_code')->nullable();
31 | $table->integer('billing_subtotal');
32 | $table->integer('billing_tax');
33 | $table->integer('billing_total');
34 | $table->string('payment_gateway')->default('stripe');
35 | $table->boolean('shipped')->default(false);
36 | $table->string('error')->nullable();
37 | $table->timestamps();
38 | });
39 | }
40 |
41 | /**
42 | * Reverse the migrations.
43 | *
44 | * @return void
45 | */
46 | public function down()
47 | {
48 | Schema::dropIfExists('orders');
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/database/migrations/2019_10_22_190613_create_order_product_table.php:
--------------------------------------------------------------------------------
1 | bigIncrements('id');
18 | $table->unsignedBigInteger('product_id')->nullable();
19 | $table->foreign('product_id')->references('id')->on('products')
20 | ->onUpdate('cascade')->onDelete('set null');
21 | $table->unsignedBigInteger('order_id')->nullable();
22 | $table->foreign('order_id')->references('id')->on('orders')
23 | ->onUpdate('cascade')->onDelete('set null');
24 | $table->unsignedInteger('quantity');
25 | $table->timestamps();
26 | });
27 | }
28 |
29 | /**
30 | * Reverse the migrations.
31 | *
32 | * @return void
33 | */
34 | public function down()
35 | {
36 | Schema::dropIfExists('order_product');
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/database/migrations/2019_11_09_002942_add_quantity_to_products_table.php:
--------------------------------------------------------------------------------
1 | unsignedInteger('quantity')->after('featured')->default(10);
18 | });
19 | }
20 |
21 | /**
22 | * Reverse the migrations.
23 | *
24 | * @return void
25 | */
26 | public function down()
27 | {
28 | Schema::table('products', function (Blueprint $table) {
29 | $table->dropColumn('quantity');
30 | });
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/database/migrations/2020_06_27_012504_create_visits_table.php:
--------------------------------------------------------------------------------
1 | bigIncrements('id');
18 | $table->string('country');
19 | $table->unsignedBigInteger('visits')->default(0);
20 | $table->timestamps();
21 | });
22 | }
23 |
24 | /**
25 | * Reverse the migrations.
26 | *
27 | * @return void
28 | */
29 | public function down()
30 | {
31 | Schema::dropIfExists('visits');
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/database/seeds/CategoryTableSeeder.php:
--------------------------------------------------------------------------------
1 | 'Laptops',
19 | 'slug' => 'laptops'
20 | ]);
21 | Category::create([
22 | 'name' => 'Desktops',
23 | 'slug' => 'desktops'
24 | ]);
25 | Category::create([
26 | 'name' => 'Phones',
27 | 'slug' => 'phones'
28 | ]);
29 | Category::create([
30 | 'name' => 'Tablets',
31 | 'slug' => 'tablets'
32 | ]);
33 | Category::create([
34 | 'name' => 'TVs',
35 | 'slug' => 'tvs'
36 | ]);
37 | Category::create([
38 | 'name' => 'Cameras',
39 | 'slug' => 'cameras'
40 | ]);
41 |
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/database/seeds/CouponsTableSeeder.php:
--------------------------------------------------------------------------------
1 | 'ABC123',
19 | 'type' => 'fixed',
20 | 'value' => 20,
21 | ]);
22 | Coupon::create([
23 | 'code' => 'DEF456',
24 | 'type' => 'percent',
25 | 'percent_off' => 40,
26 | ]);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/database/seeds/DataTypesTableSeeder.php:
--------------------------------------------------------------------------------
1 | dataType('slug', 'users');
16 | if (!$dataType->exists) {
17 | $dataType->fill([
18 | 'name' => 'users',
19 | 'display_name_singular' => __('voyager::seeders.data_types.user.singular'),
20 | 'display_name_plural' => __('voyager::seeders.data_types.user.plural'),
21 | 'icon' => 'voyager-person',
22 | 'model_name' => 'TCG\\Voyager\\Models\\User',
23 | 'policy_name' => 'TCG\\Voyager\\Policies\\UserPolicy',
24 | 'controller' => 'TCG\\Voyager\\Http\\Controllers\\VoyagerUserController',
25 | 'generate_permissions' => 1,
26 | 'description' => '',
27 | ])->save();
28 | }
29 |
30 | $dataType = $this->dataType('slug', 'menus');
31 | if (!$dataType->exists) {
32 | $dataType->fill([
33 | 'name' => 'menus',
34 | 'display_name_singular' => __('voyager::seeders.data_types.menu.singular'),
35 | 'display_name_plural' => __('voyager::seeders.data_types.menu.plural'),
36 | 'icon' => 'voyager-list',
37 | 'model_name' => 'TCG\\Voyager\\Models\\Menu',
38 | 'controller' => '',
39 | 'generate_permissions' => 1,
40 | 'description' => '',
41 | ])->save();
42 | }
43 |
44 | $dataType = $this->dataType('slug', 'roles');
45 | if (!$dataType->exists) {
46 | $dataType->fill([
47 | 'name' => 'roles',
48 | 'display_name_singular' => __('voyager::seeders.data_types.role.singular'),
49 | 'display_name_plural' => __('voyager::seeders.data_types.role.plural'),
50 | 'icon' => 'voyager-lock',
51 | 'model_name' => 'TCG\\Voyager\\Models\\Role',
52 | 'controller' => '',
53 | 'generate_permissions' => 1,
54 | 'description' => '',
55 | ])->save();
56 | }
57 | }
58 |
59 | /**
60 | * [dataType description].
61 | *
62 | * @param [type] $field [description]
63 | * @param [type] $for [description]
64 | *
65 | * @return [type] [description]
66 | */
67 | protected function dataType($field, $for)
68 | {
69 | return DataType::firstOrNew([$field => $for]);
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/database/seeds/DatabaseSeeder.php:
--------------------------------------------------------------------------------
1 | call(CategoryTableSeeder::class);
17 | $this->call(TagsTableSeeder::class);
18 | $this->call(CouponsTableSeeder::class);
19 | $this->call(ProductsTableSeeder::class);
20 | $this->call(ProductTagSeeder::class);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/database/seeds/MenusTableSeeder.php:
--------------------------------------------------------------------------------
1 | 'admin',
19 | ]);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/database/seeds/MenusTableSeederCustom.php:
--------------------------------------------------------------------------------
1 | 'main',
19 | ]);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/database/seeds/OrderProductTableSeeder.php:
--------------------------------------------------------------------------------
1 | rand(1, 120),
21 | 'order_id' => Order::all()->random()->id,
22 | 'quantity' => rand(1,3),
23 | ]);
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/database/seeds/OrdersTableSeeder.php:
--------------------------------------------------------------------------------
1 | rand(1, 2) == 1? 1 : null,
22 | 'billing_email' => $faker->email,
23 | 'billing_name' => $faker->userName,
24 | 'billing_address' => $faker->secondaryAddress,
25 | 'billing_city' => $faker->city,
26 | 'billing_province' => $faker->city,
27 | 'billing_postalcode' => $faker->postcode,
28 | 'billing_phone' => $faker->phoneNumber,
29 | 'billing_name_on_card' => $faker->userName,
30 | 'billing_discount' => 0,
31 | 'billing_discount_code' => null,
32 | 'billing_subtotal' => 1000,
33 | 'billing_tax' => 200,
34 | 'billing_total' => 1200,
35 | 'shipped' => rand(0,1),
36 | 'error' => $i%4 == 0 ? 'Error' : null,
37 | ]);
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/database/seeds/PermissionRoleTableSeeder.php:
--------------------------------------------------------------------------------
1 | firstOrFail();
19 |
20 | $permissions = Permission::all();
21 |
22 | $role->permissions()->sync(
23 | $permissions->pluck('id')->all()
24 | );
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/database/seeds/PermissionRoleTableSeederCustom.php:
--------------------------------------------------------------------------------
1 | firstOrFail();
19 |
20 | $permissions = Permission::all();
21 |
22 | $role->permissions()->sync(
23 | $permissions->pluck('id')->all()
24 | );
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/database/seeds/PermissionsTableSeeder.php:
--------------------------------------------------------------------------------
1 | $key,
26 | 'table_name' => null,
27 | ]);
28 | }
29 |
30 | Permission::generateFor('menus');
31 |
32 | Permission::generateFor('roles');
33 |
34 | Permission::generateFor('users');
35 |
36 | Permission::generateFor('settings');
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/database/seeds/PermissionsTableSeederCustom.php:
--------------------------------------------------------------------------------
1 | $key,
26 | 'table_name' => null,
27 | ]);
28 | }
29 |
30 | Permission::generateFor('products');
31 |
32 | Permission::generateFor('category');
33 |
34 | Permission::generateFor('coupons');
35 |
36 | Permission::generateFor('tags');
37 |
38 | Permission::generateFor('product_tag');
39 |
40 | Permission::generateFor('orders');
41 |
42 | Permission::generateFor('country_visits');
43 |
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/database/seeds/ProductTagSeeder.php:
--------------------------------------------------------------------------------
1 | rand(1, 120),
20 | 'tag_id' => rand(1, 4)
21 | ]);
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/database/seeds/RolesTableSeeder.php:
--------------------------------------------------------------------------------
1 | 'admin']);
16 | if (!$role->exists) {
17 | $role->fill([
18 | 'display_name' => __('voyager::seeders.roles.admin'),
19 | ])->save();
20 | }
21 |
22 | $role = Role::firstOrNew(['name' => 'user']);
23 | if (!$role->exists) {
24 | $role->fill([
25 | 'display_name' => __('voyager::seeders.roles.user'),
26 | ])->save();
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/database/seeds/SettingsTableSeederCustom.php:
--------------------------------------------------------------------------------
1 | findSetting('site.stock_threshold');
16 | if (!$setting->exists) {
17 | $setting->fill([
18 | 'display_name' => 'Stock Threshold',
19 | 'value' => 5,
20 | 'details' => '',
21 | 'type' => 'number',
22 | 'order' => 6,
23 | 'group' => 'Site',
24 | ])->save();
25 | }
26 | }
27 |
28 | /**
29 | * [setting description].
30 | *
31 | * @param [type] $key [description]
32 | *
33 | * @return [type] [description]
34 | */
35 | protected function findSetting($key)
36 | {
37 | return Setting::firstOrNew(['key' => $key]);
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/database/seeds/TagsTableSeeder.php:
--------------------------------------------------------------------------------
1 | 'Tag ' . $i,
20 | 'slug' => 'tag-' . $i
21 | ]);
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/database/seeds/UsersTableSeeder.php:
--------------------------------------------------------------------------------
1 | firstOrFail();
21 |
22 | User::create([
23 | 'name' => 'Admin',
24 | 'email' => 'admin@admin.com',
25 | 'password' => bcrypt(config('voyager.password')),
26 | 'remember_token' => Str::random(60),
27 | 'role_id' => $role->id,
28 | ]);
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/database/seeds/VoyagerDatabaseSeeder.php:
--------------------------------------------------------------------------------
1 | call(DataTypesTableSeeder::class);
22 | $this->call(DataRowsTableSeeder::class);
23 | $this->call(MenusTableSeeder::class);
24 | $this->call(MenuItemsTableSeeder::class);
25 | $this->call(RolesTableSeeder::class);
26 | $this->call(PermissionsTableSeeder::class);
27 | $this->call(PermissionRoleTableSeeder::class);
28 | $this->call(SettingsTableSeeder::class);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/database/seeds/VoyagerDatabaseSeederCustom.php:
--------------------------------------------------------------------------------
1 | call(DataTypesTableSeederCustom::class);
22 | $this->call(DataRowsTableSeederCustom::class);
23 | $this->call(MenusTableSeederCustom::class);
24 | $this->call(MenuItemsTableSeederCustom::class);
25 | $this->call(PermissionsTableSeederCustom::class);
26 | $this->call(PermissionRoleTableSeederCustom::class);
27 | $this->call(SettingsTableSeederCustom::class);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/database/seeds/VoyagerDummyDatabaseSeeder.php:
--------------------------------------------------------------------------------
1 | seedersPath = database_path('seeds').'/';
22 | $this->call(UsersTableSeeder::class);
23 | $this->call(PermissionRoleTableSeeder::class);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/hooks/hooks.json:
--------------------------------------------------------------------------------
1 | {}
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "scripts": {
4 | "dev": "npm run development",
5 | "development": "mix",
6 | "watch": "mix watch",
7 | "watch-poll": "mix watch -- --watch-options-poll=1000",
8 | "hot": "mix watch --hot",
9 | "prod": "npm run production",
10 | "production": "mix --production"
11 | },
12 | "devDependencies": {
13 | "axios": "^0.28.0",
14 | "bootstrap": "^4.5.0",
15 | "cross-env": "^5.1",
16 | "font-awesome": "^4.7.0",
17 | "jquery": "^3.5.1",
18 | "laravel-mix": "^6.0.49",
19 | "lodash": "^4.17.21",
20 | "popper.js": "^1.16.1",
21 | "resolve-url-loader": "^2.3.1",
22 | "sass": "^1.26.9",
23 | "sass-loader": "7.*",
24 | "vue": "^2.6.11",
25 | "vue-template-compiler": "^2.6.11"
26 | },
27 | "dependencies": {
28 | "aos": "^3.0.0-beta.6",
29 | "chart.js": "^2.9.4",
30 | "font-awesome": "^4.7.0"
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/phpunit.xml:
--------------------------------------------------------------------------------
1 |
2 |
Country | 28 |Visits | 29 |
---|---|
{{ $visit->country }} | 35 |{{ $visit->visits }} | 36 |
{{ $product->details }}
27 |{!! $product->description !!}
29 | @if ($product->quantity > 0) 30 | 37 | @endif 38 |Name | 16 |Price | 17 |details | 18 |Description | 19 |Image | 20 |
---|---|---|---|---|
{{ $product->name }} | 26 |${{ format($product->price) }} | 27 |{{ $product->details }} | 28 |{{ str_limit($product->description, 70) }} | 29 |
Lorem ipsum dolor sit amet consectetur adipisicing elit. Aliquam, assumenda. Culpa, libero.
13 | 14 | 15 |Lorem ipsum dolor sit amet consectetur adipisicing elit. Quam accusamus eos quibusdam, esse voluptates voluptatibus id corporis facere neque amet alias molestias itaque ex porro architecto blanditiis distinctio maxime laboriosam. 24 |