├── database
├── .gitignore
├── seeds
│ ├── SalesTableSeeder.php
│ ├── UserTableSeeder.php
│ ├── FileCategoryTableSeeder.php
│ ├── FileUploadsTableSeeder.php
│ ├── FilesTableSeeder.php
│ └── DatabaseSeeder.php
├── migrations
│ ├── 2017_11_17_233343_create_roles_table.php
│ ├── 2018_01_09_220606_create_images_table.php
│ ├── 2018_01_22_045328_create_categories_table.php
│ ├── 2014_10_12_100000_create_password_resets_table.php
│ ├── 2018_01_01_233358_add_stripe_connect_columns_to_user_table.php
│ ├── 2018_01_23_153819_create_notifications_table.php
│ ├── 2017_11_17_233726_create_user_role_table.php
│ ├── 2018_01_12_204240_create_comments_table.php
│ ├── 2018_01_22_045422_create_category_file_table.php
│ ├── 2014_10_12_000000_create_users_table.php
│ ├── 2017_10_29_002256_create_file_approvals_table.php
│ ├── 2017_10_29_171614_create_uploads_table.php
│ ├── 2017_12_24_001756_create_sales_table.php
│ └── 2017_10_21_232741_create_files_table.php
└── factories
│ ├── FileCategoryFactory.php
│ ├── UploadFactory.php
│ ├── UserFactory.php
│ ├── SaleFactory.php
│ └── FileFactory.php
├── bootstrap
├── cache
│ └── .gitignore
└── app.php
├── storage
├── debugbar
│ └── .gitignore
├── logs
│ └── .gitignore
├── app
│ ├── public
│ │ └── .gitignore
│ └── .gitignore
└── framework
│ ├── cache
│ └── .gitignore
│ ├── testing
│ └── .gitignore
│ ├── views
│ └── .gitignore
│ ├── sessions
│ └── .gitignore
│ └── .gitignore
├── public
├── robots.txt
├── favicon.ico
├── images
│ ├── home
│ │ ├── default.png
│ │ ├── dashboard.JPG
│ │ ├── watermark.png
│ │ ├── multiple-select.png
│ │ └── process
│ │ │ ├── create-files.svg
│ │ │ ├── profits.svg
│ │ │ ├── publish.svg
│ │ │ ├── one.svg
│ │ │ ├── signup.svg
│ │ │ ├── connect-stripe.svg
│ │ │ ├── four.svg
│ │ │ ├── two.svg
│ │ │ ├── three.svg
│ │ │ └── five.svg
│ └── icons
│ │ ├── favicon-16x16.png
│ │ ├── favicon-32x32.png
│ │ ├── favicon-128x128.png
│ │ ├── marketplace-logo.png
│ │ └── avatar.svg
├── fonts
│ └── vendor
│ │ └── bootstrap-sass
│ │ └── bootstrap
│ │ ├── glyphicons-halflings-regular.eot
│ │ ├── glyphicons-halflings-regular.ttf
│ │ ├── glyphicons-halflings-regular.woff
│ │ └── glyphicons-halflings-regular.woff2
├── mix-manifest.json
├── .htaccess
├── web.config
└── index.php
├── Procfile
├── .travis.yml
├── config
├── marketplace.php
├── image.php
├── sentry.php
├── view.php
├── services.php
├── broadcasting.php
└── filesystems.php
├── .gitattributes
├── app
├── Role.php
├── Category.php
├── Http
│ ├── Middleware
│ │ ├── EncryptCookies.php
│ │ ├── VerifyCsrfToken.php
│ │ ├── TrimStrings.php
│ │ ├── AbortIfNotAdmin.php
│ │ ├── Admin
│ │ │ └── Impersonate.php
│ │ ├── RedirectIfMarketplaceConnected.php
│ │ ├── RedirectIfAuthenticated.php
│ │ ├── RedirectIfMarketplaceNotConnected.php
│ │ └── TrustProxies.php
│ ├── Controllers
│ │ ├── Controller.php
│ │ ├── Api
│ │ │ └── FileController.php
│ │ ├── HomeController.php
│ │ ├── Admin
│ │ │ ├── PreviewFileController.php
│ │ │ ├── FileController.php
│ │ │ ├── CategoriesController.php
│ │ │ └── AdminController.php
│ │ ├── Auth
│ │ │ ├── ForgotPasswordController.php
│ │ │ ├── LoginController.php
│ │ │ └── ResetPasswordController.php
│ │ ├── Account
│ │ │ ├── EmailController.php
│ │ │ ├── AvatarController.php
│ │ │ ├── DatabaseNotificationsController.php
│ │ │ └── MarketPlaceConnectController.php
│ │ └── Checkout
│ │ │ └── CheckoutController.php
│ ├── Resources
│ │ └── FilesCollection.php
│ ├── ViewComposers
│ │ ├── AdminStatsComposer.php
│ │ └── AccountStatsComposer.php
│ └── Requests
│ │ ├── File
│ │ └── UpdateFileRequest.php
│ │ ├── Account
│ │ ├── UpdateSettingsRequest.php
│ │ ├── PasswordStoreRequest.php
│ │ └── StoreAvatarFormRequest.php
│ │ ├── Checkout
│ │ └── FreeCheckoutRequest.php
│ │ └── Category
│ │ └── FileCategoryRequest.php
├── Policies
│ ├── UploadPolicy.php
│ └── FilePolicy.php
├── Listeners
│ └── Checkout
│ │ └── SendEmailToBuyer.php
├── Providers
│ ├── BroadcastServiceProvider.php
│ ├── AppServiceProvider.php
│ ├── PaymentGatewayServiceProvider.php
│ ├── RoleServiceProvider.php
│ ├── AuthServiceProvider.php
│ ├── EventServiceProvider.php
│ ├── ComposerServiceProvider.php
│ └── RouteServiceProvider.php
├── Events
│ └── Checkout
│ │ └── SaleCreated.php
├── Image.php
├── Traits
│ ├── HasApprovals.php
│ └── HasRoles.php
├── Rules
│ ├── CurrentPassword.php
│ └── Recaptcha.php
├── Mail
│ └── Checkout
│ │ └── SaleConfirmationToBuyer.php
├── Console
│ └── Kernel.php
├── helpers.php
├── Notifications
│ ├── PasswordChanged.php
│ ├── FileChanges.php
│ ├── UpdatedFileApproved.php
│ ├── FileApproved.php
│ ├── EmailVerification.php
│ ├── FileRejected.php
│ └── UpdatedFileRejection.php
├── Comment.php
├── FileApproval.php
├── Exceptions
│ └── Handler.php
├── Upload.php
├── Jobs
│ └── Checkout
│ │ └── CreateSale.php
└── Sale.php
├── after.sh
├── .gitignore
├── tests
├── TestCase.php
├── Unit
│ └── ExampleTest.php
├── Feature
│ └── ExampleTest.php
└── CreatesApplication.php
├── nginx.conf
├── resources
├── views
│ ├── admin
│ │ ├── files
│ │ │ ├── new
│ │ │ │ ├── index.blade.php
│ │ │ │ └── rejection.blade.php
│ │ │ └── updated
│ │ │ │ ├── index.blade.php
│ │ │ │ └── rejection.blade.php
│ │ ├── layouts
│ │ │ └── default.blade.php
│ │ ├── partials
│ │ │ ├── _file_to_approve.blade.php
│ │ │ ├── _file_updated_to_approve.blade.php
│ │ │ ├── _stats.blade.php
│ │ │ └── _navigation.blade.php
│ │ ├── categories
│ │ │ ├── index.blade.php
│ │ │ ├── create.blade.php
│ │ │ └── edit.blade.php
│ │ └── users
│ │ │ └── index.blade.php
│ ├── account
│ │ ├── files
│ │ │ ├── index.blade.php
│ │ │ └── notify
│ │ │ │ └── index.blade.php
│ │ ├── partials
│ │ │ ├── _email_verification.blade.php
│ │ │ └── _file.blade.php
│ │ ├── layouts
│ │ │ ├── default.blade.php
│ │ │ └── _stats.blade.php
│ │ ├── marketplace
│ │ │ └── index.blade.php
│ │ ├── notifications
│ │ │ ├── show.blade.php
│ │ │ ├── index.blade.php
│ │ │ └── all-notifications.blade.php
│ │ ├── bought
│ │ │ └── index.blade.php
│ │ └── password
│ │ │ └── index.blade.php
│ ├── layouts
│ │ ├── plain.blade.php
│ │ ├── partials
│ │ │ ├── _flash.blade.php
│ │ │ ├── _scripts.blade.php
│ │ │ └── _footer.blade.php
│ │ ├── app.blade.php
│ │ └── home.blade.php
│ ├── files
│ │ ├── partials
│ │ │ ├── _checkout_form_free.blade.php
│ │ │ └── _checkout_form.blade.php
│ │ └── index.blade.php
│ ├── emails
│ │ ├── checkout
│ │ │ └── confirmation.blade.php
│ │ └── layouts
│ │ │ └── default.blade.php
│ ├── vendor
│ │ └── notifications
│ │ │ └── email.blade.php
│ └── auth
│ │ └── passwords
│ │ └── email.blade.php
├── lang
│ └── en
│ │ ├── pagination.php
│ │ ├── auth.php
│ │ └── passwords.php
└── assets
│ ├── js
│ ├── app.js
│ ├── components
│ │ ├── files
│ │ │ ├── partials
│ │ │ │ └── File.vue
│ │ │ └── Index.vue
│ │ └── AvatarUpload.vue
│ └── bootstrap.js
│ └── sass
│ └── _variables.scss
├── routes
├── channels.php
├── console.php
└── api.php
├── server.php
├── .env.example
├── webpack.mix.js
├── phpunit.xml
├── package.json
├── Vagrantfile
├── artisan
└── composer.json
/database/.gitignore:
--------------------------------------------------------------------------------
1 | *.sqlite
2 |
--------------------------------------------------------------------------------
/bootstrap/cache/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/storage/debugbar/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
--------------------------------------------------------------------------------
/storage/logs/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | User-agent: *
2 | Disallow:
3 |
--------------------------------------------------------------------------------
/storage/app/public/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/storage/app/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !public/
3 | !.gitignore
4 |
--------------------------------------------------------------------------------
/storage/framework/cache/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/storage/framework/testing/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/storage/framework/views/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/storage/framework/sessions/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/Procfile:
--------------------------------------------------------------------------------
1 | web: $(composer config bin-dir)/heroku-php-nginx -C nginx.conf public/
2 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/davidtrushkov/marketplace/HEAD/public/favicon.ico
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: php
2 | php:
3 | - '7.0'
4 | before_script:
5 | - composer install
6 |
7 | script: phpunit
--------------------------------------------------------------------------------
/public/images/home/default.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/davidtrushkov/marketplace/HEAD/public/images/home/default.png
--------------------------------------------------------------------------------
/config/marketplace.php:
--------------------------------------------------------------------------------
1 | [
5 | 'commission' => 20,
6 | 'remaining' => 80
7 | ]
8 | ];
--------------------------------------------------------------------------------
/public/images/home/dashboard.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/davidtrushkov/marketplace/HEAD/public/images/home/dashboard.JPG
--------------------------------------------------------------------------------
/public/images/home/watermark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/davidtrushkov/marketplace/HEAD/public/images/home/watermark.png
--------------------------------------------------------------------------------
/public/images/home/multiple-select.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/davidtrushkov/marketplace/HEAD/public/images/home/multiple-select.png
--------------------------------------------------------------------------------
/public/images/icons/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/davidtrushkov/marketplace/HEAD/public/images/icons/favicon-16x16.png
--------------------------------------------------------------------------------
/public/images/icons/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/davidtrushkov/marketplace/HEAD/public/images/icons/favicon-32x32.png
--------------------------------------------------------------------------------
/public/images/icons/favicon-128x128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/davidtrushkov/marketplace/HEAD/public/images/icons/favicon-128x128.png
--------------------------------------------------------------------------------
/public/images/icons/marketplace-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/davidtrushkov/marketplace/HEAD/public/images/icons/marketplace-logo.png
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto
2 | *.css linguist-vendored
3 | *.scss linguist-vendored
4 | *.js linguist-vendored
5 | CHANGELOG.md export-ignore
6 |
--------------------------------------------------------------------------------
/config/image.php:
--------------------------------------------------------------------------------
1 | [
5 | 'relative' => public_path($relative = 'images/avatar'),
6 | 'absolute' => $relative
7 | ]
8 | ];
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/app/Role.php:
--------------------------------------------------------------------------------
1 | create();
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/public/mix-manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "/js/app.js": "/js/app.js",
3 | "/css/app.css": "/css/app.css",
4 | "/js/plugins/multiple-select.js": "/js/plugins/multiple-select.js",
5 | "/css/plugins/multiple-select.css": "/css/plugins/multiple-select.css"
6 | }
--------------------------------------------------------------------------------
/nginx.conf:
--------------------------------------------------------------------------------
1 | location / {
2 | # try to serve file directly, fallback to rewrite
3 | try_files $uri @rewriteapp;
4 | }
5 |
6 | location @rewriteapp {
7 | # rewrite all to app.php
8 | rewrite ^(.*)$ /index.php$1 last;
9 | }
10 |
11 | client_max_body_size 100m;
--------------------------------------------------------------------------------
/app/Category.php:
--------------------------------------------------------------------------------
1 | belongsToMany(File::class);
13 | }
14 |
15 | }
--------------------------------------------------------------------------------
/resources/views/admin/files/new/index.blade.php:
--------------------------------------------------------------------------------
1 | @extends('admin.layouts.default')
2 |
3 | @section('admin.content')
4 | @if($files->count())
5 | @each('admin.partials._file_to_approve', $files, 'file')
6 | @else
7 |
There are no new files waiting for approval.
8 | @endif
9 | @endsection
--------------------------------------------------------------------------------
/resources/views/admin/files/updated/index.blade.php:
--------------------------------------------------------------------------------
1 | @extends('admin.layouts.default')
2 |
3 | @section('admin.content')
4 | @if($files->count())
5 | @each('admin.partials._file_updated_to_approve', $files, 'file')
6 | @else
7 | There are no updated files waiting for approval.
8 | @endif
9 | @endsection
--------------------------------------------------------------------------------
/database/seeds/UserTableSeeder.php:
--------------------------------------------------------------------------------
1 | create();
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/database/seeds/FileCategoryTableSeeder.php:
--------------------------------------------------------------------------------
1 | create();
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/database/seeds/FileUploadsTableSeeder.php:
--------------------------------------------------------------------------------
1 | create();
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/resources/views/account/files/index.blade.php:
--------------------------------------------------------------------------------
1 | @extends('account.layouts.default')
2 |
3 | @section('account.content')
4 |
5 | @if($files->count())
6 | @each('account.partials._file', $files, 'file')
7 | @else
8 |
You have no files.
9 | @endif
10 |
11 | @endsection
--------------------------------------------------------------------------------
/config/sentry.php:
--------------------------------------------------------------------------------
1 | env('SENTRY_DSN'),
5 |
6 | // capture release as git sha
7 | // 'release' => trim(exec('git log --pretty="%h" -n1 HEAD')),
8 |
9 | // Capture bindings on SQL queries
10 | 'breadcrumbs.sql_bindings' => true,
11 |
12 | // Capture default user context
13 | 'user_context' => true,
14 | );
15 |
--------------------------------------------------------------------------------
/app/Http/Middleware/EncryptCookies.php:
--------------------------------------------------------------------------------
1 | create();
16 | factory(App\Comment::class, 400)->create();
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/resources/views/layouts/plain.blade.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | @include('layouts.partials._head')
5 |
6 |
7 |
8 |
9 | @include('layouts.partials._navigation')
10 | @yield('content')
11 |
12 |
13 | @include('layouts.partials._footer')
14 | @include('layouts.partials._scripts')
15 |
16 |
17 |
--------------------------------------------------------------------------------
/tests/Unit/ExampleTest.php:
--------------------------------------------------------------------------------
1 | assertTrue(true);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/app/Policies/UploadPolicy.php:
--------------------------------------------------------------------------------
1 | id == $upload->user_id;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/app/Http/Middleware/VerifyCsrfToken.php:
--------------------------------------------------------------------------------
1 | readyToBeShown()->paginate(self::PERPAGE));
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/tests/Feature/ExampleTest.php:
--------------------------------------------------------------------------------
1 | get('/');
18 |
19 | $response->assertStatus(200);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/app/Listeners/Checkout/SendEmailToBuyer.php:
--------------------------------------------------------------------------------
1 | sale->buyer_email)->send(new SaleConfirmationToBuyer($event->sale));
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/app/Http/Controllers/HomeController.php:
--------------------------------------------------------------------------------
1 | make(Kernel::class)->bootstrap();
19 |
20 | return $app;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/app/Providers/BroadcastServiceProvider.php:
--------------------------------------------------------------------------------
1 | sale = $sale;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/Image.php:
--------------------------------------------------------------------------------
1 | path;
17 | }
18 |
19 |
20 | /**
21 | * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
22 | */
23 | public function user() {
24 | return $this->belongsTo(User::class);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/Http/Middleware/AbortIfNotAdmin.php:
--------------------------------------------------------------------------------
1 | user()->hasRole('admin')) {
19 | return abort(404);
20 | }
21 | return $next($request);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/app/Policies/FilePolicy.php:
--------------------------------------------------------------------------------
1 | id == $file->user_id;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/app/Http/ViewComposers/AdminStatsComposer.php:
--------------------------------------------------------------------------------
1 | with([
18 | 'fileCount' => File::finished()->approved()->count(),
19 | 'saleCount' => Sale::count(),
20 | 'lifetimeCommission' => Sale::lifetimeCommission(),
21 | 'thisMonthCommission' => Sale::commissionThisMonth()
22 | ]);
23 | }
24 | }
--------------------------------------------------------------------------------
/app/Http/Middleware/Admin/Impersonate.php:
--------------------------------------------------------------------------------
1 | has('impersonate')) {
19 | \Auth::onceUsingId(session('impersonate'));
20 | }
21 |
22 | return $next($request);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/routes/channels.php:
--------------------------------------------------------------------------------
1 | id === (int) $id;
16 | });
17 |
--------------------------------------------------------------------------------
/app/Providers/AppServiceProvider.php:
--------------------------------------------------------------------------------
1 | ''
23 | ]);
24 | }
25 |
26 | public function messages() {
27 | return parent::messages();
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/resources/lang/en/pagination.php:
--------------------------------------------------------------------------------
1 | '« Previous',
17 | 'next' => 'Next »',
18 |
19 | ];
20 |
--------------------------------------------------------------------------------
/routes/console.php:
--------------------------------------------------------------------------------
1 | comment(Inspiring::quote());
18 | })->describe('Display an inspiring quote');
19 |
--------------------------------------------------------------------------------
/app/Traits/HasApprovals.php:
--------------------------------------------------------------------------------
1 | where('approved', true);
12 | }
13 |
14 |
15 | public function scopeUnapproved(Builder $builder) {
16 | return $builder->where('approved', false);
17 | }
18 |
19 |
20 | public function scopeWithoutPreviewFiles(Builder $builder) {
21 | return $builder->where('preview', false);
22 | }
23 |
24 | public function scopeWithPreviewFiles(Builder $builder) {
25 | return $builder->where('preview', true);
26 | }
27 | }
--------------------------------------------------------------------------------
/resources/views/layouts/partials/_flash.blade.php:
--------------------------------------------------------------------------------
1 | @if(session()->has('success'))
2 |
3 | ×
4 | {{ session('success') }}
5 |
6 | @endif
7 |
8 | @if(session()->has('error'))
9 |
10 | ×
11 | {{ session('error') }}
12 |
13 | @endif
--------------------------------------------------------------------------------
/app/Providers/PaymentGatewayServiceProvider.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 |
--------------------------------------------------------------------------------
/app/Http/Middleware/RedirectIfMarketplaceConnected.php:
--------------------------------------------------------------------------------
1 | user()->stripe_id) {
20 | return redirect()->route('account');
21 | }
22 |
23 | return $next($request);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/routes/api.php:
--------------------------------------------------------------------------------
1 | get('/user', function (Request $request) {
17 | return $request->user();
18 | });
19 |
20 | //Route::get('/files', 'Api\FileController@index');
21 |
--------------------------------------------------------------------------------
/app/Http/Middleware/RedirectIfAuthenticated.php:
--------------------------------------------------------------------------------
1 | check()) {
21 | return redirect('/home');
22 | }
23 |
24 | return $next($request);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/Http/Middleware/RedirectIfMarketplaceNotConnected.php:
--------------------------------------------------------------------------------
1 | user()->stripe_id) {
20 | return redirect()->route('account.connect');
21 | }
22 |
23 | return $next($request);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/public/.htaccess:
--------------------------------------------------------------------------------
1 |
2 |
3 | Options -MultiViews
4 |
5 |
6 | RewriteEngine On
7 |
8 | # Redirect Trailing Slashes If Not A Folder...
9 | RewriteCond %{REQUEST_FILENAME} !-d
10 | RewriteCond %{REQUEST_URI} (.+)/$
11 | RewriteRule ^ %1 [L,R=301]
12 |
13 | # Handle Front Controller...
14 | RewriteCond %{REQUEST_FILENAME} !-d
15 | RewriteCond %{REQUEST_FILENAME} !-f
16 | RewriteRule ^ index.php [L]
17 |
18 | # Handle Authorization Header
19 | RewriteCond %{HTTP:Authorization} .
20 | RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
21 |
22 |
--------------------------------------------------------------------------------
/app/Http/Requests/Account/UpdateSettingsRequest.php:
--------------------------------------------------------------------------------
1 | user();
27 |
28 | return [
29 | 'name' => 'required|string|max:25|unique:users,name,'.$user->id,
30 | ];
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/app/Http/Requests/Checkout/FreeCheckoutRequest.php:
--------------------------------------------------------------------------------
1 | 'required|email'
28 | ];
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/app/Traits/HasRoles.php:
--------------------------------------------------------------------------------
1 | belongsToMany(Role::class, 'user_role');
15 | }
16 |
17 |
18 | /**
19 | * Check if the current user is attached to any roles in the 'roles' table.
20 | * If not, return false, else, return true.
21 | * @param $role
22 | *
23 | * @return bool
24 | */
25 | public function hasRole($role) {
26 | if (!$this->roles->contains('name', $role)) {
27 | return false;
28 | }
29 |
30 | return true;
31 | }
32 |
33 | }
--------------------------------------------------------------------------------
/app/Providers/RoleServiceProvider.php:
--------------------------------------------------------------------------------
1 | check() && auth()->user()->hasRole($role);
19 | });
20 | }
21 |
22 | /**
23 | * Register the application services.
24 | *
25 | * @return void
26 | */
27 | public function register()
28 | {
29 | //
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/resources/lang/en/auth.php:
--------------------------------------------------------------------------------
1 | 'These credentials do not match our records.',
17 | 'throttle' => 'Too many login attempts. Please try again in :seconds seconds.',
18 |
19 | ];
20 |
--------------------------------------------------------------------------------
/resources/views/files/partials/_checkout_form_free.blade.php:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/images/home/process/create-files.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/Http/Requests/Category/FileCategoryRequest.php:
--------------------------------------------------------------------------------
1 | id);
28 |
29 | return [
30 | 'name' => 'required|string|max:25|unique:categories,name,'.$category->id,
31 | ];
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/resources/views/account/partials/_email_verification.blade.php:
--------------------------------------------------------------------------------
1 | @if(auth()->user()->isVerified())
2 |
3 |
4 |
Please verify your email address.
5 |
6 |
13 |
14 |
15 | @endif
--------------------------------------------------------------------------------
/.env.example:
--------------------------------------------------------------------------------
1 | APP_NAME=Marketplace
2 | APP_ENV=local
3 | APP_KEY=
4 | APP_DEBUG=true
5 | APP_LOG_LEVEL=debug
6 | APP_URL=http://localhost
7 |
8 | DB_CONNECTION=mysql
9 | DB_HOST=127.0.0.1
10 | DB_PORT=
11 | DB_DATABASE=
12 | DB_USERNAME=
13 | DB_PASSWORD=
14 |
15 | BROADCAST_DRIVER=log
16 | CACHE_DRIVER=file
17 | SESSION_DRIVER=file
18 | QUEUE_DRIVER=sync
19 |
20 | REDIS_HOST=127.0.0.1
21 | REDIS_PASSWORD=null
22 | REDIS_PORT=6379
23 |
24 | MAIL_DRIVER=smtp
25 | MAIL_HOST=smtp.mailtrap.io
26 | MAIL_PORT=2525
27 | MAIL_USERNAME=null
28 | MAIL_PASSWORD=null
29 | MAIL_ENCRYPTION=null
30 |
31 | PUSHER_APP_ID=
32 | PUSHER_APP_KEY=
33 | PUSHER_APP_SECRET=
34 |
35 | SENTRY_DSN=
36 |
37 | STRIPE_KEY=
38 | STRIPE_SECRET=
39 | STRIPE_CONNECT_KEY=
40 |
41 | RECAPTCHA_SECRET=
42 |
--------------------------------------------------------------------------------
/database/migrations/2017_11_17_233343_create_roles_table.php:
--------------------------------------------------------------------------------
1 | increments('id');
18 | $table->string('name');
19 | });
20 | }
21 |
22 | /**
23 | * Reverse the migrations.
24 | *
25 | * @return void
26 | */
27 | public function down()
28 | {
29 | Schema::dropIfExists('roles');
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/app/Rules/CurrentPassword.php:
--------------------------------------------------------------------------------
1 | user()->password);
21 | }
22 |
23 | /**
24 | * Get the validation error message.
25 | *
26 | * @return string
27 | */
28 | public function message()
29 | {
30 | return 'Your current password you entered is incorrect.';
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/resources/views/emails/checkout/confirmation.blade.php:
--------------------------------------------------------------------------------
1 | @extends('emails.layouts.default')
2 |
3 | @section('content')
4 |
5 |
6 |
7 |
8 |
9 |
10 | Thanks for downloading: {{ $sale->file->title }} from Marketplace
11 |
12 |
13 |
14 | Download your file
15 |
16 |
17 |
18 | Or, copy and paste this into your browser.
19 | {{ route('files.download', [$sale->file, $sale]) }}
20 |
21 | @endsection
--------------------------------------------------------------------------------
/app/Providers/AuthServiceProvider.php:
--------------------------------------------------------------------------------
1 | 'App\Policies\FilePolicy',
17 | 'App\Upload' => 'App\Policies\UploadPolicy',
18 | ];
19 |
20 | /**
21 | * Register any authentication / authorization services.
22 | *
23 | * @return void
24 | */
25 | public function boot()
26 | {
27 | $this->registerPolicies();
28 |
29 | //
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/app/Providers/EventServiceProvider.php:
--------------------------------------------------------------------------------
1 | [
17 | 'App\Listeners\Checkout\SendEmailToBuyer',
18 | ],
19 | ];
20 |
21 | /**
22 | * Register any events for your application.
23 | *
24 | * @return void
25 | */
26 | public function boot()
27 | {
28 | parent::boot();
29 |
30 | //
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/resources/views/admin/layouts/default.blade.php:
--------------------------------------------------------------------------------
1 | @extends('layouts.app')
2 |
3 | @section('content')
4 |
5 |
8 |
9 |
10 | @include('admin.partials._navigation')
11 |
12 |
13 | @include('layouts.partials._flash')
14 | @yield('admin.content')
15 |
16 |
17 |
20 |
21 | @endsection
--------------------------------------------------------------------------------
/public/images/home/process/profits.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/Http/Requests/Account/PasswordStoreRequest.php:
--------------------------------------------------------------------------------
1 | ['required', new CurrentPassword()],
29 | 'password' => 'required|min:6|max:16|confirmed',
30 | ];
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/app/Mail/Checkout/SaleConfirmationToBuyer.php:
--------------------------------------------------------------------------------
1 | sale = $sale;
26 | }
27 |
28 | /**
29 | * Build the message.
30 | *
31 | * @return $this
32 | */
33 | public function build()
34 | {
35 | return $this->subject('Your purchase confirmation')->view('emails.checkout.confirmation');
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/webpack.mix.js:
--------------------------------------------------------------------------------
1 | let 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 application. By default, we are compiling the Sass
10 | | file for the application as well as bundling up all the JS files.
11 | |
12 | */
13 |
14 | mix.js('resources/assets/js/app.js', 'public/js')
15 | .sass('resources/assets/sass/app.scss', 'public/css')
16 | .js('resources/assets/js/plugins/multiple-select.js', 'public/js/plugins/multiple-select.js');
17 |
18 | mix.styles([
19 | 'resources/assets/css/multiple-select.css',
20 | ], 'public/css/plugins/multiple-select.css');
--------------------------------------------------------------------------------
/app/Http/Middleware/TrustProxies.php:
--------------------------------------------------------------------------------
1 | 'FORWARDED',
24 | Request::HEADER_X_FORWARDED_FOR => 'X_FORWARDED_FOR',
25 | Request::HEADER_X_FORWARDED_HOST => 'X_FORWARDED_HOST',
26 | Request::HEADER_X_FORWARDED_PORT => 'X_FORWARDED_PORT',
27 | Request::HEADER_X_FORWARDED_PROTO => 'X_FORWARDED_PROTO',
28 | ];
29 | }
30 |
--------------------------------------------------------------------------------
/app/Providers/ComposerServiceProvider.php:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{ str_limit($file->overview_short, 150) }}
4 |
5 |
6 | Preview file
7 |
8 |
9 | Approve
10 |
11 |
12 |
16 |
17 |
18 | Reject
19 |
20 |
21 |
--------------------------------------------------------------------------------
/resources/views/account/layouts/default.blade.php:
--------------------------------------------------------------------------------
1 | @extends('layouts.app')
2 |
3 | @section('content')
4 |
5 |
8 |
9 | @include('account.partials._email_verification')
10 |
11 | @include('account.partials._navigation')
12 |
13 |
14 | @include('layouts.partials._flash')
15 | @yield('account.content')
16 |
17 |
18 |
21 |
22 | @endsection
--------------------------------------------------------------------------------
/database/migrations/2018_01_09_220606_create_images_table.php:
--------------------------------------------------------------------------------
1 | increments('id');
18 | $table->string('path');
19 | $table->integer('user_id')->nullable();
20 | $table->timestamps();
21 | });
22 | }
23 |
24 | /**
25 | * Reverse the migrations.
26 | *
27 | * @return void
28 | */
29 | public function down()
30 | {
31 | Schema::dropIfExists('images');
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/database/migrations/2018_01_22_045328_create_categories_table.php:
--------------------------------------------------------------------------------
1 | increments('id');
18 | $table->string('name', 25)->unique();
19 | $table->string('slug');
20 | $table->timestamps();
21 | });
22 | }
23 |
24 | /**
25 | * Reverse the migrations.
26 | *
27 | * @return void
28 | */
29 | public function down()
30 | {
31 | Schema::dropIfExists('categories');
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/resources/views/admin/partials/_file_updated_to_approve.blade.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
{{ str_limit($file->overview_short, 150) }}
4 |
5 |
6 | Preview changes
7 |
8 |
9 | Approve
10 |
11 |
12 |
16 |
17 |
18 | Reject
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/resources/views/layouts/partials/_scripts.blade.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/resources/lang/en/passwords.php:
--------------------------------------------------------------------------------
1 | 'Passwords must be at least six characters and match the confirmation.',
17 | 'reset' => 'Your password has been reset!',
18 | 'sent' => 'We have e-mailed your password reset link!',
19 | 'token' => 'This password reset token is invalid.',
20 | 'user' => "We can't find a user with that e-mail address.",
21 |
22 | ];
23 |
--------------------------------------------------------------------------------
/resources/views/files/partials/_checkout_form.blade.php:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/Http/Requests/Account/StoreAvatarFormRequest.php:
--------------------------------------------------------------------------------
1 | 'image|max:2048'
28 | ];
29 | }
30 |
31 | public function messages() {
32 | return [
33 | 'avatar.image' => 'Not a valid image.',
34 | 'avatar.max' => 'Maximum size of image can only be 2MB.'
35 | ];
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/database/migrations/2018_01_01_233358_add_stripe_connect_columns_to_user_table.php:
--------------------------------------------------------------------------------
1 | string('stripe_id')->nullable();
18 | $table->string('stripe_key')->nullable();
19 | });
20 | }
21 |
22 | /**
23 | * Reverse the migrations.
24 | *
25 | * @return void
26 | */
27 | public function down()
28 | {
29 | Schema::table('users', function (Blueprint $table) {
30 | $table->dropColumn('stripe_id', 'stripe_key');
31 | });
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/app/Http/ViewComposers/AccountStatsComposer.php:
--------------------------------------------------------------------------------
1 | user();
17 |
18 | // Grab user sales.
19 | $sales = $user->sales;
20 |
21 | // Grab user files that are 'finished'.
22 | // -- "finished" scope on 'File' model
23 | $files = $user->files()->finished();
24 |
25 | // Grab the sales earned overall for this authenticated user.
26 | // -- "saleValueOverLifetime" coming from 'User' model.
27 | $lifetimeEarned = $user->saleValueOverLifetime();
28 |
29 | $view->with([
30 | 'fileCount' => $files->count(),
31 | 'saleCount' => $sales->count(),
32 | 'thisMonthEarned' => $user->saleValueThisMonth(),
33 | 'lifetimeEarned' => $lifetimeEarned
34 | ]);
35 | }
36 | }
--------------------------------------------------------------------------------
/app/Rules/Recaptcha.php:
--------------------------------------------------------------------------------
1 | post('https://www.google.com/recaptcha/api/siteverify', [
21 | 'secret' => config('services.recaptcha.secret'),
22 | 'response' => $value,
23 | 'remoteip' => request()->ip()
24 | ]);
25 |
26 | return $response->json()['success'];
27 | }
28 |
29 |
30 | /**
31 | * Get the validation error message.
32 | *
33 | * @return string
34 | */
35 | public function message()
36 | {
37 | return 'The recaptcha verification failed. Try again..';
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/database/migrations/2018_01_23_153819_create_notifications_table.php:
--------------------------------------------------------------------------------
1 | uuid('id')->primary();
18 | $table->string('type');
19 | $table->morphs('notifiable');
20 | $table->text('data');
21 | $table->timestamp('read_at')->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('notifications');
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/database/migrations/2017_11_17_233726_create_user_role_table.php:
--------------------------------------------------------------------------------
1 | integer('user_id')->unsigned()->index();
18 | $table->integer('role_id')->unsigned();
19 | $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
20 | $table->foreign('role_id')->references('id')->on('roles')->onDelete('cascade');
21 | });
22 | }
23 |
24 | /**
25 | * Reverse the migrations.
26 | *
27 | * @return void
28 | */
29 | public function down()
30 | {
31 | Schema::dropIfExists('user_role');
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Admin/PreviewFileController.php:
--------------------------------------------------------------------------------
1 | visible() ) {
22 | return abort( 404 );
23 | }
24 |
25 | $fileUploads = $file->uploads()->withoutPreviewFiles()->latest()->get();
26 |
27 | $uploadPreviews = $file->uploads()->withPreviewFiles()->latest()->get();
28 |
29 | $updatedChanges = $approvals = $file->approvals->first();
30 |
31 | return view( 'admin.previews.index', compact('file', 'fileUploads', 'uploadPreviews', 'updatedChanges'));
32 | }
33 |
34 | }
--------------------------------------------------------------------------------
/public/web.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Auth/ForgotPasswordController.php:
--------------------------------------------------------------------------------
1 | middleware('guest');
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/database/factories/FileCategoryFactory.php:
--------------------------------------------------------------------------------
1 | define(App\Category::class, function (Faker $faker) {
17 | return [
18 | 'name' => $slug = $faker->unique()->randomElement($array = array ('Code', 'Templates', 'Photoshop', 'Images', 'Graphics', 'Icons', 'Fonts')),
19 | 'slug' => str_slug($slug),
20 | 'created_at' =>$faker->dateTimeBetween($startDate = '-2 years', $endDate = 'now', $timezone = null),
21 | 'updated_at' =>$faker->dateTimeBetween($startDate = '-2 years', $endDate = 'now', $timezone = null)
22 | ];
23 | });
24 |
--------------------------------------------------------------------------------
/public/images/home/process/publish.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Admin/FileController.php:
--------------------------------------------------------------------------------
1 | replaceFilePropertiesWithUnapprovedChanges($file);
20 |
21 | return view('files.show',[
22 | 'file' => $file,
23 | 'uploads' => $file->uploads
24 | ]);
25 | }
26 |
27 |
28 | /**
29 | * Get the unapproved changes made to the file
30 | * @param File $file
31 | *
32 | * @return File
33 | */
34 | protected function replaceFilePropertiesWithUnapprovedChanges(File $file) {
35 | if ($file->approvals->count()) {
36 | $file->fill($file->approvals->first()->toArray());
37 | }
38 |
39 | return $file;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/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/helpers.php:
--------------------------------------------------------------------------------
1 | user = $user;
21 | }
22 |
23 | /**
24 | * Get the notification's delivery channels.
25 | *
26 | * @param mixed $notifiable
27 | * @return array
28 | */
29 | public function via($notifiable) {
30 | return ['mail'];
31 | }
32 |
33 |
34 | public function toMail($notifiable) {
35 |
36 | $image = '/images/icons/password.svg';
37 | $imageAlt = 'Your password has been changed';
38 |
39 | return (new MailMessage)
40 | ->markdown('vendor.notifications.email', ['image' => $image, 'imageAlt' => $imageAlt])
41 | ->line('Your password has been changed successfully');
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/app/Comment.php:
--------------------------------------------------------------------------------
1 | morphTo();
17 | }
18 |
19 |
20 | /**
21 | * A comment belongs to a user.
22 | * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
23 | */
24 | public function user() {
25 | return $this->belongsTo(User::class);
26 | }
27 |
28 |
29 | /**
30 | * A comment has many replies, and references "parent_id"
31 | * @return \Illuminate\Database\Eloquent\Relations\HasMany
32 | */
33 | public function replies() {
34 | return $this->hasMany(Comment::class, 'parent_id');
35 | }
36 |
37 |
38 | /**
39 | * A 'parent' comment belongs to the "parent_id".
40 | * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
41 | */
42 | public function parent() {
43 | return $this->belongsTo(Comment::class, 'parent_id');
44 | }
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/database/migrations/2018_01_12_204240_create_comments_table.php:
--------------------------------------------------------------------------------
1 | increments('id');
18 | $table->integer('user_id')->unsigned()->index();
19 | $table->integer('parent_id')->unsigned()->index()->nullable();
20 | $table->text('body', 2500);
21 | $table->integer('commentable_id')->nullable();
22 | $table->string('commentable_type')->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('comments');
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/app/FileApproval.php:
--------------------------------------------------------------------------------
1 | file->approvals->each->delete();
35 | });
36 | }
37 |
38 |
39 | /**
40 | * An approval belongs to a file.
41 | * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
42 | */
43 | public function file() {
44 | return $this->belongsTo(File::class);
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/resources/views/admin/categories/index.blade.php:
--------------------------------------------------------------------------------
1 | @extends('admin.layouts.default')
2 |
3 | @section('admin.content')
4 |
5 |
9 |
10 |
11 |
12 |
13 | Name
14 |
15 |
16 |
17 |
18 | @foreach($categories as $category)
19 |
20 |
21 | {{ $category->name }}
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | @endforeach
30 |
31 |
32 |
33 | {{ $categories->render() }}
34 |
35 | @endsection
--------------------------------------------------------------------------------
/app/Http/Controllers/Auth/LoginController.php:
--------------------------------------------------------------------------------
1 | middleware('guest')->except('logout');
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/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' => realpath(storage_path('framework/views')),
32 |
33 | ];
34 |
--------------------------------------------------------------------------------
/database/migrations/2018_01_22_045422_create_category_file_table.php:
--------------------------------------------------------------------------------
1 | increments('id');
18 | $table->integer('category_id')->unsigned();
19 | $table->integer('file_id')->unsigned();
20 | $table->foreign('category_id')->references('id')->on('categories')->onUpdate('cascade')->onDelete('cascade');
21 | $table->foreign('file_id')->references('id')->on('files')->onUpdate('cascade')->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('category_file');
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Auth/ResetPasswordController.php:
--------------------------------------------------------------------------------
1 | middleware('guest');
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/phpunit.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
13 | ./tests/Feature
14 |
15 |
16 |
17 | ./tests/Unit
18 |
19 |
20 |
21 |
22 | ./app
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/database/migrations/2014_10_12_000000_create_users_table.php:
--------------------------------------------------------------------------------
1 | increments('id');
18 | $table->string('name', 25)->unique();
19 | $table->string('email')->unique();
20 | $table->string('password');
21 | $table->boolean('verified')->default(false);
22 | $table->string('token')->nullable();
23 | $table->string('avatar')->nullable();
24 | $table->boolean('user_notifications')->default(false);
25 | $table->rememberToken();
26 | $table->timestamps();
27 | });
28 | }
29 |
30 | /**
31 | * Reverse the migrations.
32 | *
33 | * @return void
34 | */
35 | public function down()
36 | {
37 | Schema::dropIfExists('users');
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/database/seeds/DatabaseSeeder.php:
--------------------------------------------------------------------------------
1 | insert([
15 | 'name' => 'admin'
16 | ]);
17 |
18 | DB::table('users')->insert([
19 | 'name' => 'David Trushkov',
20 | 'email' => 'davidisback4good@hotmail.com',
21 | 'password' => bcrypt('d16331633'),
22 | 'remember_token' => str_random(10),
23 | 'verified' => 1,
24 | 'token' => '',
25 | 'avatar' => '',
26 | 'created_at' => \Carbon\Carbon::now()->format('Y-m-d H:i:s'),
27 | 'updated_at' => \Carbon\Carbon::now()->format('Y-m-d H:i:s'),
28 | ]);
29 |
30 | DB::table('user_role')->insert([
31 | 'user_id' => 1,
32 | 'role_id' => 1
33 | ]);
34 |
35 | $this->call(UserTableSeeder::class);
36 | $this->call(FilesTableSeeder::class);
37 | $this->call(FileUploadsTableSeeder::class);
38 | $this->call(SalesTableSeeder::class);
39 | $this->call(FileCategoryTableSeeder::class);
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/resources/views/layouts/app.blade.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | @include('layouts.partials._head')
5 |
6 |
7 |
27 |
28 |
29 | @if (!in_array(Route::currentRouteName(), ['login', 'register']))
30 | @include('layouts.partials._navigation')
31 | @endif
32 |
33 | @yield('content')
34 |
35 |
36 | @include('layouts.partials._footer')
37 | @include('layouts.partials._scripts')
38 | @yield('scripts')
39 |
40 |
41 |
--------------------------------------------------------------------------------
/database/factories/UploadFactory.php:
--------------------------------------------------------------------------------
1 | define(App\Upload::class, function (Faker $faker) {
17 |
18 | $user_id = App\File::all()->random()->user_id;
19 |
20 | $file_id = \App\File::where('user_id', '=', $user_id)->first();
21 |
22 | return [
23 | 'user_id' => $user_id,
24 | 'file_id' => $file_id,
25 | 'filename' => $faker->image('public/images/fake',1000,700, null, false),
26 | 'size' => $faker->numberBetween($min = 1000, $max = 1000000),
27 | 'approved' => rand(0, 1),
28 | 'preview' => rand(0, 1),
29 | 'created_at' =>$faker->dateTimeBetween($startDate = '-2 years', $endDate = 'now', $timezone = null),
30 | 'updated_at' =>$faker->dateTimeBetween($startDate = '-2 years', $endDate = 'now', $timezone = null)
31 | ];
32 | });
--------------------------------------------------------------------------------
/database/migrations/2017_10_29_002256_create_file_approvals_table.php:
--------------------------------------------------------------------------------
1 | increments('id');
18 | $table->integer('file_id')->unsigned()->index();
19 | $table->foreign('file_id')->references('id')->on('files')->onDelete('cascade');
20 | $table->string('title');
21 | $table->string('overview_short', 300);
22 | $table->text('overview');
23 | $table->string('youtube_url')->nullable();
24 | $table->string('vimeo_url')->nullable();
25 | $table->softDeletes();
26 | $table->timestamps();
27 | });
28 | }
29 |
30 | /**
31 | * Reverse the migrations.
32 | *
33 | * @return void
34 | */
35 | public function down()
36 | {
37 | Schema::dropIfExists('file_approvals');
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/resources/assets/js/app.js:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | * First we will load all of this project's JavaScript dependencies which
4 | * includes Vue and other libraries. It is a great starting point when
5 | * building robust, powerful web applications using Vue and Laravel.
6 | */
7 |
8 | require('./bootstrap');
9 |
10 | window.Vue = require('vue');
11 |
12 | import VueRouter from 'vue-router'
13 | Vue.use(VueRouter)
14 |
15 | /**
16 | * Next, we will create a fresh Vue application instance and attach it to
17 | * the page. Then, you may begin adding components to this application
18 | * or customize the JavaScript scaffolding to fit your unique needs.
19 | */
20 |
21 | Vue.component('avatar-upload', require('./components/AvatarUpload.vue'));
22 |
23 | // const FileIndex = require('./components/files/Index.vue');
24 |
25 | // const routes = [
26 | // {
27 | // path: '/files',
28 | // name: 'files.index',
29 | // component: FileIndex
30 | // }
31 | // ];
32 | //
33 | //
34 | // const router = new VueRouter({
35 | // mode: 'history',
36 | // routes
37 | // });
38 |
39 | const app = new Vue({
40 | el: '#app',
41 | //router
42 | });
43 |
44 | $(function () {
45 | $('[data-toggle="tooltip"]').tooltip()
46 | })
--------------------------------------------------------------------------------
/database/factories/UserFactory.php:
--------------------------------------------------------------------------------
1 | define(App\User::class, function (Faker $faker) {
17 |
18 | static $password;
19 |
20 | return [
21 | 'name' => $faker->unique()->firstName,
22 | 'email' => $faker->unique()->safeEmail,
23 | 'password' => $password ?: $password = bcrypt('secret'),
24 | 'remember_token' => str_random(10),
25 | 'verified' => 1,
26 | 'token' => '',
27 | 'avatar' => $faker->image('public/images/avatars',1000,700, null, false),
28 | 'stripe_id' => '',
29 | 'stripe_key' => '',
30 | 'created_at' =>$faker->dateTimeBetween($startDate = '-2 years', $endDate = 'now', $timezone = null),
31 | 'updated_at' =>$faker->dateTimeBetween($startDate = '-2 years', $endDate = 'now', $timezone = null)
32 | ];
33 | });
--------------------------------------------------------------------------------
/public/images/home/process/one.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
8 |
10 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/config/services.php:
--------------------------------------------------------------------------------
1 | [
18 | 'domain' => env('MAILGUN_DOMAIN'),
19 | 'secret' => env('MAILGUN_SECRET'),
20 | ],
21 |
22 | 'ses' => [
23 | 'key' => env('SES_KEY'),
24 | 'secret' => env('SES_SECRET'),
25 | 'region' => 'us-east-1',
26 | ],
27 |
28 | 'sparkpost' => [
29 | 'secret' => env('SPARKPOST_SECRET'),
30 | ],
31 |
32 | 'stripe' => [
33 | 'model' => App\User::class,
34 | 'key' => env('STRIPE_KEY'),
35 | 'secret' => env('STRIPE_SECRET'),
36 | ],
37 |
38 | 'stripe_connect' => [
39 | 'key' => env('STRIPE_CONNECT_KEY'),
40 | ],
41 |
42 | 'recaptcha' => [
43 | 'secret' => env('RECAPTCHA_SECRET')
44 | ]
45 | ];
46 |
--------------------------------------------------------------------------------
/resources/views/account/partials/_file.blade.php:
--------------------------------------------------------------------------------
1 |
2 |
5 |
{{ str_limit($file->overview_short, 150) }}
6 |
7 |
8 | {{ $file->isFree() ? 'Free' : '$' . $file->price }}
9 |
10 | @if(!$file->approved)
11 |
12 | Pending approval
13 |
14 | @endif
15 |
16 |
17 | {{ $file->live ? 'Live' : 'Not Live' }}
18 |
19 |
20 | Make changes
21 |
22 |
{{ $file->sales->count() }} {{ str_plural('sale', $file->sales->count()) }}
23 | @if($file->sales->count() > 0)
24 |
25 | Send Notification Users
26 |
27 |
28 |
29 | Send Notification Users
30 |
31 | @endif
32 |
33 |
--------------------------------------------------------------------------------
/public/images/home/process/signup.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/views/layouts/home.blade.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | @include('layouts.partials._head')
5 |
6 | @if(Route::current()->getName() == 'home')
7 |
15 | @endif
16 |
17 |
18 |
19 |
39 |
40 |
41 | @include('layouts.partials._navigation')
42 |
43 | @yield('content')
44 |
45 |
46 | @include('layouts.partials._footer')
47 | @include('layouts.partials._scripts')
48 |
49 |
50 |
--------------------------------------------------------------------------------
/database/migrations/2017_10_29_171614_create_uploads_table.php:
--------------------------------------------------------------------------------
1 | increments('id');
18 | $table->integer('user_id')->unsigned()->index();
19 | $table->integer('file_id')->unsigned()->index();
20 | $table->string('filename');
21 | $table->bigInteger('size');
22 | $table->boolean('approved')->default(false);
23 | $table->boolean('preview')->default(false);
24 | $table->softDeletes();
25 | $table->timestamps();
26 |
27 | $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
28 | $table->foreign('file_id')->references('id')->on('files')->onDelete('cascade');
29 | });
30 | }
31 |
32 | /**
33 | * Reverse the migrations.
34 | *
35 | * @return void
36 | */
37 | public function down()
38 | {
39 | Schema::dropIfExists('uploads');
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/resources/views/admin/categories/create.blade.php:
--------------------------------------------------------------------------------
1 | @extends('admin.layouts.default')
2 |
3 | @section('admin.content')
4 |
5 |
32 |
33 | @endsection
--------------------------------------------------------------------------------
/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": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
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 --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
11 | },
12 | "devDependencies": {
13 | "axios": "^0.16.2",
14 | "bootstrap-sass": "^3.3.7",
15 | "cross-env": "^5.0.1",
16 | "jquery": "^3.1.1",
17 | "laravel-mix": "^1.0",
18 | "lodash": "^4.17.4",
19 | "vue": "^2.1.10"
20 | },
21 | "dependencies": {
22 | "dropzone": "^5.2.0",
23 | "hover.css": "^2.2.1",
24 | "trix": "^0.11.1",
25 | "vue-router": "^3.0.1"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Account/EmailController.php:
--------------------------------------------------------------------------------
1 | firstOrFail()->confirmEmail();
25 |
26 | \Auth::logout();
27 |
28 | // Flash a success message saying user has been confirmed.
29 | return redirect('/login')->withSuccess('You are now confirmed. You can now login.');
30 | }
31 |
32 |
33 | /**
34 | * Send a email verification code to user if they have not gotten the email when they registered.
35 | *
36 | * @return \Illuminate\Http\RedirectResponse
37 | */
38 | public function confirmEmailAgain() {
39 |
40 | $user = auth()->user();
41 |
42 | $user->notify(new EmailVerification($user));
43 |
44 | return back()->withSuccess('Email verification code sent to your email. Please check spam folder to.');
45 | }
46 |
47 | }
--------------------------------------------------------------------------------
/public/images/home/process/connect-stripe.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/views/emails/layouts/default.blade.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
22 |
23 |
24 |
25 |
26 |
29 |
30 |
31 | @yield('content')
32 |
33 |
Thanks, {{ config('app.name') }}
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/resources/views/admin/categories/edit.blade.php:
--------------------------------------------------------------------------------
1 | @extends('admin.layouts.default')
2 |
3 | @section('admin.content')
4 |
5 |
32 |
33 | @endsection
--------------------------------------------------------------------------------
/resources/views/admin/files/new/rejection.blade.php:
--------------------------------------------------------------------------------
1 | @extends('admin.layouts.default')
2 |
3 | @section('admin.content')
4 |
5 |
6 | Give a reason for rejecting this file so the user knows what to fix?
7 |
8 |
31 |
32 | @endsection
--------------------------------------------------------------------------------
/database/factories/SaleFactory.php:
--------------------------------------------------------------------------------
1 | define(App\Sale::class, function (Faker $faker) {
17 |
18 | $userId = \App\File::all()->random()->user_id;
19 |
20 | $fileId = \App\File::where('user_id', $userId)->first();
21 |
22 | $boughtUserId = App\User::all()->random()->id;
23 |
24 | $buyerEmail = App\User::where('id', $boughtUserId)->first();
25 |
26 | return [
27 | 'identifier' => uniqid(),
28 | 'user_id' => $userId,
29 | 'bought_user_id' => App\User::all()->random()->id,
30 | 'file_id' => $fileId->id,
31 | 'buyer_email' => $buyerEmail->email,
32 | 'sale_price' => $faker->randomFloat($nbMaxDecimals = 2, $min = 0, $max = 125),
33 | 'sale_commission' => $faker->randomFloat($nbMaxDecimals = 2, $min = 0, $max = 50),
34 | 'created_at' =>$faker->dateTimeBetween($startDate = '-2 years', $endDate = 'now', $timezone = null),
35 | 'updated_at' =>$faker->dateTimeBetween($startDate = '-2 years', $endDate = 'now', $timezone = null)
36 | ];
37 | });
--------------------------------------------------------------------------------
/resources/views/admin/files/updated/rejection.blade.php:
--------------------------------------------------------------------------------
1 | @extends('admin.layouts.default')
2 |
3 | @section('admin.content')
4 |
5 |
6 | Give a reason for rejecting this file so the user knows what to fix?
7 |
8 |
9 |
10 | {{ csrf_field() }}
11 |
12 |
13 | Reason for rejecting this file
14 | {{ old('data') }}
15 | @if ($errors->has('data'))
16 |
17 | {{ $errors->first('data') }}
18 |
19 | @endif
20 |
21 |
22 |
23 |
24 |
28 |
29 |
30 |
31 |
32 | @endsection
--------------------------------------------------------------------------------
/database/migrations/2017_12_24_001756_create_sales_table.php:
--------------------------------------------------------------------------------
1 | increments('id');
18 | $table->string('identifier')->unique();
19 | $table->integer('user_id')->unsigned()->index()->nullable();
20 | $table->integer('bought_user_id')->unsigned()->index()->nullable();
21 | $table->integer('file_id')->unsigned()->index()->nullable();
22 | $table->string('buyer_email');
23 | $table->decimal('sale_price', 6, 2);
24 | $table->decimal('sale_commission', 6, 2);
25 | $table->timestamps();
26 |
27 | $table->foreign('user_id')->references('id')->on('users')->onDelete('set null');
28 | $table->foreign('file_id')->references('id')->on('files')->onDelete('set null');
29 | $table->foreign('bought_user_id')->references('id')->on('users')->onDelete('set null');
30 | });
31 | }
32 |
33 | /**
34 | * Reverse the migrations.
35 | *
36 | * @return void
37 | */
38 | public function down()
39 | {
40 | Schema::dropIfExists('sales');
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/app/Notifications/FileChanges.php:
--------------------------------------------------------------------------------
1 | data = $data;
26 | $this->header = $header;
27 | $this->owner = $owner;
28 | $this->file = $file;
29 | }
30 |
31 |
32 | /**
33 | * Get the notification's delivery channels.
34 | *
35 | * @param mixed $notifiable
36 | * @return array
37 | */
38 | public function via($notifiable) {
39 | return ['database'];
40 | }
41 |
42 |
43 | /**
44 | * Get the array representation of the notification.
45 | *
46 | * @param mixed $notifiable
47 | * @return array
48 | */
49 | public function toArray($notifiable) {
50 | return [
51 | 'header' => isset($this->header) ? $this->header : 'File updated for: '.$this->file->title,
52 | 'data' => $this->data,
53 | 'file' => $this->file->title,
54 | 'slug' => $this->file->identifier,
55 | 'owner_avatar' => $this->owner->avatar,
56 | 'owner_name' => $this->owner->name
57 | ];
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/public/images/home/process/four.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
8 |
10 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/resources/views/account/layouts/_stats.blade.php:
--------------------------------------------------------------------------------
1 |
2 |
36 |
--------------------------------------------------------------------------------
/app/Exceptions/Handler.php:
--------------------------------------------------------------------------------
1 | bound('sentry') && $this->shouldReport($exception)) {
40 | app('sentry')->captureException($exception);
41 | }
42 |
43 | parent::report($exception);
44 | }
45 |
46 | /**
47 | * Render an exception into an HTTP response.
48 | *
49 | * @param \Illuminate\Http\Request $request
50 | * @param \Exception $exception
51 | * @return \Illuminate\Http\Response
52 | */
53 | public function render($request, Exception $exception)
54 | {
55 | return parent::render($request, $exception);
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/public/images/home/process/two.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
8 |
10 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/resources/views/admin/partials/_stats.blade.php:
--------------------------------------------------------------------------------
1 |
2 |
36 |
--------------------------------------------------------------------------------
/database/migrations/2017_10_21_232741_create_files_table.php:
--------------------------------------------------------------------------------
1 | increments('id');
18 | $table->string('identifier')->unique();
19 | $table->integer('user_id')->unsigned()->index();
20 | $table->string('title', 100);
21 | $table->string('overview_short', 300);
22 | $table->text('overview');
23 | $table->decimal('price', 6, 2);
24 | $table->boolean('live')->default(false);
25 | $table->boolean('approved')->default(false);
26 | $table->boolean('finished')->default(false);
27 | $table->string('avatar')->nullable();
28 | $table->string('youtube_url')->nullable();
29 | $table->string('vimeo_url')->nullable();
30 | $table->softDeletes();
31 | $table->timestamps();
32 |
33 | $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
34 | });
35 | }
36 |
37 | /**
38 | * Reverse the migrations.
39 | *
40 | * @return void
41 | */
42 | public function down()
43 | {
44 | Schema::dropIfExists('files');
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/app/Upload.php:
--------------------------------------------------------------------------------
1 | belongsTo(File::class);
28 | }
29 |
30 |
31 | /**
32 | * An upload belongs to a user.
33 | * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
34 | */
35 | public function user() {
36 | return $this->belongsTo(User::class);
37 | }
38 |
39 |
40 | /**
41 | * Access the full path of a filename
42 | * @return string
43 | */
44 | public function getPathAttribute() {
45 | return storage_path('app/files/' . $this->file->identifier . '/' . $this->filename);
46 | }
47 |
48 |
49 | /**
50 | * Convert file size into readable names.
51 | * @param $size
52 | * @param int $precision
53 | *
54 | * @return int|string
55 | */
56 | public static function formatBytes($size, $precision = 2) {
57 | if ($size > 0) {
58 | $size = (int) $size;
59 | $base = log($size) / log(1024);
60 | $suffixes = array(' bytes', ' KB', ' MB', ' GB', ' TB');
61 |
62 | return round(pow(1024, $base - floor($base)), $precision) . $suffixes[floor($base)];
63 | } else {
64 | return $size;
65 | }
66 | }
67 |
68 | }
69 |
--------------------------------------------------------------------------------
/app/Jobs/Checkout/CreateSale.php:
--------------------------------------------------------------------------------
1 | file = $file;
33 | $this->email = $email;
34 | }
35 |
36 |
37 | /**
38 | * Execute the job.
39 | *
40 | * @return void
41 | */
42 | public function handle()
43 | {
44 | $sale = new Sale;
45 |
46 | $isUser = auth()->user() ? auth()->user()->id : NULL;
47 |
48 | $sale->fill([
49 | 'identifier' => uniqid(true),
50 | 'bought_user_id' => $isUser,
51 | 'buyer_email' => $this->email,
52 | 'sale_price' => $this->file->price,
53 | 'sale_commission' => $this->file->calculateCommission()
54 | ]);
55 |
56 | $sale->file()->associate($this->file);
57 | $sale->user()->associate($this->file->user);
58 |
59 | $sale->save();
60 |
61 | // Fire a new event
62 | event(new SaleCreated($sale));
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/resources/views/account/marketplace/index.blade.php:
--------------------------------------------------------------------------------
1 | @extends('account.layouts.default')
2 |
3 | @section('account.content')
4 |
5 |
6 |
Please connect your Stripe account to start creating and selling files.
7 |
8 |
9 | In order for us to pay you out, you need to make an account with Stripe
10 | so you can receive the portion of your payment when someone buys your files.
11 | You can also sign into your existing account if you have one.
12 |
13 |
Connect your Stripe account
14 |
15 |
16 |
17 |
18 |
19 | ×
20 |
21 | This app is on a local environment. When you hit the "Connect your Stripe account" button above, you can make a Stripe account, login into Stripe, or just skip by clicking the
22 | "Skip this account form" on the top of the page.
23 |
24 |
25 | @endsection
--------------------------------------------------------------------------------
/public/images/home/process/three.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
8 |
10 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/resources/views/vendor/notifications/email.blade.php:
--------------------------------------------------------------------------------
1 | @component('mail::message', ['image' => $image, 'imageAlt' => $imageAlt])
2 |
3 | @isset($image)
4 |
5 |
6 |
7 | @endisset
8 |
9 | {{-- Greeting --}}
10 | @if (! empty($greeting))
11 | # {{ $greeting }}
12 | @else
13 | @if ($level == 'error')
14 | # Whoops!
15 | @else
16 | {{--# Hello!--}}
17 | @endif
18 | @endif
19 |
20 | {{-- Intro Lines --}}
21 | @foreach ($introLines as $line)
22 | {{ $line }}
23 |
24 | @endforeach
25 |
26 | {{-- Action Button --}}
27 | @isset($actionText)
28 |
40 | @component('mail::button', ['url' => $actionUrl, 'color' => $color])
41 | {{ $actionText }}
42 | @endcomponent
43 | @endisset
44 |
45 | {{-- Outro Lines --}}
46 | @foreach ($outroLines as $line)
47 | {{ $line }}
48 |
49 | @endforeach
50 |
51 | {{-- Salutation --}}
52 | @if (! empty($salutation))
53 | {{ $salutation }}
54 | @else
55 | Regards, {{ config('app.name') }}
56 | @endif
57 |
58 | {{-- Subcopy --}}
59 | @isset($actionText)
60 | @component('mail::subcopy')
61 | If you’re having trouble clicking the "{{ $actionText }}" button, copy and paste the URL below
62 | into your web browser: [{{ $actionUrl }}]({{ $actionUrl }})
63 | @endcomponent
64 | @endisset
65 | @endcomponent
66 |
--------------------------------------------------------------------------------
/Vagrantfile:
--------------------------------------------------------------------------------
1 | # -*- mode: ruby -*-
2 | # vi: set ft=ruby :
3 |
4 | require 'json'
5 | require 'yaml'
6 |
7 | VAGRANTFILE_API_VERSION ||= "2"
8 | confDir = $confDir ||= File.expand_path("vendor/laravel/homestead", File.dirname(__FILE__))
9 |
10 | homesteadYamlPath = File.expand_path("Homestead.yaml", File.dirname(__FILE__))
11 | homesteadJsonPath = File.expand_path("Homestead.json", File.dirname(__FILE__))
12 | afterScriptPath = "after.sh"
13 | aliasesPath = "aliases"
14 |
15 | require File.expand_path(confDir + '/scripts/homestead.rb')
16 |
17 | Vagrant.require_version '>= 1.9.0'
18 |
19 | Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
20 | if File.exist? aliasesPath then
21 | config.vm.provision "file", source: aliasesPath, destination: "/tmp/bash_aliases"
22 | config.vm.provision "shell" do |s|
23 | s.inline = "awk '{ sub(\"\r$\", \"\"); print }' /tmp/bash_aliases > /home/vagrant/.bash_aliases"
24 | end
25 | end
26 |
27 | if File.exist? homesteadYamlPath then
28 | settings = YAML::load(File.read(homesteadYamlPath))
29 | elsif File.exist? homesteadJsonPath then
30 | settings = JSON.parse(File.read(homesteadJsonPath))
31 | else
32 | abort "Homestead settings file not found in #{confDir}"
33 | end
34 |
35 | Homestead.configure(config, settings)
36 |
37 | if File.exist? afterScriptPath then
38 | config.vm.provision "shell", path: afterScriptPath, privileged: false
39 | end
40 |
41 | if defined? VagrantPlugins::HostsUpdater
42 | config.hostsupdater.aliases = settings['sites'].map { |site| site['map'] }
43 | end
44 | end
45 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Account/AvatarController.php:
--------------------------------------------------------------------------------
1 | user();
23 |
24 | // Delete the old avatar in the public images directory
25 | \File::delete(public_path() . '/images/avatars/'.$user->avatar);
26 |
27 | // Get the current file uploaded
28 | $avatar = request()->file( 'avatar' );
29 |
30 | // Get the file name
31 | $avatarName = sha1( $avatar->getClientOriginalName() );
32 |
33 | // Get the file extension
34 | $avatarExtension = $avatar->getClientOriginalExtension();
35 |
36 | // Combine the image name and extension
37 | $image = "{$avatarName}.{$avatarExtension}";
38 |
39 | // Move the file to a path with the image name
40 | $request->file( 'avatar' )->move(
41 | base_path() . '/public/images/avatars/', $image
42 | );
43 |
44 | // Set the users avatar to the image
45 | $user->avatar = $image;
46 |
47 | // Save the image to database
48 | $user->save();
49 |
50 | return back();
51 | } else {
52 | return back();
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/public/images/home/process/five.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
8 |
10 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/app/Notifications/UpdatedFileApproved.php:
--------------------------------------------------------------------------------
1 | user = $user;
27 | $this->file = $file;
28 | }
29 |
30 | /**
31 | * Get the notification's delivery channels.
32 | *
33 | * @param mixed $notifiable
34 | * @return array
35 | */
36 | public function via($notifiable)
37 | {
38 | return ['mail'];
39 | }
40 |
41 | /**
42 | * Get the mail representation of the notification.
43 | *
44 | * @param mixed $notifiable
45 | * @return \Illuminate\Notifications\Messages\MailMessage
46 | */
47 | public function toMail($notifiable)
48 | {
49 |
50 | $image = '/images/icons/checkbox.svg';
51 | $imageAlt = 'Your file updates has been approved';
52 |
53 | return (new MailMessage)
54 | ->markdown('vendor.notifications.email', ['image' => $image, 'imageAlt' => $imageAlt])
55 | ->line('File name: ' . $this->file->title)
56 | ->line('Your file updates has been approved!');
57 | }
58 |
59 | /**
60 | * Get the array representation of the notification.
61 | *
62 | * @param mixed $notifiable
63 | * @return array
64 | */
65 | public function toArray($notifiable)
66 | {
67 | return [
68 | //
69 | ];
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Account/DatabaseNotificationsController.php:
--------------------------------------------------------------------------------
1 | first();
18 |
19 | if (!$file->sales->count() > 0) {
20 | return redirect(route('account.files.index'));
21 | }
22 |
23 | return view( 'account.files.notify.index', compact('file'));
24 | }
25 |
26 |
27 | public function notifyOfChanges(Request $request, $identifier) {
28 |
29 | $this->validate($request, [
30 | 'data' => 'required|min:15|max:2500',
31 | 'header' => 'nullable|max:50|min:5'
32 | ]);
33 |
34 | $data = $request->data;
35 | $header = $request->header;
36 |
37 | $file = File::where('identifier', $identifier)->first();
38 |
39 | $owner = User::where('id', $file->user_id)->first();
40 |
41 | $sales = Sale::where('file_id', $file->id)->get();
42 |
43 | $userIds = $sales->pluck('bought_user_id');
44 |
45 | $users = User::whereIn('id', $userIds)->where('user_notifications', 0)->get();
46 |
47 | \Notification::send($users, new FileChanges($data, $header, $owner, $file));
48 |
49 | return redirect(route('account.files.index'))->withSuccess('Notification sent successfully to users.');
50 | }
51 |
52 |
53 | public function markAllAsRead() {
54 |
55 | auth()->user()->unreadNotifications->markAsRead();
56 |
57 | return back()->withSuccess('Marked all as read');
58 | }
59 |
60 | }
--------------------------------------------------------------------------------
/resources/assets/js/components/files/partials/File.vue:
--------------------------------------------------------------------------------
1 |
2 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/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 | //
40 | ],
41 | ],
42 |
43 | 'redis' => [
44 | 'driver' => 'redis',
45 | 'connection' => 'default',
46 | ],
47 |
48 | 'log' => [
49 | 'driver' => 'log',
50 | ],
51 |
52 | 'null' => [
53 | 'driver' => 'null',
54 | ],
55 |
56 | ],
57 |
58 | ];
59 |
--------------------------------------------------------------------------------
/app/Notifications/FileApproved.php:
--------------------------------------------------------------------------------
1 | user = $user;
27 | $this->file = $file;
28 | }
29 |
30 | /**
31 | * Get the notification's delivery channels.
32 | *
33 | * @param mixed $notifiable
34 | * @return array
35 | */
36 | public function via($notifiable)
37 | {
38 | return ['mail'];
39 | }
40 |
41 | /**
42 | * Get the mail representation of the notification.
43 | *
44 | * @param mixed $notifiable
45 | * @return \Illuminate\Notifications\Messages\MailMessage
46 | */
47 | public function toMail($notifiable)
48 | {
49 |
50 | $image = '/images/icons/checkbox.svg';
51 | $imageAlt = 'Your file has been approved';
52 |
53 | return (new MailMessage)
54 | ->markdown('vendor.notifications.email', ['image' => $image, 'imageAlt' => $imageAlt])
55 | ->line('File name: ' . $this->file->title)
56 | ->line('Your file has been approved!');
57 | }
58 |
59 | /**
60 | * Get the array representation of the notification.
61 | *
62 | * @param mixed $notifiable
63 | * @return array
64 | */
65 | public function toArray($notifiable)
66 | {
67 | return [
68 | //
69 | ];
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/app/Notifications/EmailVerification.php:
--------------------------------------------------------------------------------
1 | user = $user;
25 | }
26 |
27 | /**
28 | * Get the notification's delivery channels.
29 | *
30 | * @param mixed $notifiable
31 | * @return array
32 | */
33 | public function via($notifiable)
34 | {
35 | return ['mail'];
36 | }
37 |
38 | /**
39 | * Get the mail representation of the notification.
40 | *
41 | * @param mixed $notifiable
42 | * @return \Illuminate\Notifications\Messages\MailMessage
43 | */
44 | public function toMail($notifiable)
45 | {
46 | $image = '/images/icons/email.svg';
47 | $imageAlt = 'Please verify your email address icon image';
48 |
49 | return (new MailMessage)
50 | ->markdown('vendor.notifications.email', ['image' => $image, 'imageAlt' => $imageAlt])
51 | ->action('Verify email address', route('verify.email', $this->user->token))
52 | ->line('Thanks for registering! In order to protect your account and verify who you are, please confirm your email.');
53 | }
54 |
55 | /**
56 | * Get the array representation of the notification.
57 | *
58 | * @param mixed $notifiable
59 | * @return array
60 | */
61 | public function toArray($notifiable)
62 | {
63 | return [
64 | //
65 | ];
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/resources/views/account/notifications/show.blade.php:
--------------------------------------------------------------------------------
1 | @extends('account.layouts.default')
2 |
3 | @section('account.content')
4 |
5 |
6 |
7 |
14 |
15 |
16 |
{{ $notification->data['data'] }}
17 |
18 |
19 | @if(isset($notification->data['owner_name']))
20 | From: {{ $notification->data['owner_name'] }}
21 | @endif
22 | {{ $notification->created_at->diffForHumans() }}
23 |
24 |
25 |
26 |
27 |
34 |
35 |
36 | @endsection
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/resources/views/layouts/partials/_footer.blade.php:
--------------------------------------------------------------------------------
1 |
55 |
--------------------------------------------------------------------------------
/resources/assets/js/components/files/Index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/resources/assets/js/bootstrap.js:
--------------------------------------------------------------------------------
1 |
2 | window._ = require('lodash');
3 |
4 | /**
5 | * We'll load jQuery and the Bootstrap jQuery plugin which provides support
6 | * for JavaScript based Bootstrap features such as modals and tabs. This
7 | * code may be modified to fit the specific needs of your application.
8 | */
9 |
10 | try {
11 | window.$ = window.jQuery = require('jquery');
12 |
13 | require('bootstrap-sass');
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 | * Next we will register the CSRF Token as a common header with Axios so that
28 | * all outgoing HTTP requests automatically have it attached. This is just
29 | * a simple convenience so we don't have to attach every token manually.
30 | */
31 |
32 | let token = document.head.querySelector('meta[name="csrf-token"]');
33 |
34 | if (token) {
35 | window.axios.defaults.headers.common['X-CSRF-TOKEN'] = token.content;
36 | } else {
37 | console.error('CSRF token not found: https://laravel.com/docs/csrf#csrf-x-csrf-token');
38 | }
39 |
40 | /**
41 | * Echo exposes an expressive API for subscribing to channels and listening
42 | * for events that are broadcast by Laravel. Echo and event broadcasting
43 | * allows your team to easily build robust real-time web applications.
44 | */
45 |
46 | // import Echo from 'laravel-echo'
47 |
48 | // window.Pusher = require('pusher-js');
49 |
50 | // window.Echo = new Echo({
51 | // broadcaster: 'pusher',
52 | // key: 'your-pusher-key'
53 | // });
54 |
55 |
56 | window.Dropzone = require('dropzone');
57 | Dropzone.autoDiscover = false;
--------------------------------------------------------------------------------
/resources/views/admin/users/index.blade.php:
--------------------------------------------------------------------------------
1 | @extends('admin.layouts.default')
2 |
3 | @section('admin.content')
4 |
5 |
6 |
7 | Avatar
8 | Name
9 | Email
10 | Joined
11 | Impersonate
12 |
13 |
14 |
15 | @foreach($users as $user)
16 |
17 |
18 | @if($user->avatar)
19 |
20 | @endif
21 |
22 |
23 | {{ $user->name }}
24 |
25 |
26 |
27 | {{ $user->email }}
28 |
29 |
30 |
31 | {{ $user->created_at->format('m/d/Y H:i:s') }}
32 |
33 |
34 | @if(auth()->user()->id !== $user->id)
35 |
36 | {{ csrf_field() }}
37 |
38 |
39 |
40 |
41 | @endif
42 |
43 |
44 | @endforeach
45 |
46 |
47 |
48 | {{ $users->render() }}
49 | @endsection
--------------------------------------------------------------------------------
/app/Notifications/FileRejected.php:
--------------------------------------------------------------------------------
1 | user = $user;
23 | $this->file = $file;
24 | $this->data = $data;
25 | }
26 |
27 |
28 | /**
29 | * Get the notification's delivery channels.
30 | *
31 | * @param mixed $notifiable
32 | * @return array
33 | */
34 | public function via($notifiable) {
35 | return ['mail', 'database'];
36 | }
37 |
38 |
39 | /**
40 | * Get the mail representation of the notification.
41 | *
42 | * @param mixed $notifiable
43 | * @return \Illuminate\Notifications\Messages\MailMessage
44 | */
45 | public function toMail($notifiable) {
46 |
47 | $image = '/images/icons/rejected.svg';
48 | $imageAlt = 'Your file has been rejected';
49 |
50 | return (new MailMessage)
51 | ->markdown('vendor.notifications.email', ['image' => $image, 'imageAlt' => $imageAlt])
52 | ->line('File name: ' . $this->file->title)
53 | ->line('Your file has been rejected')
54 | ->line('You can check your notifications on Marketplace to see if the admin gave a reason on why your file was rejected');
55 | }
56 |
57 | /**
58 | * Get the array representation of the notification.
59 | *
60 | * @param mixed $notifiable
61 | * @return array
62 | */
63 | public function toArray($notifiable) {
64 | return [
65 | 'header' => 'File: "'.$this->file->title.'" has been rejected by admin',
66 | 'data' => isset($this->data) ? $this->data : 'Admin gave no reason for file rejection.',
67 | 'file' => $this->file->title,
68 | ];
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Account/MarketPlaceConnectController.php:
--------------------------------------------------------------------------------
1 | middleware(['auth', 'has.marketplace']);
18 | }
19 |
20 |
21 | /**
22 | * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
23 | */
24 | public function index() {
25 |
26 | session(['stripe_token' => str_random(60)]);
27 |
28 | return view('account.marketplace.index');
29 | }
30 |
31 |
32 | /**
33 | * @param Request $request
34 | * @param Guzzle $guzzle
35 | *
36 | * @return \Illuminate\Http\RedirectResponse
37 | */
38 | public function store(Request $request, Guzzle $guzzle) {
39 |
40 | // If no request code found, return redirect to account connect route.
41 | if (!$request->code) {
42 | return redirect()->route('account.connect');
43 | }
44 |
45 | // If no session found, return redirect to account connect route.
46 | if ($request->state !== session('stripe_token')) {
47 | return redirect()->route('account.connect');
48 | }
49 |
50 | $stripeRequest = $guzzle->request('POST', 'https://connect.stripe.com/oauth/token', [
51 | 'form_params' => [
52 | 'client_secret' => config('services.stripe.secret'),
53 | 'code' => $request->code,
54 | 'grant_type' => 'authorization_code'
55 | ]
56 | ]);
57 |
58 | $stripeRequest = json_decode($stripeRequest->getBody());
59 |
60 | $request->user()->update([
61 | 'stripe_id' => $stripeRequest->stripe_user_id,
62 | 'stripe_key' => $stripeRequest->stripe_publishable_key,
63 | ]);
64 |
65 | return redirect()->route('account')->withSuccess('You have connected your Stripe account.');
66 |
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/app/Notifications/UpdatedFileRejection.php:
--------------------------------------------------------------------------------
1 | user = $user;
23 | $this->file = $file;
24 | $this->data = $data;
25 | }
26 |
27 | /**
28 | * Get the notification's delivery channels.
29 | *
30 | * @param mixed $notifiable
31 | * @return array
32 | */
33 | public function via($notifiable) {
34 | return ['mail', 'database'];
35 | }
36 |
37 | /**
38 | * Get the mail representation of the notification.
39 | *
40 | * @param mixed $notifiable
41 | * @return \Illuminate\Notifications\Messages\MailMessage
42 | */
43 | public function toMail($notifiable) {
44 |
45 | $image = '/images/icons/rejected.svg';
46 | $imageAlt = 'Your file updates has been rejected';
47 |
48 | return (new MailMessage)
49 | ->markdown('vendor.notifications.email', ['image' => $image, 'imageAlt' => $imageAlt])
50 | ->line('File name: ' . $this->file->title)
51 | ->line('Your file updates has been rejected')
52 | ->line('You can check your notifications on Marketplace to see if the admin gave a reason on why your file was rejected');
53 | }
54 |
55 |
56 | /**
57 | * Get the array representation of the notification.
58 | *
59 | * @param mixed $notifiable
60 | * @return array
61 | */
62 | public function toArray($notifiable) {
63 | return [
64 | 'header' => 'File: "'.$this->file->title.'" has been rejected by admin',
65 | 'data' => isset($this->data) ? $this->data : 'Admin gave no reason for file rejection.',
66 | 'file' => $this->file->title,
67 | ];
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/database/factories/FileFactory.php:
--------------------------------------------------------------------------------
1 | define(App\File::class, function (Faker $faker) {
17 |
18 | $live = rand(0, 1);
19 |
20 | return [
21 | 'identifier' => uniqid(),
22 | 'user_id' => App\User::all()->random()->id,
23 | 'title' => $faker->sentence($nbWords = 4),
24 | 'overview_short' => $faker->sentence,
25 | 'overview' => $faker->text($maxNbChars = 500),
26 | 'price' => $faker->randomFloat($nbMaxDecimals = 2, $min = 0, $max = 125),
27 | 'live' => $live,
28 | 'approved' => $live,
29 | 'finished' => $live,
30 | 'avatar' => $faker->image('public/images/files/cover',1000,700, null, false),
31 | 'youtube_url' => 'https://www.youtube.com/watch?v=Ff6bi8rkLpg',
32 | 'vimeo_url' => 'https://vimeo.com/99232333',
33 | 'created_at' =>$faker->dateTimeBetween($startDate = '-2 years', $endDate = 'now', $timezone = null),
34 | 'updated_at' =>$faker->dateTimeBetween($startDate = '-2 years', $endDate = 'now', $timezone = null)
35 | ];
36 | });
37 |
38 |
39 |
40 | $factory->define(App\Comment::class, function (Faker $faker) {
41 |
42 | $file = rand(1, 50);
43 |
44 | return [
45 | 'user_id' => App\User::all()->random()->id,
46 | 'parent_id' => null,
47 | 'body' => $faker->sentence,
48 | 'commentable_id' => $file,
49 | 'commentable_type' => 'App\File',
50 | 'created_at' =>$faker->dateTimeBetween($startDate = '-1 years', $endDate = 'now', $timezone = null),
51 | 'updated_at' =>$faker->dateTimeBetween($startDate = '-1 years', $endDate = 'now', $timezone = null)
52 | ];
53 | });
--------------------------------------------------------------------------------
/resources/views/account/bought/index.blade.php:
--------------------------------------------------------------------------------
1 | @extends('account.layouts.default')
2 |
3 | @section('account.content')
4 | @if(\App\Sale::boughtUserId()->count() > 0)
5 | @foreach($boughtFiles as $bought)
6 |
31 | @endforeach
32 |
33 | {!! $boughtFiles->render() !!}
34 | @else
35 | You have not purchased any files on this account yet.
36 | @endif
37 |
38 | @endsection
--------------------------------------------------------------------------------
/resources/views/admin/partials/_navigation.blade.php:
--------------------------------------------------------------------------------
1 |
11 |
12 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Admin/CategoriesController.php:
--------------------------------------------------------------------------------
1 | paginate(50);
19 |
20 | return view('admin.categories.index', compact ('categories'));
21 | }
22 |
23 |
24 | /**
25 | * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
26 | */
27 | public function create() {
28 | return view('admin.categories.create');
29 | }
30 |
31 |
32 | /**
33 | * @param $slug
34 | *
35 | * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
36 | */
37 | public function edit($slug) {
38 |
39 | $category = Category::where('slug', $slug)->first();
40 |
41 | return view('admin.categories.edit', compact('category'));
42 | }
43 |
44 |
45 | /**
46 | * @param Request $request
47 | *
48 | * @return mixed
49 | */
50 | public function store(Request $request) {
51 |
52 | $this->validate($request,[
53 | 'name' => 'required|string|max:25|unique:categories,name'
54 | ]);
55 |
56 | Category::create([
57 | 'name' => $request->name,
58 | 'slug' => str_slug($request->name)
59 | ]);
60 |
61 | return redirect(route('admin.categories'))->withSuccess("Category created.");
62 | }
63 |
64 |
65 | /**
66 | * @param FileCategoryRequest $request
67 | * @param $id
68 | *
69 | * @return mixed
70 | */
71 | public function update(FileCategoryRequest $request, $id) {
72 |
73 | $category = Category::find($id);
74 |
75 | $category->update([
76 | 'name' => $request->name,
77 | 'slug' => str_slug($request->name)
78 | ]);
79 |
80 | return redirect(route('admin.categories'))->withSuccess("Category updated.");
81 | }
82 |
83 | }
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "laravel/laravel",
3 | "description": "The Laravel Framework.",
4 | "keywords": ["framework", "laravel"],
5 | "license": "MIT",
6 | "type": "project",
7 | "require": {
8 | "php": ">=7.0.0",
9 | "barryvdh/laravel-ide-helper": "^2.4",
10 | "chumper/zipper": "^1.0",
11 | "fideloper/proxy": "~3.3",
12 | "guzzlehttp/guzzle": "^6.3",
13 | "intervention/image": "^2.4",
14 | "kitetail/zttp": "^0.3.0",
15 | "laravel/framework": "5.5.*",
16 | "laravel/tinker": "~1.0",
17 | "sentry/sentry-laravel": "^0.8.0",
18 | "stripe/stripe-php": "^5.8",
19 | "ext-gd":" *"
20 | },
21 | "require-dev": {
22 | "filp/whoops": "~2.0",
23 | "fzaninotto/faker": "~1.4",
24 | "laravel/homestead": "^6.2",
25 | "mockery/mockery": "0.9.*",
26 | "phpunit/phpunit": "~6.0"
27 | },
28 | "autoload": {
29 | "classmap": [
30 | "database/seeds",
31 | "database/factories"
32 | ],
33 | "files": [
34 | "app/helpers.php"
35 | ],
36 | "psr-4": {
37 | "App\\": "app/"
38 | }
39 | },
40 | "autoload-dev": {
41 | "psr-4": {
42 | "Tests\\": "tests/"
43 | }
44 | },
45 | "extra": {
46 | "laravel": {
47 | "dont-discover": [
48 | ]
49 | }
50 | },
51 | "scripts": {
52 | "post-root-package-install": [
53 | "@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
54 | ],
55 | "post-create-project-cmd": [
56 | "@php artisan key:generate"
57 | ],
58 | "post-autoload-dump": [
59 | "Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
60 | "@php artisan package:discover"
61 | ]
62 | },
63 | "config": {
64 | "preferred-install": "dist",
65 | "sort-packages": true,
66 | "optimize-autoloader": true
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/resources/views/files/index.blade.php:
--------------------------------------------------------------------------------
1 | @extends('layouts.plain')
2 |
3 | @section('content')
4 |
5 | @include('files.partials._top_filter_nav')
6 |
7 | @if($files->isEmpty())
8 |
No files found
9 | @else
10 | @foreach($files as $file)
11 |
30 | @endforeach
31 |
32 | {{ $files->appends(request()->input())->links() }}
33 | @endif
34 |
35 |
36 | @endsection
--------------------------------------------------------------------------------
/resources/views/account/password/index.blade.php:
--------------------------------------------------------------------------------
1 | @extends('account.layouts.default')
2 |
3 | @section('account.content')
4 |
5 |
Change Password
6 |
44 |
45 | @endsection
--------------------------------------------------------------------------------
/resources/assets/js/components/AvatarUpload.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
28 |
29 |
--------------------------------------------------------------------------------
/resources/views/auth/passwords/email.blade.php:
--------------------------------------------------------------------------------
1 | @extends('layouts.app')
2 |
3 | @section('content')
4 |
5 |
6 |
7 |
8 |
9 |
14 |
Rest Password
15 | @if (session('status'))
16 |
17 | {{ session('status') }}
18 |
19 | @endif
20 |
21 |
22 | {{ csrf_field() }}
23 |
24 |
25 |
26 | @if ($errors->has('email'))
27 |
28 | {{ $errors->first('email') }}
29 |
30 | @endif
31 |
32 |
33 |
34 |
35 |
36 | Send Password Reset Link
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 | @endsection
47 |
--------------------------------------------------------------------------------
/app/Sale.php:
--------------------------------------------------------------------------------
1 | belongsTo(User::class);
34 | }
35 |
36 |
37 | /**
38 | * Get the relationship of user who bought file for a particular Sale.
39 | * -- References "id" on user table, and "bought_user_id" on sales table.
40 | *
41 | * @return \Illuminate\Database\Eloquent\Relations\HasMany
42 | */
43 | public function boughtUser() {
44 | return $this->hasMany(User::class, 'id','bought_user_id');
45 | }
46 |
47 |
48 | /**
49 | * A Sale belongs to a file.
50 | * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
51 | */
52 | public function file() {
53 | return $this->belongsTo(File::class);
54 | }
55 |
56 |
57 | /**
58 | * Get the user where the 'bought_user_id' is the currently signed in user.
59 | * @param Builder $builder
60 | *
61 | * @return $this
62 | */
63 | public function scopeBoughtUserId(Builder $builder) {
64 | return $builder->where('bought_user_id', '=', auth()->user()->id);
65 | }
66 |
67 |
68 | /**
69 | * Sum up all the sales commissions.
70 | * @return mixed
71 | */
72 | public static function lifetimeCommission() {
73 | return static::get()->sum('sale_commission');
74 | }
75 |
76 |
77 | /** Grab the sales for month from now, and get all sales.
78 | * @return mixed
79 | */
80 | public static function commissionThisMonth() {
81 | $now = Carbon::now();
82 |
83 | return static::whereBetween('created_at', [
84 | $now->startOfMonth(),
85 | $now->copy()->endOfMonth()
86 | ])->get()->sum('sale_commission');
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Checkout/CheckoutController.php:
--------------------------------------------------------------------------------
1 | isFree()) {
25 | return back();
26 | }
27 |
28 | // Create a 'Job' to create a sale
29 | $this->dispatch(new CreateSale($file, $request->email));
30 |
31 | return back()->withSuccess('We\'ve emailed your download link to you. ');
32 | }
33 |
34 |
35 | /**
36 | * @param Request $request
37 | * @param File $file
38 | *
39 | * @return mixed
40 | */
41 | public function payment(Request $request, File $file) {
42 |
43 | try {
44 | $charge = Charge::create([
45 | 'amount' => $file->price * 100,
46 | 'currency' => 'usd',
47 | 'description' => 'Charge for: '. str_limit($file->title, 100),
48 | 'source' => $request->stripeToken,
49 | 'application_fee' => floor($file->calculateCommission() * 100),
50 | 'metadata' => [
51 | 'file_identifier' => $file->identifier,
52 | 'file_title' => $file->title,
53 | 'file_short_description' => $file->overview_short,
54 | 'file_user' => $file->user->name
55 | ]
56 | ], [
57 | 'stripe_account' => $file->user->stripe_id
58 | ]);
59 | } catch (\Exception $e) {
60 | return back()->withError('Something went wrong while processing your payment.');
61 | }
62 |
63 | // Create a 'Job' to create a sale
64 | $this->dispatch(new CreateSale($file, $request->stripeEmail));
65 |
66 | return back()->withSuccess('Payment complete. We\'ve emailed your download link to you.');
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/resources/assets/sass/_variables.scss:
--------------------------------------------------------------------------------
1 |
2 | // Body
3 | $body-bg: #f5f8fa;
4 |
5 | // Borders
6 | $laravel-border-color: darken($body-bg, 10%);
7 | $list-group-border: $laravel-border-color;
8 | $navbar-default-border: $laravel-border-color;
9 | $panel-default-border: $laravel-border-color;
10 | $panel-inner-border: $laravel-border-color;
11 |
12 | // Brands
13 | $brand-primary: #3097D1;
14 | $brand-info: #8eb4cb;
15 | $brand-success: #2ab27b;
16 | $brand-warning: #cbb956;
17 | $brand-danger: #bf5329;
18 |
19 | // Typography
20 | $icon-font-path: "~bootstrap-sass/assets/fonts/bootstrap/";
21 | $font-family-sans-serif: "Raleway", sans-serif;
22 | $font-size-base: 14px;
23 | $line-height-base: 1.6;
24 | $text-color: #636b6f;
25 |
26 | // Navbar
27 | $navbar-default-bg: #fff;
28 |
29 | // Buttons
30 | $btn-default-color: $text-color;
31 |
32 | // Inputs
33 | $input-border: lighten($text-color, 40%);
34 | $input-border-focus: lighten($brand-primary, 25%);
35 | $input-color-placeholder: lighten($text-color, 30%);
36 |
37 | // Panels
38 | $panel-default-heading-bg: #fff;
39 |
40 |
41 | .MAIN-BACKGROUND-OVERLAY {
42 | background: linear-gradient(45deg, #0B4182 1%, #1e88e5 64%, #40BAF5 97%);
43 | background-image: -ms-linear-gradient(45deg, #0B4182 1%, #1e88e5 64%, #40BAF5 97%);
44 | background-image: -moz-linear-gradient(45deg, #0B4182 1%, #1e88e5 64%, #40BAF5 97%);
45 | background-image: -o-linear-gradient(45deg, #0B4182 1%, #1e88e5 64%, #40BAF5 97%);
46 | background-image: -webkit-linear-gradient(45deg, #0B4182 1%, #1e88e5 64%, #40BAF5 97%);
47 | background-image: linear-gradient(45deg, #0B4182 1%, #1e88e5 64%, #40BAF5 97%);
48 | }
49 |
50 | .FORM-INPUT {
51 | -webkit-appearance: none;
52 | -moz-appearance: none;
53 | appearance: none;
54 |
55 | height: 48px;
56 | border: 1px solid #cacbcc;
57 | font-size: 16px;
58 | box-shadow: none;
59 | color: #555;
60 | margin-bottom: 10px;
61 | -webkit-border-radius: 2px;
62 | -moz-border-radius: 2px;
63 | border-radius: 2px;
64 | }
65 |
66 | .SPECIAL-BOX-SHADOW {
67 | -webkit-box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
68 | -moz-box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
69 | box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
70 | padding: 15px 20px 20px 20px;
71 | border-radius: 4px;
72 | }
--------------------------------------------------------------------------------
/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", "s3", "rackspace"
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_KEY'),
61 | 'secret' => env('AWS_SECRET'),
62 | 'region' => env('AWS_REGION'),
63 | 'bucket' => env('AWS_BUCKET'),
64 | ],
65 |
66 | ],
67 |
68 | ];
69 |
--------------------------------------------------------------------------------
/public/images/icons/avatar.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Admin/AdminController.php:
--------------------------------------------------------------------------------
1 | ', Carbon::now()->firstOfMonth())
23 | ->where('sale_price', '>', 0)
24 | ->selectRaw('DATE_FORMAT(created_at, "%m/%d") as day, sum(sale_price) as sale_price')
25 | ->groupBy('day')
26 | ->pluck('sale_price', 'day');
27 |
28 | // Get all the sales there ever was.
29 | $overallSales = Sale::where('sale_price', '>', 0)
30 | ->selectRaw('DATE_FORMAT(created_at, "%Y/%m") as year, sum(sale_price) as sale_price')
31 | ->groupBy('year')
32 | ->pluck('sale_price', 'year');
33 |
34 | return view('admin.index', compact('salesThisMonth', 'overallSales'));
35 | }
36 |
37 |
38 | /**
39 | * Get a list of all current signed up users.
40 | *
41 | * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
42 | */
43 | public function users() {
44 |
45 | $users = User::latest()->paginate(50);
46 |
47 | return view('admin.users.index', compact('users'));
48 | }
49 |
50 |
51 | /**
52 | * Start impersonating a user. Login as them.
53 | *
54 | * @param Request $request
55 | * @param $id
56 | *
57 | * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
58 | */
59 | public function impersonate(Request $request, $id) {
60 |
61 | if (!auth()->user()->isAdmin()) {
62 | $user = User::where( 'id', '=', $id )->first();
63 |
64 | session()->put( 'impersonate', $user->id );
65 |
66 | return redirect( '/' );
67 | }
68 |
69 | return back();
70 | }
71 |
72 |
73 | /**
74 | * Stop impersonating a user. Remove session.
75 | *
76 | * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
77 | */
78 | public function destroyImpersonate() {
79 |
80 | session()->forget('impersonate');
81 |
82 | return redirect('/');
83 | }
84 |
85 | }
86 |
--------------------------------------------------------------------------------
/resources/views/account/files/notify/index.blade.php:
--------------------------------------------------------------------------------
1 | @extends('account.layouts.default')
2 |
3 | @section('account.content')
4 |
54 | @endsection
--------------------------------------------------------------------------------
/resources/views/account/notifications/index.blade.php:
--------------------------------------------------------------------------------
1 | @extends('account.layouts.default')
2 |
3 | @section('account.content')
4 |
5 |
6 |
7 |
11 |
12 |
13 | @if($unreadNotifications->count() > 0)
14 |
Mark All as Read
15 |
16 | @foreach($unreadNotifications as $unread)
17 |
18 |
25 |
26 |
27 |
{{ str_limit($unread->data['data'], 80) }} Read more...
28 |
29 |
30 | @if(isset($unread->data['owner_name']))
31 | From: {{ $unread->data['owner_name'] }}
32 | @endif
33 | {{ $unread->created_at->diffForHumans() }}
34 |
35 |
36 |
37 | @endforeach
38 |
39 | {{ $unreadNotifications->render() }}
40 | @else
41 |
You have no unread notifications
42 | @endif
43 |
44 |
45 | @endsection
--------------------------------------------------------------------------------
/resources/views/account/notifications/all-notifications.blade.php:
--------------------------------------------------------------------------------
1 | @extends('account.layouts.default')
2 |
3 | @section('account.content')
4 |
5 |
6 |
7 |
11 |
12 |
13 | @if($notifications->count() > 0)
14 | @foreach($notifications as $allNotifications)
15 |
16 |
23 |
24 |
25 |
{{ str_limit($allNotifications->data['data'], 80) }} Read more...
26 |
27 |
28 | @if(isset($allNotifications->data['owner_name']))
29 | From: {{ $allNotifications->data['owner_name'] }}
30 | @endif
31 | {{ $allNotifications->created_at->diffForHumans() }}
32 |
33 |
34 |
35 | @endforeach
36 |
37 | {{ $notifications->render() }}
38 | @else
39 |
You have no notifications
40 | @endif
41 |
42 |
43 |
44 | @endsection
--------------------------------------------------------------------------------