mirror of
https://github.com/VueFileManager/vuefilemanager.git
synced 2026-04-18 16:22:14 +00:00
Setup wizard update
This commit is contained in:
67
.env.dev
Normal file
67
.env.dev
Normal file
@@ -0,0 +1,67 @@
|
||||
APP_NAME=VueFileManager
|
||||
APP_ENV=local
|
||||
APP_KEY=base64:EYM98pyseC/frZhW30ifeJqpOP3UmmLj1fMahrDN3zw=
|
||||
APP_DEBUG=true
|
||||
APP_URL=http://localhost
|
||||
APP_DEMO=false
|
||||
|
||||
LOG_CHANNEL=stack
|
||||
SCOUT_DRIVER=tntsearch
|
||||
FILESYSTEM_DRIVER=local
|
||||
|
||||
DB_CONNECTION=mysql
|
||||
DB_HOST=127.0.0.1
|
||||
DB_PORT=8889
|
||||
DB_DATABASE=file-manager
|
||||
DB_USERNAME=root
|
||||
DB_PASSWORD=root
|
||||
|
||||
BROADCAST_DRIVER=log
|
||||
CACHE_DRIVER=file
|
||||
QUEUE_CONNECTION=sync
|
||||
SESSION_DRIVER=file
|
||||
SESSION_LIFETIME=120
|
||||
|
||||
MAIL_DRIVER=smtp
|
||||
MAIL_HOST=smtp.websupport.sk
|
||||
MAIL_PORT=25
|
||||
MAIL_USERNAME=vuefilemanager@hi5ve.digital
|
||||
MAIL_PASSWORD=Yl2d]kET>)
|
||||
MAIL_ENCRYPTION=tls
|
||||
MAIL_FROM_ADDRESS="${MAIL_USERNAME}"
|
||||
MAIL_FROM_NAME="${APP_NAME}"
|
||||
|
||||
AWS_ACCESS_KEY_ID=AKIA3UOZZXPUGKQ3BLMZ
|
||||
AWS_SECRET_ACCESS_KEY=op7JLdtWO+zp0JYthUbamCZ7b4uMBrlMI5uu/CHB
|
||||
AWS_DEFAULT_REGION=eu-central-1
|
||||
AWS_BUCKET=vuefilemanager-frankfurt
|
||||
|
||||
DO_SPACES_KEY=FSUHFOF5DMZCEWXVNPTI
|
||||
DO_SPACES_SECRET=2t87Ugz/JoIjT1dIdTjnnKQ4t74Yfe665KBjCRc0yDk
|
||||
DO_SPACES_ENDPOINT=https://fra1.digitaloceanspaces.com
|
||||
DO_SPACES_REGION=fra1
|
||||
DO_SPACES_BUCKET=vuefilemanager
|
||||
|
||||
WASABI_KEY=
|
||||
WASABI_SECRET=
|
||||
WASABI_ENDPOINT=
|
||||
WASABI_REGION=
|
||||
WASABI_BUCKET=
|
||||
|
||||
BACKBLAZE_KEY=
|
||||
BACKBLAZE_SECRET=
|
||||
BACKBLAZE_ENDPOINT=
|
||||
BACKBLAZE_REGION=
|
||||
BACKBLAZE_BUCKET=
|
||||
|
||||
PASSPORT_CLIENT_ID=1
|
||||
PASSPORT_CLIENT_SECRET=kZevoWiMjuoxlfO0N0Ezq2oo6ukvX27VPEEJlQUD
|
||||
|
||||
APP_DEPLOY_SECRET=5603148y60eew0q5fw46
|
||||
APP_DEPLOY_BRANCH=dev
|
||||
|
||||
CASHIER_LOGGER=stack
|
||||
CASHIER_CURRENCY=usd
|
||||
STRIPE_KEY=pk_test_51GsACaCBETHMUxzVsYkeApHtqb85paMuye7G77PDDQ28kXqDJ5HTmqLi13aM6xee81OQK1fhkTZ7vmDiWLStU9160061Yb2MtL
|
||||
STRIPE_SECRET=sk_test_51GsACaCBETHMUxzVviYCrv0CeZMyWAOfBPe4uH5rkKJcJxrXhIciWQTr7UB1sgw9geoJMkNDVSWBQW36tuAsVznd00zhNHXhok
|
||||
STRIPE_WEBHOOK_SECRET=whsec_5aM5emy4U9AzPLFxOPyBSyI0QGyI1MZW
|
||||
21
.env.example
21
.env.example
@@ -1,6 +1,6 @@
|
||||
APP_NAME=Laravel
|
||||
APP_ENV=local
|
||||
APP_KEY=
|
||||
APP_KEY=base64:sB1YuKsbWv7MdWugb9ZsYBqv2QZJ+QOuHZHEddOsUuo=
|
||||
APP_DEBUG=true
|
||||
APP_URL=http://localhost
|
||||
|
||||
@@ -45,10 +45,25 @@ DO_SPACES_ENDPOINT=
|
||||
DO_SPACES_REGION=
|
||||
DO_SPACES_BUCKET=
|
||||
|
||||
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
|
||||
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
|
||||
WASABI_KEY=
|
||||
WASABI_SECRET=
|
||||
WASABI_ENDPOINT=
|
||||
WASABI_REGION=
|
||||
WASABI_BUCKET=
|
||||
|
||||
BACKBLAZE_KEY=
|
||||
BACKBLAZE_SECRET=
|
||||
BACKBLAZE_ENDPOINT=
|
||||
BACKBLAZE_REGION=
|
||||
BACKBLAZE_BUCKET=
|
||||
|
||||
PASSPORT_CLIENT_ID=
|
||||
PASSPORT_CLIENT_SECRET=
|
||||
|
||||
APP_DEPLOY_SECRET=
|
||||
|
||||
CASHIER_LOGGER=stack
|
||||
CASHIER_CURRENCY=
|
||||
STRIPE_KEY=
|
||||
STRIPE_SECRET=
|
||||
STRIPE_WEBHOOK_SECRET=
|
||||
@@ -63,9 +63,6 @@ class SetupProductionEnvironment extends Command
|
||||
public function migrateDatabase()
|
||||
{
|
||||
$this->call('migrate:fresh');
|
||||
$this->call('db:seed', [
|
||||
'--class' => 'PaymentGatewaysSeeder'
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -171,8 +171,6 @@ class UserController extends Controller
|
||||
{
|
||||
// Store avatar
|
||||
if ($request->hasFile('avatar')) {
|
||||
|
||||
// Update avatar
|
||||
$avatar = store_avatar($request->file('avatar'), 'avatars');
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,8 @@ class AuthController extends Controller
|
||||
* @param Request $request
|
||||
* @return mixed
|
||||
*/
|
||||
public function check_account(CheckAccountRequest $request) {
|
||||
public function check_account(CheckAccountRequest $request)
|
||||
{
|
||||
|
||||
// Get User
|
||||
$user = User::where('email', $request->input('email'))->select(['name', 'avatar'])->first();
|
||||
@@ -34,6 +35,7 @@ class AuthController extends Controller
|
||||
// Abort with 404, user not found
|
||||
return abort('404', __('vuefilemanager.user_not_fount'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Login user
|
||||
*
|
||||
@@ -42,18 +44,17 @@ class AuthController extends Controller
|
||||
*/
|
||||
public function login(Request $request)
|
||||
{
|
||||
$response = Route::dispatch(self::make_request($request));
|
||||
$response = Route::dispatch(self::make_login_request($request));
|
||||
|
||||
if ($response->isSuccessful()) {
|
||||
|
||||
$data = json_decode($response->content(), true);
|
||||
|
||||
return response('Login Successfull!', 200)->cookie('access_token', $data['access_token'], 43200);
|
||||
} else {
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register user
|
||||
@@ -81,22 +82,23 @@ class AuthController extends Controller
|
||||
]);
|
||||
|
||||
// Create settings
|
||||
// TODO: set default storage capacity
|
||||
$settings = UserSettings::create([
|
||||
'user_id' => $user->id
|
||||
'user_id' => $user->id,
|
||||
'storage_capacity' => 5,
|
||||
]);
|
||||
|
||||
$response = Route::dispatch(self::make_request($request));
|
||||
$response = Route::dispatch(self::make_login_request($request));
|
||||
|
||||
if ($response->isSuccessful()) {
|
||||
|
||||
$data = json_decode($response->content(), true);
|
||||
|
||||
return response('Register Successfull!', 200)->cookie('access_token', $data['access_token'], 43200);
|
||||
} else {
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Logout user entity
|
||||
@@ -118,18 +120,17 @@ class AuthController extends Controller
|
||||
$token->delete();
|
||||
});
|
||||
|
||||
return response('Logout successfull', 204)
|
||||
return response('Logout successful', 204)
|
||||
->cookie('access_token', '', -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make request for get user token
|
||||
* Make login request for get access token
|
||||
*
|
||||
* @param Request $request
|
||||
* @param string $provider
|
||||
* @return Request
|
||||
*/
|
||||
private static function make_request($request)
|
||||
private static function make_login_request($request)
|
||||
{
|
||||
$request->request->add([
|
||||
'grant_type' => 'password',
|
||||
|
||||
607
app/Http/Controllers/General/SetupWizardController.php
Normal file
607
app/Http/Controllers/General/SetupWizardController.php
Normal file
@@ -0,0 +1,607 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\General;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\SetupWizard\CreateAdminRequest;
|
||||
use App\Http\Requests\SetupWizard\StoreAppSetupRequest;
|
||||
use App\Http\Requests\SetupWizard\StoreDatabaseCredentialsRequest;
|
||||
use App\Http\Requests\SetupWizard\StoreEnvironmentSetupRequest;
|
||||
use App\Http\Requests\SetupWizard\StoreStripeBillingRequest;
|
||||
use App\Http\Requests\SetupWizard\StoreStripeCredentialsRequest;
|
||||
use App\Http\Requests\SetupWizard\StoreStripePlansRequest;
|
||||
use App\Services\StripeService;
|
||||
use App\Setting;
|
||||
use App\User;
|
||||
use App\UserSettings;
|
||||
use Artisan;
|
||||
use Cartalyst\Stripe\Exception\UnauthorizedException;
|
||||
use Doctrine\DBAL\Driver\PDOException;
|
||||
use Illuminate\Contracts\Routing\ResponseFactory;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Stripe;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||
|
||||
class SetupWizardController extends Controller
|
||||
{
|
||||
/**
|
||||
* Inject Stripe Service
|
||||
*/
|
||||
public function __construct(StripeService $stripe)
|
||||
{
|
||||
$this->stripe = $stripe;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify Envato purchase code
|
||||
*
|
||||
* @param Request $request
|
||||
* @return ResponseFactory|\Illuminate\Http\Response|mixed
|
||||
*/
|
||||
public function verify_purchase_code(Request $request)
|
||||
{
|
||||
// Author API token
|
||||
$token = 'X3kPkRnIHqauwE7vle3Gvhx6PTY9bvLr';
|
||||
// e3420e63-ce6f-4d04-9b3e-f7f5cc6af7c6
|
||||
|
||||
// Verify purchase code
|
||||
$response = Http::withHeaders([
|
||||
'Authorization' => 'Bearer ' . $token
|
||||
])->get('https://api.envato.com/v3/market/author/sale?code=' . $request->purchaseCode);
|
||||
|
||||
if ($response->successful()) {
|
||||
return $response['license'];
|
||||
}
|
||||
|
||||
return response('Purchase code is invalid.', 400);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up database credentials
|
||||
*
|
||||
* @param StoreDatabaseCredentialsRequest $request
|
||||
* @return ResponseFactory|\Illuminate\Http\Response
|
||||
*/
|
||||
public function setup_database(StoreDatabaseCredentialsRequest $request)
|
||||
{
|
||||
// Set temporary database connection
|
||||
config(['database.connections.test.driver' => $request->connection]);
|
||||
config(['database.connections.test.host' => $request->host]);
|
||||
config(['database.connections.test.port' => $request->port]);
|
||||
config(['database.connections.test.database' => $request->name]);
|
||||
config(['database.connections.test.username' => $request->username]);
|
||||
config(['database.connections.test.password' => $request->password]);
|
||||
|
||||
// Test database connection
|
||||
try {
|
||||
\DB::connection('test')->getPdo();
|
||||
|
||||
} catch (PDOException $e) {
|
||||
throw new HttpException(500, $e->getMessage());
|
||||
}
|
||||
|
||||
$database_credentials = collect([
|
||||
[
|
||||
'name' => 'DB_CONNECTION',
|
||||
'value' => $request->connection,
|
||||
],
|
||||
[
|
||||
'name' => 'DB_HOST',
|
||||
'value' => $request->host,
|
||||
],
|
||||
[
|
||||
'name' => 'DB_PORT',
|
||||
'value' => $request->port,
|
||||
],
|
||||
[
|
||||
'name' => 'DB_DATABASE',
|
||||
'value' => $request->name,
|
||||
],
|
||||
[
|
||||
'name' => 'DB_USERNAME',
|
||||
'value' => $request->username,
|
||||
],
|
||||
[
|
||||
'name' => 'DB_PASSWORD',
|
||||
'value' => $request->password,
|
||||
],
|
||||
]);
|
||||
|
||||
// Store database credentials
|
||||
$database_credentials->each(function ($col) {
|
||||
$this->setEnvironmentValue($col['name'], $col['value']);
|
||||
});
|
||||
|
||||
// Set up application
|
||||
$this->set_up_application();
|
||||
|
||||
return response('Done', 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Migrate database and generate necessary things
|
||||
*/
|
||||
private function set_up_application()
|
||||
{
|
||||
// Clear Cache
|
||||
Artisan::call('cache:clear');
|
||||
Artisan::call('config:clear');
|
||||
|
||||
// Generate app key
|
||||
Artisan::call('key:generate');
|
||||
|
||||
// Migrate database
|
||||
Artisan::call('migrate:fresh');
|
||||
|
||||
// Create Passport Keys
|
||||
Artisan::call('passport:keys', [
|
||||
'--force' => true
|
||||
]);
|
||||
|
||||
// Create Password grant client
|
||||
Artisan::call('passport:client', [
|
||||
'--password' => true,
|
||||
'--name' => 'vuefilemanager',
|
||||
]);
|
||||
|
||||
// Create Personal access client
|
||||
Artisan::call('passport:client', [
|
||||
'--personal' => true,
|
||||
'--name' => 'shared',
|
||||
]);
|
||||
|
||||
// Get generated client
|
||||
$client = \DB::table('oauth_clients')->where('name', '=', 'vuefilemanager')->first();
|
||||
|
||||
// Set passport client to .env
|
||||
$this->setEnvironmentValue('PASSPORT_CLIENT_ID', $client->id);
|
||||
$this->setEnvironmentValue('PASSPORT_CLIENT_SECRET', $client->secret);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store and test stripe credentials
|
||||
*
|
||||
* @param StoreStripeCredentialsRequest $request
|
||||
* @return ResponseFactory|\Illuminate\Http\Response
|
||||
*/
|
||||
public function store_stripe_credentials(StoreStripeCredentialsRequest $request)
|
||||
{
|
||||
// Create stripe instance
|
||||
$stripe = Stripe::make($request->secret, '2020-03-02');
|
||||
|
||||
// Try to get stripe account details
|
||||
try {
|
||||
$stripe->account()->details();
|
||||
} catch (UnauthorizedException $e) {
|
||||
throw new HttpException(401, $e->getMessage());
|
||||
}
|
||||
|
||||
// Get options
|
||||
$settings = collect([
|
||||
[
|
||||
'name' => 'stripe_currency',
|
||||
'value' => $request->currency,
|
||||
],
|
||||
[
|
||||
'name' => 'stripe_webhook_secret',
|
||||
'value' => $request->webhookSecret,
|
||||
],
|
||||
[
|
||||
'name' => 'stripe_secret_key',
|
||||
'value' => $request->secret,
|
||||
],
|
||||
[
|
||||
'name' => 'stripe_publishable_key',
|
||||
'value' => $request->key,
|
||||
],
|
||||
]);
|
||||
|
||||
// Set stripe credentials to .env
|
||||
$this->setEnvironmentValue('CASHIER_CURRENCY', $request->currency);
|
||||
$this->setEnvironmentValue('STRIPE_KEY', $request->key);
|
||||
$this->setEnvironmentValue('STRIPE_SECRET', $request->secret);
|
||||
$this->setEnvironmentValue('STRIPE_WEBHOOK_SECRET', $request->webhookSecret);
|
||||
|
||||
// Store options
|
||||
$settings->each(function ($col) {
|
||||
Setting::updateOrCreate(['name' => $col['name']], $col);
|
||||
});
|
||||
|
||||
return response('Done', 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store Stripe billings
|
||||
*
|
||||
* @param StoreStripeBillingRequest $request
|
||||
* @return ResponseFactory|\Illuminate\Http\Response
|
||||
*/
|
||||
public function store_stripe_billings(StoreStripeBillingRequest $request)
|
||||
{
|
||||
// Get options
|
||||
$settings = collect([
|
||||
[
|
||||
'name' => 'billing_phone_number',
|
||||
'value' => $request->billing_phone_number,
|
||||
],
|
||||
[
|
||||
'name' => 'billing_postal_code',
|
||||
'value' => $request->billing_postal_code,
|
||||
],
|
||||
[
|
||||
'name' => 'billing_vat_number',
|
||||
'value' => $request->billing_vat_number,
|
||||
],
|
||||
[
|
||||
'name' => 'billing_address',
|
||||
'value' => $request->billing_address,
|
||||
],
|
||||
[
|
||||
'name' => 'billing_country',
|
||||
'value' => $request->billing_country,
|
||||
],
|
||||
[
|
||||
'name' => 'billing_state',
|
||||
'value' => $request->billing_state,
|
||||
],
|
||||
[
|
||||
'name' => 'billing_city',
|
||||
'value' => $request->billing_city,
|
||||
],
|
||||
[
|
||||
'name' => 'billing_name',
|
||||
'value' => $request->billing_name,
|
||||
],
|
||||
]);
|
||||
|
||||
// Store options
|
||||
$settings->each(function ($col) {
|
||||
Setting::updateOrCreate(['name' => $col['name']], $col);
|
||||
});
|
||||
|
||||
return response('Done', 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create Stripe subscription plan
|
||||
*
|
||||
* @param StoreStripePlansRequest $request
|
||||
*/
|
||||
public function store_stripe_plans(StoreStripePlansRequest $request)
|
||||
{
|
||||
foreach ($request->input('plans') as $plan) {
|
||||
$this->stripe->createPlan($plan);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Store environment setup
|
||||
*
|
||||
* @param StoreEnvironmentSetupRequest $request
|
||||
* @return string
|
||||
*/
|
||||
public function store_environment_setup(StoreEnvironmentSetupRequest $request)
|
||||
{
|
||||
$storage_driver = $request->input('storage.driver');
|
||||
|
||||
if ($storage_driver === 'local') {
|
||||
|
||||
$storage = collect([
|
||||
[
|
||||
'name' => 'FILESYSTEM_DRIVER',
|
||||
'value' => 'local',
|
||||
],
|
||||
]);
|
||||
|
||||
} else if ($storage_driver === 's3') {
|
||||
|
||||
$storage = collect([
|
||||
[
|
||||
'name' => 'FILESYSTEM_DRIVER',
|
||||
'value' => $request->input('storage.driver'),
|
||||
],
|
||||
[
|
||||
'name' => 'AWS_ACCESS_KEY_ID',
|
||||
'value' => $request->input('storage.key'),
|
||||
],
|
||||
[
|
||||
'name' => 'AWS_SECRET_ACCESS_KEY',
|
||||
'value' => $request->input('storage.secret'),
|
||||
],
|
||||
[
|
||||
'name' => 'AWS_DEFAULT_REGION',
|
||||
'value' => $request->input('storage.region'),
|
||||
],
|
||||
[
|
||||
'name' => 'AWS_BUCKET',
|
||||
'value' => $request->input('storage.bucket'),
|
||||
],
|
||||
]);
|
||||
|
||||
} else if ($storage_driver === 'spaces') {
|
||||
|
||||
$storage = collect([
|
||||
[
|
||||
'name' => 'FILESYSTEM_DRIVER',
|
||||
'value' => $request->input('storage.driver'),
|
||||
],
|
||||
[
|
||||
'name' => 'DO_SPACES_KEY',
|
||||
'value' => $request->input('storage.key'),
|
||||
],
|
||||
[
|
||||
'name' => 'DO_SPACES_SECRET',
|
||||
'value' => $request->input('storage.secret'),
|
||||
],
|
||||
[
|
||||
'name' => 'DO_SPACES_ENDPOINT',
|
||||
'value' => $request->input('storage.endpoint'),
|
||||
],
|
||||
[
|
||||
'name' => 'DO_SPACES_REGION',
|
||||
'value' => $request->input('storage.region'),
|
||||
],
|
||||
[
|
||||
'name' => 'DO_SPACES_BUCKET',
|
||||
'value' => $request->input('storage.bucket'),
|
||||
],
|
||||
]);
|
||||
|
||||
} else if ($storage_driver === 'wasabi') {
|
||||
|
||||
$storage = collect([
|
||||
[
|
||||
'name' => 'FILESYSTEM_DRIVER',
|
||||
'value' => $request->input('storage.driver'),
|
||||
],
|
||||
[
|
||||
'name' => 'WASABI_KEY',
|
||||
'value' => $request->input('storage.key'),
|
||||
],
|
||||
[
|
||||
'name' => 'WASABI_SECRET',
|
||||
'value' => $request->input('storage.secret'),
|
||||
],
|
||||
[
|
||||
'name' => 'WASABI_ENDPOINT',
|
||||
'value' => $request->input('storage.endpoint'),
|
||||
],
|
||||
[
|
||||
'name' => 'WASABI_REGION',
|
||||
'value' => $request->input('storage.region'),
|
||||
],
|
||||
[
|
||||
'name' => 'WASABI_BUCKET',
|
||||
'value' => $request->input('storage.bucket'),
|
||||
],
|
||||
]);
|
||||
|
||||
} else if ($storage_driver === 'backblaze') {
|
||||
|
||||
$storage = collect([
|
||||
[
|
||||
'name' => 'FILESYSTEM_DRIVER',
|
||||
'value' => $request->input('storage.driver'),
|
||||
],
|
||||
[
|
||||
'name' => 'BACKBLAZE_KEY',
|
||||
'value' => $request->input('storage.key'),
|
||||
],
|
||||
[
|
||||
'name' => 'BACKBLAZE_SECRET',
|
||||
'value' => $request->input('storage.secret'),
|
||||
],
|
||||
[
|
||||
'name' => 'BACKBLAZE_ENDPOINT',
|
||||
'value' => $request->input('storage.endpoint'),
|
||||
],
|
||||
[
|
||||
'name' => 'BACKBLAZE_REGION',
|
||||
'value' => $request->input('storage.region'),
|
||||
],
|
||||
[
|
||||
'name' => 'BACKBLAZE_BUCKET',
|
||||
'value' => $request->input('storage.bucket'),
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
// Store storage driver options
|
||||
$storage->each(function ($col) {
|
||||
$this->setEnvironmentValue($col['name'], $col['value']);
|
||||
});
|
||||
|
||||
// Get options
|
||||
$mail = collect([
|
||||
[
|
||||
'name' => 'MAIL_DRIVER',
|
||||
'value' => $request->input('mail.driver'),
|
||||
],
|
||||
[
|
||||
'name' => 'MAIL_HOST',
|
||||
'value' => $request->input('mail.host'),
|
||||
],
|
||||
[
|
||||
'name' => 'MAIL_PORT',
|
||||
'value' => $request->input('mail.port'),
|
||||
],
|
||||
[
|
||||
'name' => 'MAIL_USERNAME',
|
||||
'value' => $request->input('mail.username'),
|
||||
],
|
||||
[
|
||||
'name' => 'MAIL_PASSWORD',
|
||||
'value' => $request->input('mail.password'),
|
||||
],
|
||||
[
|
||||
'name' => 'MAIL_ENCRYPTION',
|
||||
'value' => $request->input('mail.encryption'),
|
||||
],
|
||||
]);
|
||||
|
||||
// Store mail options
|
||||
$mail->each(function ($col) {
|
||||
$this->setEnvironmentValue($col['name'], $col['value']);
|
||||
});
|
||||
|
||||
return response('Done', 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store app settings
|
||||
* @param StoreAppSetupRequest $request
|
||||
* @return ResponseFactory|\Illuminate\Http\Response
|
||||
*/
|
||||
public function store_app_settings(StoreAppSetupRequest $request)
|
||||
{
|
||||
// Store Logo
|
||||
if ($request->hasFile('logo')) {
|
||||
$logo = store_system_image($request->file('logo'), 'system');
|
||||
}
|
||||
|
||||
// Store favicon
|
||||
if ($request->hasFile('favicon')) {
|
||||
$favicon = store_system_image($request->file('favicon'), 'system');
|
||||
}
|
||||
|
||||
// Get options
|
||||
$settings = collect([
|
||||
[
|
||||
'name' => 'app_title',
|
||||
'value' => $request->title,
|
||||
],
|
||||
[
|
||||
'name' => 'app_description',
|
||||
'value' => $request->description,
|
||||
],
|
||||
[
|
||||
'name' => 'app_logo',
|
||||
'value' => $request->hasFile('logo') ? $logo : null,
|
||||
],
|
||||
[
|
||||
'name' => 'app_favicon',
|
||||
'value' => $request->hasFile('favicon') ? $favicon : null,
|
||||
],
|
||||
[
|
||||
'name' => 'google_analytics',
|
||||
'value' => $request->googleAnalytics,
|
||||
],
|
||||
[
|
||||
'name' => 'contact_email',
|
||||
'value' => $request->contactMail,
|
||||
],
|
||||
[
|
||||
'name' => 'registration',
|
||||
'value' => $request->userRegistration,
|
||||
],
|
||||
[
|
||||
'name' => 'storage_limitation',
|
||||
'value' => $request->storageLimitation,
|
||||
],
|
||||
[
|
||||
'name' => 'storage_default',
|
||||
'value' => $request->defaultStorage,
|
||||
],
|
||||
]);
|
||||
|
||||
// Store options
|
||||
$settings->each(function ($col) {
|
||||
Setting::updateOrCreate(['name' => $col['name']], $col);
|
||||
});
|
||||
|
||||
return response('Done', 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and login admin account
|
||||
*
|
||||
* @param Request $request
|
||||
* @return ResponseFactory|\Illuminate\Http\Response|\Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function create_admin_account(Request $request)
|
||||
{
|
||||
// Validate request
|
||||
$request->validate([
|
||||
'email' => 'required|string|email|unique:users',
|
||||
'password' => 'required|string|min:6|confirmed',
|
||||
'name' => 'required|string',
|
||||
'avatar' => 'sometimes|file',
|
||||
]);
|
||||
|
||||
// Store avatar
|
||||
if ($request->hasFile('avatar')) {
|
||||
$avatar = store_avatar($request->file('avatar'), 'avatars');
|
||||
}
|
||||
|
||||
// Create user
|
||||
$user = User::create([
|
||||
'avatar' => $request->hasFile('avatar') ? $avatar : null,
|
||||
'name' => $request->name,
|
||||
'role' => 'admin',
|
||||
'email' => $request->email,
|
||||
'password' => Hash::make($request->password),
|
||||
]);
|
||||
|
||||
// Create settings
|
||||
// TODO: set default storage capacity
|
||||
UserSettings::create([
|
||||
'user_id' => $user->id,
|
||||
'storage_capacity' => 1,
|
||||
]);
|
||||
|
||||
// Retrieve access token
|
||||
$response = Route::dispatch(self::make_login_request($request));
|
||||
|
||||
// Send access token to user if request is successful
|
||||
if ($response->isSuccessful()) {
|
||||
|
||||
$data = json_decode($response->content(), true);
|
||||
|
||||
return response('Admin was created', 200)->cookie('access_token', $data['access_token'], 43200);
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make login request for get access token
|
||||
*
|
||||
* @param Request $request
|
||||
* @return Request
|
||||
*/
|
||||
private static function make_login_request($request)
|
||||
{
|
||||
$request->request->add([
|
||||
'grant_type' => 'password',
|
||||
'client_id' => config('services.passport.client_id'),
|
||||
'client_secret' => config('services.passport.client_secret'),
|
||||
'username' => $request->email,
|
||||
'password' => $request->password,
|
||||
'scope' => 'master',
|
||||
]);
|
||||
|
||||
return Request::create(url('/oauth/token'), 'POST', $request->all());
|
||||
}
|
||||
|
||||
/**
|
||||
* Set environment value
|
||||
*
|
||||
* @param $key
|
||||
* @param $value
|
||||
*/
|
||||
public function setEnvironmentValue($key, $value)
|
||||
{
|
||||
$env_path = app()->environmentFilePath();
|
||||
|
||||
$escaped = preg_quote('=' . env($key), '/');
|
||||
|
||||
file_put_contents($env_path, preg_replace(
|
||||
"/^{$key}{$escaped}/m",
|
||||
$key . '=' . $value,
|
||||
file_get_contents($env_path)
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -179,6 +179,28 @@ function store_avatar($image, $path)
|
||||
return $path . '/' . $image_path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store system image
|
||||
*
|
||||
* @param $image
|
||||
* @param $path
|
||||
* @return string
|
||||
*/
|
||||
function store_system_image($image, $path)
|
||||
{
|
||||
// Get directory
|
||||
$path = check_directory($path);
|
||||
|
||||
// Store avatar
|
||||
$image_path = Str::random(8) . '-' . str_replace(' ', '', $image->getClientOriginalName());
|
||||
|
||||
// Store image to disk
|
||||
Storage::putFileAs($path, $image, $image_path);
|
||||
|
||||
// Return path to image
|
||||
return $path . '/' . $image_path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if directory exist, if no, then create it
|
||||
*
|
||||
|
||||
38
app/Http/Requests/SetupWizard/StoreAppSetupRequest.php
Normal file
38
app/Http/Requests/SetupWizard/StoreAppSetupRequest.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests\SetupWizard;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class StoreAppSetupRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'title' => 'required|string',
|
||||
'description' => 'required|string',
|
||||
'logo' => 'sometimes|file',
|
||||
'favicon' => 'sometimes|file',
|
||||
'contactMail' => 'required|email',
|
||||
'googleAnalytics' => 'required|string',
|
||||
'defaultStorage' => 'required|digits_between:1,9',
|
||||
'userRegistration' => 'required|boolean',
|
||||
'storageLimitation' => 'required|boolean',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests\SetupWizard;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class StoreDatabaseCredentialsRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'connection' => 'required|string',
|
||||
'host' => 'required|string',
|
||||
'port' => 'required|string',
|
||||
'name' => 'required|string',
|
||||
'username' => 'required|string',
|
||||
'password' => 'required|string',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests\SetupWizard;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class StoreEnvironmentSetupRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'storage' => 'required|array',
|
||||
'storage.driver' => 'required|string',
|
||||
'storage.key' => 'sometimes|nullable|string',
|
||||
'storage.secret' => 'sometimes|nullable|string',
|
||||
'storage.endpoint' => 'sometimes|nullable|string',
|
||||
'storage.region' => 'sometimes|nullable|string',
|
||||
'storage.bucket' => 'sometimes|nullable|string',
|
||||
'mail' => 'required|array',
|
||||
'mail.driver' => 'required|string',
|
||||
'mail.host' => 'required|string',
|
||||
'mail.port' => 'required|string',
|
||||
'mail.username' => 'required|string',
|
||||
'mail.password' => 'required|string',
|
||||
'mail.encryption' => 'required|string',
|
||||
];
|
||||
}
|
||||
}
|
||||
37
app/Http/Requests/SetupWizard/StoreStripeBillingRequest.php
Normal file
37
app/Http/Requests/SetupWizard/StoreStripeBillingRequest.php
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests\SetupWizard;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class StoreStripeBillingRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'billing_phone_number' => 'sometimes|nullable|string',
|
||||
'billing_postal_code' => 'required|string',
|
||||
'billing_vat_number' => 'required|string',
|
||||
'billing_address' => 'required|string',
|
||||
'billing_country' => 'required|string',
|
||||
'billing_state' => 'required|string',
|
||||
'billing_city' => 'required|string',
|
||||
'billing_name' => 'required|string',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests\SetupWizard;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class StoreStripeCredentialsRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'currency' => 'required|string',
|
||||
'webhookSecret' => 'required|string',
|
||||
'secret' => 'required|string',
|
||||
'key' => 'required|string',
|
||||
];
|
||||
}
|
||||
}
|
||||
35
app/Http/Requests/SetupWizard/StoreStripePlansRequest.php
Normal file
35
app/Http/Requests/SetupWizard/StoreStripePlansRequest.php
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests\SetupWizard;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class StoreStripePlansRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'plans' => 'required|array',
|
||||
'plans.*.type' => 'required|string',
|
||||
'plans.*.attributes.name' => 'required|string',
|
||||
'plans.*.attributes.price' => 'required|string',
|
||||
'plans.*.attributes.description' => 'sometimes|nullable|string',
|
||||
'plans.*.attributes.capacity' => 'required|digits_between:1,9',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,9 @@ namespace App\Providers;
|
||||
use Illuminate\Support\Facades\App;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Laravel\Passport\Console\ClientCommand;
|
||||
use Laravel\Passport\Console\InstallCommand;
|
||||
use Laravel\Passport\Console\KeysCommand;
|
||||
|
||||
class AppServiceProvider extends ServiceProvider
|
||||
{
|
||||
@@ -31,5 +34,12 @@ class AppServiceProvider extends ServiceProvider
|
||||
|
||||
// Set locale for carbon dates
|
||||
setlocale(LC_TIME, $get_time_locale);
|
||||
|
||||
// Install passport commands
|
||||
$this->commands([
|
||||
InstallCommand::class,
|
||||
ClientCommand::class,
|
||||
KeysCommand::class,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
namespace App\Services;
|
||||
|
||||
use App\User;
|
||||
use Artisan;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Str;
|
||||
use Laravel\Cashier\Exceptions\IncompletePayment;
|
||||
use Stripe;
|
||||
@@ -16,9 +18,16 @@ class StripeService
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
dd(config('stripe.secret'));
|
||||
|
||||
$this->stripe = Stripe::make(env('STRIPE_SECRET'), '2020-03-02');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Stripe account details
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getAccountDetails()
|
||||
{
|
||||
$account = $this->stripe->account()->details();
|
||||
@@ -112,6 +121,8 @@ class StripeService
|
||||
}
|
||||
|
||||
/**
|
||||
* Update customer details
|
||||
*
|
||||
* @param $user
|
||||
*/
|
||||
public function updateCustomerDetails($user)
|
||||
@@ -205,22 +216,38 @@ class StripeService
|
||||
/**
|
||||
* Create plan
|
||||
*
|
||||
* @param $request
|
||||
* @param $data
|
||||
* @return mixed
|
||||
*/
|
||||
public function createPlan($request)
|
||||
public function createPlan($data)
|
||||
{
|
||||
if ($data instanceof Request) {
|
||||
$plan = [
|
||||
'name' => $data->input('attributes.name'),
|
||||
'description' => $data->input('attributes.description'),
|
||||
'price' => $data->input('attributes.price'),
|
||||
'capacity' => $data->input('attributes.capacity'),
|
||||
];
|
||||
} else {
|
||||
$plan = [
|
||||
'name' => $data['attributes']['name'],
|
||||
'description' => $data['attributes']['description'],
|
||||
'price' => $data['attributes']['price'],
|
||||
'capacity' => $data['attributes']['capacity'],
|
||||
];
|
||||
}
|
||||
|
||||
$product = $this->stripe->products()->create([
|
||||
'name' => $request->input('attributes.name'),
|
||||
'description' => $request->input('attributes.description'),
|
||||
'name' => $plan['name'],
|
||||
'description' => $plan['description'],
|
||||
'metadata' => [
|
||||
'capacity' => $request->input('attributes.capacity')
|
||||
'capacity' => $plan['capacity']
|
||||
]
|
||||
]);
|
||||
|
||||
$plan = $this->stripe->plans()->create([
|
||||
'id' => Str::slug($request->input('attributes.name')),
|
||||
'amount' => $request->input('attributes.price'),
|
||||
'id' => Str::slug($plan['name']),
|
||||
'amount' => $plan['price'],
|
||||
'currency' => 'USD',
|
||||
'interval' => 'month',
|
||||
'product' => $product['id'],
|
||||
|
||||
@@ -164,6 +164,7 @@ return [
|
||||
|
||||
TeamTNT\Scout\TNTSearchScoutServiceProvider::class,
|
||||
Intervention\Image\ImageServiceProvider::class,
|
||||
Laravel\Passport\PassportServiceProvider::class,
|
||||
|
||||
/*
|
||||
* Package Service Providers...
|
||||
|
||||
@@ -73,6 +73,24 @@ return [
|
||||
'bucket' => env('DO_SPACES_BUCKET'),
|
||||
],
|
||||
|
||||
'wasabi' => [
|
||||
'driver' => 's3',
|
||||
'key' => env('WASABI_KEY'),
|
||||
'secret' => env('WASABI_SECRET'),
|
||||
'endpoint' => env('WASABI_ENDPOINT'),
|
||||
'region' => env('WASABI_REGION'),
|
||||
'bucket' => env('WASABI_BUCKET'),
|
||||
],
|
||||
|
||||
'backblaze' => [
|
||||
'driver' => 's3',
|
||||
'key' => env('BACKBLAZE_KEY'),
|
||||
'secret' => env('BACKBLAZE_SECRET'),
|
||||
'endpoint' => env('BACKBLAZE_ENDPOINT'),
|
||||
'region' => env('BACKBLAZE_REGION'),
|
||||
'bucket' => env('BACKBLAZE_BUCKET'),
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
];
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateOauthAuthCodesTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('oauth_auth_codes', function (Blueprint $table) {
|
||||
$table->string('id', 100)->primary();
|
||||
$table->unsignedBigInteger('user_id')->index();
|
||||
$table->unsignedBigInteger('client_id');
|
||||
$table->text('scopes')->nullable();
|
||||
$table->boolean('revoked');
|
||||
$table->dateTime('expires_at')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('oauth_auth_codes');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateOauthAccessTokensTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('oauth_access_tokens', function (Blueprint $table) {
|
||||
$table->string('id', 100)->primary();
|
||||
$table->unsignedBigInteger('user_id')->nullable()->index();
|
||||
$table->unsignedBigInteger('client_id');
|
||||
$table->string('name')->nullable();
|
||||
$table->text('scopes')->nullable();
|
||||
$table->boolean('revoked');
|
||||
$table->timestamps();
|
||||
$table->dateTime('expires_at')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('oauth_access_tokens');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateOauthRefreshTokensTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('oauth_refresh_tokens', function (Blueprint $table) {
|
||||
$table->string('id', 100)->primary();
|
||||
$table->string('access_token_id', 100);
|
||||
$table->boolean('revoked');
|
||||
$table->dateTime('expires_at')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('oauth_refresh_tokens');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateOauthClientsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('oauth_clients', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
$table->unsignedBigInteger('user_id')->nullable()->index();
|
||||
$table->string('name');
|
||||
$table->string('secret', 100)->nullable();
|
||||
$table->text('redirect');
|
||||
$table->boolean('personal_access_client');
|
||||
$table->boolean('password_client');
|
||||
$table->boolean('revoked');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('oauth_clients');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateOauthPersonalAccessClientsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('oauth_personal_access_clients', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
$table->unsignedBigInteger('client_id');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('oauth_personal_access_clients');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateCustomerColumns extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
$table->string('stripe_id')->nullable()->index();
|
||||
$table->string('card_brand')->nullable();
|
||||
$table->string('card_last_four', 4)->nullable();
|
||||
$table->timestamp('trial_ends_at')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
$table->dropColumn([
|
||||
'stripe_id',
|
||||
'card_brand',
|
||||
'card_last_four',
|
||||
'trial_ends_at',
|
||||
]);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateSubscriptionsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('subscriptions', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
$table->unsignedBigInteger('user_id');
|
||||
$table->string('name');
|
||||
$table->string('stripe_id');
|
||||
$table->string('stripe_status');
|
||||
$table->string('stripe_plan')->nullable();
|
||||
$table->integer('quantity')->nullable();
|
||||
$table->timestamp('trial_ends_at')->nullable();
|
||||
$table->timestamp('ends_at')->nullable();
|
||||
$table->timestamps();
|
||||
|
||||
$table->index(['user_id', 'stripe_status']);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('subscriptions');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateSubscriptionItemsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('subscription_items', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
$table->unsignedBigInteger('subscription_id');
|
||||
$table->string('stripe_id')->index();
|
||||
$table->string('stripe_plan');
|
||||
$table->integer('quantity');
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique(['subscription_id', 'stripe_plan']);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('subscription_items');
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreatePaymentGatewaysTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('payment_gateways', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
$table->boolean('status')->default(0);
|
||||
$table->boolean('sandbox')->default(0);
|
||||
$table->text('name');
|
||||
$table->text('slug');
|
||||
$table->text('logo');
|
||||
$table->text('client_id')->nullable();
|
||||
$table->text('secret')->nullable();
|
||||
$table->text('webhook')->nullable();
|
||||
$table->bigInteger('payment_processed')->default(0);
|
||||
$table->longText('optional')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('payment_gateways');
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class PaymentGatewaysSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
// Create Stripe default record
|
||||
DB::table('payment_gateways')->insert([
|
||||
'logo' => '/assets/images/stripe-logo-thumbnail.png',
|
||||
'name' => 'Stripe',
|
||||
'slug' => 'stripe',
|
||||
]);
|
||||
}
|
||||
}
|
||||
13
public/assets/icons/stripe-service.svg
Normal file
13
public/assets/icons/stripe-service.svg
Normal file
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="96px" height="40px" viewBox="0 0 96 40" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 55.2 (78181) - https://sketchapp.com -->
|
||||
<title>stripe-service</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<g id="Setup-Wizard" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="3.-Payment-Select" transform="translate(-504.000000, -360.000000)" fill="#FFFFFF" fill-rule="nonzero">
|
||||
<g id="Payment-option" transform="translate(476.000000, 333.000000)">
|
||||
<path d="M34.746625,42.6742143 C34.746625,41.6329466 35.5999375,41.2322857 37.0135,41.2322857 C39.04,41.2322857 41.5999375,41.8466073 43.626625,42.9413841 L43.626625,36.6661785 C41.413375,35.7850625 39.22675,35.4379107 37.0135,35.4379107 C31.6,35.4379107 28,38.2684465 28,42.9948932 C28,50.3645 38.13325,49.1897413 38.13325,52.3674289 C38.13325,53.595509 37.06675,53.9961699 35.5733125,53.9961699 C33.3600625,53.9961699 30.5333125,53.0882055 28.29325,51.8599377 L28.29325,58.2151252 C30.7733125,59.2832413 33.28,59.7370358 35.5733125,59.7370358 C41.1199375,59.7370358 44.9333125,56.9868574 44.9333125,52.2070895 C44.9066875,44.2498216 34.746625,45.6649018 34.746625,42.6742143 Z M52.77325,30.0975179 L46.266625,31.4859374 L46.24,52.8745447 C46.24,56.8267057 49.2000625,59.7370358 53.14675,59.7370358 C55.333375,59.7370358 56.9333125,59.3365627 57.81325,58.8559198 L57.81325,53.4353573 C56.960125,53.7825091 52.746625,55.0107769 52.746625,51.0588036 L52.746625,41.5794375 L57.81325,41.5794375 L57.81325,35.8918929 L52.746625,35.8918929 L52.77325,30.0975179 Z M66.10675,37.8677857 L65.68,35.8918929 L59.92,35.8918929 L59.92,59.2563929 L66.58675,59.2563929 L66.58675,43.422027 C68.159875,41.3659645 70.8266875,41.739777 71.653375,42.0334197 L71.653375,35.8918929 C70.8000625,35.5714017 67.6800625,34.9839285 66.10675,37.8677857 Z M73.2799375,35.8918929 L79.9733125,35.8918929 L79.9733125,59.2563929 L73.2799375,59.2563929 L73.2799375,35.8918929 L73.2799375,35.8918929 Z M73.2799375,33.8624911 L79.9733125,32.4205625 L79.9733125,27 L73.2799375,28.4152679 L73.2799375,33.8623033 L73.2799375,33.8624911 Z M93.8933125,35.4379107 C91.2799375,35.4379107 89.5999375,36.6661785 88.66675,37.5208216 L88.319875,35.8652322 L82.453375,35.8652322 L82.453375,67 L89.1199375,65.5849198 L89.14675,58.0281251 C90.10675,58.7224287 91.5199375,59.7103751 93.8666875,59.7103751 C98.6400625,59.7103751 102.986687,55.8652322 102.986687,47.4006609 C102.960062,39.6568661 98.56,35.4379107 93.8933125,35.4379107 L93.8933125,35.4379107 Z M92.293375,53.8358304 C90.7200625,53.8358304 89.7865,53.2752056 89.14675,52.580902 L89.1199375,42.6742143 C89.8133125,41.8999287 90.7733125,41.3659645 92.293375,41.3659645 C94.72,41.3659645 96.4,44.0894822 96.4,47.5874732 C96.4,51.165634 94.746625,53.8358304 92.293375,53.8358304 L92.293375,53.8358304 Z M124,47.667643 C124,40.8318125 120.69325,35.4379107 114.373375,35.4379107 C108.0265,35.4379107 104.1865,40.8320003 104.1865,47.6143217 C104.1865,55.6515715 108.720063,59.7103751 115.2265,59.7103751 C118.399938,59.7103751 120.799938,58.9894108 122.61325,57.9748038 L122.61325,52.6342233 C120.800125,53.5421877 118.72,54.1030003 116.08,54.1030003 C113.49325,54.1030003 111.199938,53.1950359 110.906688,50.0441966 L123.94675,50.0441966 C123.94675,49.696857 124,48.3084375 124,47.667643 Z M110.826625,45.1309376 C110.826625,42.1135894 112.66675,40.8584732 114.34675,40.8584732 C115.973313,40.8584732 117.70675,42.1135894 117.70675,45.1309376 L110.826625,45.1309376 Z" id="stripe-service"></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.6 KiB |
@@ -10,5 +10,276 @@
|
||||
"/js/main.ec4459f3993385a8ffb0.hot-update.js": "/js/main.ec4459f3993385a8ffb0.hot-update.js",
|
||||
"/js/main.4aa483cf186b82e6f133.hot-update.js": "/js/main.4aa483cf186b82e6f133.hot-update.js",
|
||||
"/js/main.0b62890fe58f6191cff2.hot-update.js": "/js/main.0b62890fe58f6191cff2.hot-update.js",
|
||||
"/js/main.8f85a1128dbc59267b4d.hot-update.js": "/js/main.8f85a1128dbc59267b4d.hot-update.js"
|
||||
"/js/main.8f85a1128dbc59267b4d.hot-update.js": "/js/main.8f85a1128dbc59267b4d.hot-update.js",
|
||||
"/js/main.f57c08e4f6453554eef7.hot-update.js": "/js/main.f57c08e4f6453554eef7.hot-update.js",
|
||||
"/js/main.49806237173f17d9145e.hot-update.js": "/js/main.49806237173f17d9145e.hot-update.js",
|
||||
"/js/main.a66ef529551f3908fa83.hot-update.js": "/js/main.a66ef529551f3908fa83.hot-update.js",
|
||||
"/js/main.d250bde2dfd0cb83ead1.hot-update.js": "/js/main.d250bde2dfd0cb83ead1.hot-update.js",
|
||||
"/js/main.86c738013294c543bf9f.hot-update.js": "/js/main.86c738013294c543bf9f.hot-update.js",
|
||||
"/js/main.7d5ddf17e4f5ac5d7774.hot-update.js": "/js/main.7d5ddf17e4f5ac5d7774.hot-update.js",
|
||||
"/js/main.ac3441b3dd689cf2a474.hot-update.js": "/js/main.ac3441b3dd689cf2a474.hot-update.js",
|
||||
"/js/main.c17831922217a8e0ca69.hot-update.js": "/js/main.c17831922217a8e0ca69.hot-update.js",
|
||||
"/js/main.047d29a9f0934470628c.hot-update.js": "/js/main.047d29a9f0934470628c.hot-update.js",
|
||||
"/js/main.a12c2cbb9d4f587cb915.hot-update.js": "/js/main.a12c2cbb9d4f587cb915.hot-update.js",
|
||||
"/js/main.eb91f9aef7a46fc4d97d.hot-update.js": "/js/main.eb91f9aef7a46fc4d97d.hot-update.js",
|
||||
"/js/main.8950f2c1f965b34c67c8.hot-update.js": "/js/main.8950f2c1f965b34c67c8.hot-update.js",
|
||||
"/js/main.c181b6f235365cc77806.hot-update.js": "/js/main.c181b6f235365cc77806.hot-update.js",
|
||||
"/js/main.432d249065d06227b881.hot-update.js": "/js/main.432d249065d06227b881.hot-update.js",
|
||||
"/js/main.6ab44d447ea09576bf79.hot-update.js": "/js/main.6ab44d447ea09576bf79.hot-update.js",
|
||||
"/js/main.f877b4f51fa54d34a703.hot-update.js": "/js/main.f877b4f51fa54d34a703.hot-update.js",
|
||||
"/js/main.bfb7a5ed9a7a787bf1b1.hot-update.js": "/js/main.bfb7a5ed9a7a787bf1b1.hot-update.js",
|
||||
"/js/main.7f79a324bd9f3e34330e.hot-update.js": "/js/main.7f79a324bd9f3e34330e.hot-update.js",
|
||||
"/js/main.7ab0530f4fa616fd6479.hot-update.js": "/js/main.7ab0530f4fa616fd6479.hot-update.js",
|
||||
"/js/main.10376c1cb6a085c800d6.hot-update.js": "/js/main.10376c1cb6a085c800d6.hot-update.js",
|
||||
"/js/main.c5c07ed33eaae7e74bb0.hot-update.js": "/js/main.c5c07ed33eaae7e74bb0.hot-update.js",
|
||||
"/js/main.b3898569822a4bea728a.hot-update.js": "/js/main.b3898569822a4bea728a.hot-update.js",
|
||||
"/js/main.cb3e97b7379bb2690e80.hot-update.js": "/js/main.cb3e97b7379bb2690e80.hot-update.js",
|
||||
"/js/main.3907d0c494c707a2e526.hot-update.js": "/js/main.3907d0c494c707a2e526.hot-update.js",
|
||||
"/js/main.30c46b47c913c6750487.hot-update.js": "/js/main.30c46b47c913c6750487.hot-update.js",
|
||||
"/js/main.63ac156900e0c0a6a163.hot-update.js": "/js/main.63ac156900e0c0a6a163.hot-update.js",
|
||||
"/js/main.b0b834bae1baf11b7d2e.hot-update.js": "/js/main.b0b834bae1baf11b7d2e.hot-update.js",
|
||||
"/js/main.ddb0da2f7522ea677587.hot-update.js": "/js/main.ddb0da2f7522ea677587.hot-update.js",
|
||||
"/js/main.6b767b34769556b6f22e.hot-update.js": "/js/main.6b767b34769556b6f22e.hot-update.js",
|
||||
"/js/main.388c60436fa8234d3415.hot-update.js": "/js/main.388c60436fa8234d3415.hot-update.js",
|
||||
"/js/main.3c144c24f3ae3943bc90.hot-update.js": "/js/main.3c144c24f3ae3943bc90.hot-update.js",
|
||||
"/js/main.bf2d7c2fb972e7d888cc.hot-update.js": "/js/main.bf2d7c2fb972e7d888cc.hot-update.js",
|
||||
"/js/main.a1260c2810a8264c42e2.hot-update.js": "/js/main.a1260c2810a8264c42e2.hot-update.js",
|
||||
"/js/main.d4e8446c38a1548413bb.hot-update.js": "/js/main.d4e8446c38a1548413bb.hot-update.js",
|
||||
"/js/main.129032d6ff4ea189d691.hot-update.js": "/js/main.129032d6ff4ea189d691.hot-update.js",
|
||||
"/js/main.bdff6b7e32d4e63268a9.hot-update.js": "/js/main.bdff6b7e32d4e63268a9.hot-update.js",
|
||||
"/js/main.bb35fbbacbb8cc6a21be.hot-update.js": "/js/main.bb35fbbacbb8cc6a21be.hot-update.js",
|
||||
"/js/main.f49adc3a4f0766e49fb8.hot-update.js": "/js/main.f49adc3a4f0766e49fb8.hot-update.js",
|
||||
"/js/main.57e0a8a6d1694937d714.hot-update.js": "/js/main.57e0a8a6d1694937d714.hot-update.js",
|
||||
"/js/main.62cbda0a1a4c8c1e7ddb.hot-update.js": "/js/main.62cbda0a1a4c8c1e7ddb.hot-update.js",
|
||||
"/js/main.bfe07da70f88cbc00a18.hot-update.js": "/js/main.bfe07da70f88cbc00a18.hot-update.js",
|
||||
"/js/main.1fc88be6d6fc7818d38c.hot-update.js": "/js/main.1fc88be6d6fc7818d38c.hot-update.js",
|
||||
"/js/main.6575481131214e9c2891.hot-update.js": "/js/main.6575481131214e9c2891.hot-update.js",
|
||||
"/js/main.c99aec40c2c3ee3eac0d.hot-update.js": "/js/main.c99aec40c2c3ee3eac0d.hot-update.js",
|
||||
"/js/main.e525917a75cbb76c8b26.hot-update.js": "/js/main.e525917a75cbb76c8b26.hot-update.js",
|
||||
"/js/main.22c20ab0c219852049ad.hot-update.js": "/js/main.22c20ab0c219852049ad.hot-update.js",
|
||||
"/js/main.df5b1efd5e4b9c9bac80.hot-update.js": "/js/main.df5b1efd5e4b9c9bac80.hot-update.js",
|
||||
"/js/main.26a5f721dbce5fad22f7.hot-update.js": "/js/main.26a5f721dbce5fad22f7.hot-update.js",
|
||||
"/js/main.0d520a66a47c10f5f5e2.hot-update.js": "/js/main.0d520a66a47c10f5f5e2.hot-update.js",
|
||||
"/js/main.e3d18eca82e2431524f8.hot-update.js": "/js/main.e3d18eca82e2431524f8.hot-update.js",
|
||||
"/js/main.3f7d42db34a8638638f5.hot-update.js": "/js/main.3f7d42db34a8638638f5.hot-update.js",
|
||||
"/js/main.12b18448bcb03190696e.hot-update.js": "/js/main.12b18448bcb03190696e.hot-update.js",
|
||||
"/js/main.f1bdbd6d4e1b6125a751.hot-update.js": "/js/main.f1bdbd6d4e1b6125a751.hot-update.js",
|
||||
"/js/main.7f954acdffdef3ba1b4e.hot-update.js": "/js/main.7f954acdffdef3ba1b4e.hot-update.js",
|
||||
"/js/main.8af19bb7c91195200c83.hot-update.js": "/js/main.8af19bb7c91195200c83.hot-update.js",
|
||||
"/js/main.83950ac988f7d52fd4db.hot-update.js": "/js/main.83950ac988f7d52fd4db.hot-update.js",
|
||||
"/js/main.2668f11eaec9054d4f85.hot-update.js": "/js/main.2668f11eaec9054d4f85.hot-update.js",
|
||||
"/js/main.0cb7453215e2457e963d.hot-update.js": "/js/main.0cb7453215e2457e963d.hot-update.js",
|
||||
"/js/main.628d6b45839c0bd50ffa.hot-update.js": "/js/main.628d6b45839c0bd50ffa.hot-update.js",
|
||||
"/js/main.494744531adf85766dd7.hot-update.js": "/js/main.494744531adf85766dd7.hot-update.js",
|
||||
"/js/main.e234521251663454e5bb.hot-update.js": "/js/main.e234521251663454e5bb.hot-update.js",
|
||||
"/js/main.0f8aceea8e819824f7f4.hot-update.js": "/js/main.0f8aceea8e819824f7f4.hot-update.js",
|
||||
"/js/main.1c4b31ce03bd281c7af0.hot-update.js": "/js/main.1c4b31ce03bd281c7af0.hot-update.js",
|
||||
"/js/main.23395410004c25e9e752.hot-update.js": "/js/main.23395410004c25e9e752.hot-update.js",
|
||||
"/js/main.dec2f01b8b3413b07cce.hot-update.js": "/js/main.dec2f01b8b3413b07cce.hot-update.js",
|
||||
"/js/main.90d5738c7eca52e99fa1.hot-update.js": "/js/main.90d5738c7eca52e99fa1.hot-update.js",
|
||||
"/js/main.350c381ae5ef35075008.hot-update.js": "/js/main.350c381ae5ef35075008.hot-update.js",
|
||||
"/js/main.7ff8cd4e0f8129b28020.hot-update.js": "/js/main.7ff8cd4e0f8129b28020.hot-update.js",
|
||||
"/js/main.36981f38ef6dbe1ad2ef.hot-update.js": "/js/main.36981f38ef6dbe1ad2ef.hot-update.js",
|
||||
"/js/main.c72e92249cae6c72de71.hot-update.js": "/js/main.c72e92249cae6c72de71.hot-update.js",
|
||||
"/js/main.8d4d5d88816dfa6a6c3a.hot-update.js": "/js/main.8d4d5d88816dfa6a6c3a.hot-update.js",
|
||||
"/js/main.6315104b66153dff7594.hot-update.js": "/js/main.6315104b66153dff7594.hot-update.js",
|
||||
"/js/main.4c5a2605aac797ae5094.hot-update.js": "/js/main.4c5a2605aac797ae5094.hot-update.js",
|
||||
"/js/main.06385ccc6884270b68f0.hot-update.js": "/js/main.06385ccc6884270b68f0.hot-update.js",
|
||||
"/js/main.b515044cb3386d6eb38c.hot-update.js": "/js/main.b515044cb3386d6eb38c.hot-update.js",
|
||||
"/js/main.daf3544f7ebd524ba8b2.hot-update.js": "/js/main.daf3544f7ebd524ba8b2.hot-update.js",
|
||||
"/js/main.f49dced487020b2401db.hot-update.js": "/js/main.f49dced487020b2401db.hot-update.js",
|
||||
"/js/main.61e51b120958c98e9b80.hot-update.js": "/js/main.61e51b120958c98e9b80.hot-update.js",
|
||||
"/js/main.4428c57138139124d638.hot-update.js": "/js/main.4428c57138139124d638.hot-update.js",
|
||||
"/js/main.2b05f7597b38aa32f3d3.hot-update.js": "/js/main.2b05f7597b38aa32f3d3.hot-update.js",
|
||||
"/js/main.b6055028d561f898e936.hot-update.js": "/js/main.b6055028d561f898e936.hot-update.js",
|
||||
"/js/main.78472a4d15e86cf01c4c.hot-update.js": "/js/main.78472a4d15e86cf01c4c.hot-update.js",
|
||||
"/js/main.210d791d65e133956107.hot-update.js": "/js/main.210d791d65e133956107.hot-update.js",
|
||||
"/js/main.ffa9b0ac8442e4d2f24b.hot-update.js": "/js/main.ffa9b0ac8442e4d2f24b.hot-update.js",
|
||||
"/js/main.e2a830fd08baece2fac6.hot-update.js": "/js/main.e2a830fd08baece2fac6.hot-update.js",
|
||||
"/js/main.d389a917baec2038604b.hot-update.js": "/js/main.d389a917baec2038604b.hot-update.js",
|
||||
"/js/main.3e0bc14c6d62109be8c1.hot-update.js": "/js/main.3e0bc14c6d62109be8c1.hot-update.js",
|
||||
"/js/main.f950652035d59e80ba88.hot-update.js": "/js/main.f950652035d59e80ba88.hot-update.js",
|
||||
"/js/main.f43b68d5594c47aa9da3.hot-update.js": "/js/main.f43b68d5594c47aa9da3.hot-update.js",
|
||||
"/js/main.e7caa0957bb1286588d4.hot-update.js": "/js/main.e7caa0957bb1286588d4.hot-update.js",
|
||||
"/js/main.95d769d0027eed99e6c1.hot-update.js": "/js/main.95d769d0027eed99e6c1.hot-update.js",
|
||||
"/js/main.77762b16026f7742cbfa.hot-update.js": "/js/main.77762b16026f7742cbfa.hot-update.js",
|
||||
"/js/main.dec59254037d7f896b86.hot-update.js": "/js/main.dec59254037d7f896b86.hot-update.js",
|
||||
"/js/main.a1cc927c6a50ee0c7c61.hot-update.js": "/js/main.a1cc927c6a50ee0c7c61.hot-update.js",
|
||||
"/js/main.bac3134e1b5eb0e23fea.hot-update.js": "/js/main.bac3134e1b5eb0e23fea.hot-update.js",
|
||||
"/js/main.d42c1993753ba7c6d7bc.hot-update.js": "/js/main.d42c1993753ba7c6d7bc.hot-update.js",
|
||||
"/js/main.fe48b2784aca36a6dfbc.hot-update.js": "/js/main.fe48b2784aca36a6dfbc.hot-update.js",
|
||||
"/js/main.f952b84184c741f68c44.hot-update.js": "/js/main.f952b84184c741f68c44.hot-update.js",
|
||||
"/js/main.22f72f1e3bcce35c118d.hot-update.js": "/js/main.22f72f1e3bcce35c118d.hot-update.js",
|
||||
"/js/main.294962aafc6753ce4207.hot-update.js": "/js/main.294962aafc6753ce4207.hot-update.js",
|
||||
"/js/main.d36f9a9f6222aa74bc38.hot-update.js": "/js/main.d36f9a9f6222aa74bc38.hot-update.js",
|
||||
"/js/main.0118b88fb836f75f907c.hot-update.js": "/js/main.0118b88fb836f75f907c.hot-update.js",
|
||||
"/js/main.a615663568a78691f42f.hot-update.js": "/js/main.a615663568a78691f42f.hot-update.js",
|
||||
"/js/main.8881ab5062a0b552e57a.hot-update.js": "/js/main.8881ab5062a0b552e57a.hot-update.js",
|
||||
"/js/main.e49de8f4cfa70d1c4935.hot-update.js": "/js/main.e49de8f4cfa70d1c4935.hot-update.js",
|
||||
"/js/main.3dfcd8d63417db8974ce.hot-update.js": "/js/main.3dfcd8d63417db8974ce.hot-update.js",
|
||||
"/js/main.a9ce2ef2a19666a6479c.hot-update.js": "/js/main.a9ce2ef2a19666a6479c.hot-update.js",
|
||||
"/js/main.2c12c92e2c72d1e41fd0.hot-update.js": "/js/main.2c12c92e2c72d1e41fd0.hot-update.js",
|
||||
"/js/main.49f0ffdafe50bb99c8d4.hot-update.js": "/js/main.49f0ffdafe50bb99c8d4.hot-update.js",
|
||||
"/js/main.fa9016e6dd018e588900.hot-update.js": "/js/main.fa9016e6dd018e588900.hot-update.js",
|
||||
"/js/main.2b915d9e98818d0176a6.hot-update.js": "/js/main.2b915d9e98818d0176a6.hot-update.js",
|
||||
"/js/main.e87a7bb1c041232220b3.hot-update.js": "/js/main.e87a7bb1c041232220b3.hot-update.js",
|
||||
"/js/main.cd116661c4a1d6c5d69c.hot-update.js": "/js/main.cd116661c4a1d6c5d69c.hot-update.js",
|
||||
"/js/main.582a1d128d577aec65b7.hot-update.js": "/js/main.582a1d128d577aec65b7.hot-update.js",
|
||||
"/js/main.571bd2027b0ad0ac5962.hot-update.js": "/js/main.571bd2027b0ad0ac5962.hot-update.js",
|
||||
"/js/main.5e91c2e331ccdfd30443.hot-update.js": "/js/main.5e91c2e331ccdfd30443.hot-update.js",
|
||||
"/js/main.e7e13a6e09678c73939d.hot-update.js": "/js/main.e7e13a6e09678c73939d.hot-update.js",
|
||||
"/js/main.5116d49d4cfe29bd317c.hot-update.js": "/js/main.5116d49d4cfe29bd317c.hot-update.js",
|
||||
"/js/main.18894bdbb14cb9e2f4e6.hot-update.js": "/js/main.18894bdbb14cb9e2f4e6.hot-update.js",
|
||||
"/js/main.4d7deb55af6c2e02cb9f.hot-update.js": "/js/main.4d7deb55af6c2e02cb9f.hot-update.js",
|
||||
"/js/main.59c52d7a2f19a0cecb7c.hot-update.js": "/js/main.59c52d7a2f19a0cecb7c.hot-update.js",
|
||||
"/js/main.78c184149bfbc5ca6932.hot-update.js": "/js/main.78c184149bfbc5ca6932.hot-update.js",
|
||||
"/js/main.51cbbf7dc86f2a2012fa.hot-update.js": "/js/main.51cbbf7dc86f2a2012fa.hot-update.js",
|
||||
"/js/main.d012d1169cb534877cd0.hot-update.js": "/js/main.d012d1169cb534877cd0.hot-update.js",
|
||||
"/js/main.994c6d9f812ba73875da.hot-update.js": "/js/main.994c6d9f812ba73875da.hot-update.js",
|
||||
"/js/main.fb808d6466d2dd3de777.hot-update.js": "/js/main.fb808d6466d2dd3de777.hot-update.js",
|
||||
"/js/main.96d27c5eba7218a1953c.hot-update.js": "/js/main.96d27c5eba7218a1953c.hot-update.js",
|
||||
"/js/main.222ebcd0c3e9d30a10a7.hot-update.js": "/js/main.222ebcd0c3e9d30a10a7.hot-update.js",
|
||||
"/js/main.ec324946af056d4e9e40.hot-update.js": "/js/main.ec324946af056d4e9e40.hot-update.js",
|
||||
"/js/main.cf59f620f34b75f33d57.hot-update.js": "/js/main.cf59f620f34b75f33d57.hot-update.js",
|
||||
"/js/main.40983dcc9efdc97efb63.hot-update.js": "/js/main.40983dcc9efdc97efb63.hot-update.js",
|
||||
"/js/main.c047afe25c97538cd057.hot-update.js": "/js/main.c047afe25c97538cd057.hot-update.js",
|
||||
"/js/main.22af859fdba4f4884580.hot-update.js": "/js/main.22af859fdba4f4884580.hot-update.js",
|
||||
"/js/main.2977f19ca914fd5a8b6a.hot-update.js": "/js/main.2977f19ca914fd5a8b6a.hot-update.js",
|
||||
"/js/main.a5e6c89e84d4ad81c052.hot-update.js": "/js/main.a5e6c89e84d4ad81c052.hot-update.js",
|
||||
"/js/main.42b8fe8b9a648085bd8e.hot-update.js": "/js/main.42b8fe8b9a648085bd8e.hot-update.js",
|
||||
"/js/main.f0cfa4545280f946ba4a.hot-update.js": "/js/main.f0cfa4545280f946ba4a.hot-update.js",
|
||||
"/js/main.85e3c644ebd07ea49ec3.hot-update.js": "/js/main.85e3c644ebd07ea49ec3.hot-update.js",
|
||||
"/js/main.ece75643d67e9bcbe226.hot-update.js": "/js/main.ece75643d67e9bcbe226.hot-update.js",
|
||||
"/js/main.6a23a146600381ea9131.hot-update.js": "/js/main.6a23a146600381ea9131.hot-update.js",
|
||||
"/js/main.bc3bf0a6e8cc685e89a1.hot-update.js": "/js/main.bc3bf0a6e8cc685e89a1.hot-update.js",
|
||||
"/js/main.afece1ee9777a0f09f92.hot-update.js": "/js/main.afece1ee9777a0f09f92.hot-update.js",
|
||||
"/js/main.318eeefc5c617a59ee6d.hot-update.js": "/js/main.318eeefc5c617a59ee6d.hot-update.js",
|
||||
"/js/main.755f6694f38c8c77bd27.hot-update.js": "/js/main.755f6694f38c8c77bd27.hot-update.js",
|
||||
"/js/main.f18d478e890997d4f4da.hot-update.js": "/js/main.f18d478e890997d4f4da.hot-update.js",
|
||||
"/js/main.db0f3a4f426d3990e240.hot-update.js": "/js/main.db0f3a4f426d3990e240.hot-update.js",
|
||||
"/js/main.a405076120f1f39d6d6d.hot-update.js": "/js/main.a405076120f1f39d6d6d.hot-update.js",
|
||||
"/js/main.6cba9147fd829edb958f.hot-update.js": "/js/main.6cba9147fd829edb958f.hot-update.js",
|
||||
"/js/main.cd2fe4e3030ca6acc4e1.hot-update.js": "/js/main.cd2fe4e3030ca6acc4e1.hot-update.js",
|
||||
"/js/main.5cded47a7b477704e2eb.hot-update.js": "/js/main.5cded47a7b477704e2eb.hot-update.js",
|
||||
"/js/main.c7486336a6790360832d.hot-update.js": "/js/main.c7486336a6790360832d.hot-update.js",
|
||||
"/js/main.f7016f686c1057bc13e3.hot-update.js": "/js/main.f7016f686c1057bc13e3.hot-update.js",
|
||||
"/js/main.17c68ee60b815575d2f9.hot-update.js": "/js/main.17c68ee60b815575d2f9.hot-update.js",
|
||||
"/js/main.86a4ab5670f7d5cabb35.hot-update.js": "/js/main.86a4ab5670f7d5cabb35.hot-update.js",
|
||||
"/js/main.4dea91e54b0a38bba6e7.hot-update.js": "/js/main.4dea91e54b0a38bba6e7.hot-update.js",
|
||||
"/js/main.feb31c4f536800f14886.hot-update.js": "/js/main.feb31c4f536800f14886.hot-update.js",
|
||||
"/js/main.c47820cef3354299e493.hot-update.js": "/js/main.c47820cef3354299e493.hot-update.js",
|
||||
"/js/main.5a3111773041d077914c.hot-update.js": "/js/main.5a3111773041d077914c.hot-update.js",
|
||||
"/js/main.6c1dc0ab6b48b7fb8d0f.hot-update.js": "/js/main.6c1dc0ab6b48b7fb8d0f.hot-update.js",
|
||||
"/js/main.acb7922f38d63ffedb8c.hot-update.js": "/js/main.acb7922f38d63ffedb8c.hot-update.js",
|
||||
"/js/main.a53e0c7d11808569d268.hot-update.js": "/js/main.a53e0c7d11808569d268.hot-update.js",
|
||||
"/js/main.a46a827c478e8ab2393e.hot-update.js": "/js/main.a46a827c478e8ab2393e.hot-update.js",
|
||||
"/js/main.701befe377412289c1e7.hot-update.js": "/js/main.701befe377412289c1e7.hot-update.js",
|
||||
"/js/main.4b1e0972a8490afd2480.hot-update.js": "/js/main.4b1e0972a8490afd2480.hot-update.js",
|
||||
"/js/main.a12d0df8441fe0b1b64e.hot-update.js": "/js/main.a12d0df8441fe0b1b64e.hot-update.js",
|
||||
"/js/main.8a13cdc450f54124a2e8.hot-update.js": "/js/main.8a13cdc450f54124a2e8.hot-update.js",
|
||||
"/js/main.86ad86b8ab0ac84651d7.hot-update.js": "/js/main.86ad86b8ab0ac84651d7.hot-update.js",
|
||||
"/js/main.d4311ae5421503ee73ba.hot-update.js": "/js/main.d4311ae5421503ee73ba.hot-update.js",
|
||||
"/js/main.a12f2b869039233ec7d1.hot-update.js": "/js/main.a12f2b869039233ec7d1.hot-update.js",
|
||||
"/js/main.4331e216c81ad63d68d2.hot-update.js": "/js/main.4331e216c81ad63d68d2.hot-update.js",
|
||||
"/js/main.a9f4434e2ef7b9e029f9.hot-update.js": "/js/main.a9f4434e2ef7b9e029f9.hot-update.js",
|
||||
"/js/main.f4cf1d836ab8fad25b18.hot-update.js": "/js/main.f4cf1d836ab8fad25b18.hot-update.js",
|
||||
"/js/main.714ab8accd45fca0352c.hot-update.js": "/js/main.714ab8accd45fca0352c.hot-update.js",
|
||||
"/js/main.f4eb0b9755cffa4dfcc7.hot-update.js": "/js/main.f4eb0b9755cffa4dfcc7.hot-update.js",
|
||||
"/js/main.e970c4c1f36844c2977f.hot-update.js": "/js/main.e970c4c1f36844c2977f.hot-update.js",
|
||||
"/js/main.78570685fbf7d85246f2.hot-update.js": "/js/main.78570685fbf7d85246f2.hot-update.js",
|
||||
"/js/main.fb03325bcaa8d4d98090.hot-update.js": "/js/main.fb03325bcaa8d4d98090.hot-update.js",
|
||||
"/js/main.4d26215591306c839618.hot-update.js": "/js/main.4d26215591306c839618.hot-update.js",
|
||||
"/js/main.2d1f539b131e5873a485.hot-update.js": "/js/main.2d1f539b131e5873a485.hot-update.js",
|
||||
"/js/main.835a770181065c1b9397.hot-update.js": "/js/main.835a770181065c1b9397.hot-update.js",
|
||||
"/js/main.09f9dab42bcfa1634f4d.hot-update.js": "/js/main.09f9dab42bcfa1634f4d.hot-update.js",
|
||||
"/js/main.8a70e542c3e3304535a4.hot-update.js": "/js/main.8a70e542c3e3304535a4.hot-update.js",
|
||||
"/js/main.325adf8cf5e1a83126a5.hot-update.js": "/js/main.325adf8cf5e1a83126a5.hot-update.js",
|
||||
"/js/main.f961b6e9d077a442035a.hot-update.js": "/js/main.f961b6e9d077a442035a.hot-update.js",
|
||||
"/js/main.60d318b86ef1942116fc.hot-update.js": "/js/main.60d318b86ef1942116fc.hot-update.js",
|
||||
"/js/main.fa7aca50202d520eff5c.hot-update.js": "/js/main.fa7aca50202d520eff5c.hot-update.js",
|
||||
"/js/main.c61bd9bd5f3bd0f7bfaf.hot-update.js": "/js/main.c61bd9bd5f3bd0f7bfaf.hot-update.js",
|
||||
"/js/main.ebf01927b1c1132074bb.hot-update.js": "/js/main.ebf01927b1c1132074bb.hot-update.js",
|
||||
"/js/main.73ceb4ddc97dd83e3e9d.hot-update.js": "/js/main.73ceb4ddc97dd83e3e9d.hot-update.js",
|
||||
"/js/main.d59fcd1a37bfee22bf4f.hot-update.js": "/js/main.d59fcd1a37bfee22bf4f.hot-update.js",
|
||||
"/js/main.94b332e4c7a0031ed8ef.hot-update.js": "/js/main.94b332e4c7a0031ed8ef.hot-update.js",
|
||||
"/js/main.578348615f140107a146.hot-update.js": "/js/main.578348615f140107a146.hot-update.js",
|
||||
"/js/main.4d0d19eb2776ac141cf3.hot-update.js": "/js/main.4d0d19eb2776ac141cf3.hot-update.js",
|
||||
"/js/main.c6c7699155e707c83638.hot-update.js": "/js/main.c6c7699155e707c83638.hot-update.js",
|
||||
"/js/main.cc2b80170d644f9fb024.hot-update.js": "/js/main.cc2b80170d644f9fb024.hot-update.js",
|
||||
"/js/main.7d835be6842b8c9b22ac.hot-update.js": "/js/main.7d835be6842b8c9b22ac.hot-update.js",
|
||||
"/js/main.c48c478a7083284384b4.hot-update.js": "/js/main.c48c478a7083284384b4.hot-update.js",
|
||||
"/js/main.0a033e7788ae142bef26.hot-update.js": "/js/main.0a033e7788ae142bef26.hot-update.js",
|
||||
"/js/main.0b7dfc2f94ca7c20da89.hot-update.js": "/js/main.0b7dfc2f94ca7c20da89.hot-update.js",
|
||||
"/js/main.321b6748d866ee25e6a0.hot-update.js": "/js/main.321b6748d866ee25e6a0.hot-update.js",
|
||||
"/js/main.0fc25b4b50854ab03ecb.hot-update.js": "/js/main.0fc25b4b50854ab03ecb.hot-update.js",
|
||||
"/js/main.d4eb7381630781b7f83b.hot-update.js": "/js/main.d4eb7381630781b7f83b.hot-update.js",
|
||||
"/js/main.dbf7b9a6b03dd3e764f5.hot-update.js": "/js/main.dbf7b9a6b03dd3e764f5.hot-update.js",
|
||||
"/js/main.f2d175ee3ad7394744f3.hot-update.js": "/js/main.f2d175ee3ad7394744f3.hot-update.js",
|
||||
"/js/main.7097f18bafbb2c782e34.hot-update.js": "/js/main.7097f18bafbb2c782e34.hot-update.js",
|
||||
"/js/main.e74278efede5c77fb59a.hot-update.js": "/js/main.e74278efede5c77fb59a.hot-update.js",
|
||||
"/js/main.b16252a3f321aa5f638c.hot-update.js": "/js/main.b16252a3f321aa5f638c.hot-update.js",
|
||||
"/js/main.65d67c907472cea149a2.hot-update.js": "/js/main.65d67c907472cea149a2.hot-update.js",
|
||||
"/js/main.d32086da1adce30a365c.hot-update.js": "/js/main.d32086da1adce30a365c.hot-update.js",
|
||||
"/js/main.2abe2dd3690d4223aae6.hot-update.js": "/js/main.2abe2dd3690d4223aae6.hot-update.js",
|
||||
"/js/main.34d101ff4e9c0f3c9f62.hot-update.js": "/js/main.34d101ff4e9c0f3c9f62.hot-update.js",
|
||||
"/js/main.db8a2c676ae81a86ac07.hot-update.js": "/js/main.db8a2c676ae81a86ac07.hot-update.js",
|
||||
"/js/main.3e10515c75b547edbd84.hot-update.js": "/js/main.3e10515c75b547edbd84.hot-update.js",
|
||||
"/js/main.a21b2c4011d251b159dc.hot-update.js": "/js/main.a21b2c4011d251b159dc.hot-update.js",
|
||||
"/js/main.29892a9f1673876f812a.hot-update.js": "/js/main.29892a9f1673876f812a.hot-update.js",
|
||||
"/js/main.90e4e646ca4687f65d71.hot-update.js": "/js/main.90e4e646ca4687f65d71.hot-update.js",
|
||||
"/js/main.2f329e24c50c195b7655.hot-update.js": "/js/main.2f329e24c50c195b7655.hot-update.js",
|
||||
"/js/main.a8a8ecc1aa6706cf3eb7.hot-update.js": "/js/main.a8a8ecc1aa6706cf3eb7.hot-update.js",
|
||||
"/js/main.e03c44a34c09251882cb.hot-update.js": "/js/main.e03c44a34c09251882cb.hot-update.js",
|
||||
"/js/main.1c1d02f7cd7ffae319bd.hot-update.js": "/js/main.1c1d02f7cd7ffae319bd.hot-update.js",
|
||||
"/js/main.a1fed26b6036e6849112.hot-update.js": "/js/main.a1fed26b6036e6849112.hot-update.js",
|
||||
"/js/main.c4018662de1655065788.hot-update.js": "/js/main.c4018662de1655065788.hot-update.js",
|
||||
"/js/main.330cb26c0bc23a53c884.hot-update.js": "/js/main.330cb26c0bc23a53c884.hot-update.js",
|
||||
"/js/main.33a43c4c29198be879c5.hot-update.js": "/js/main.33a43c4c29198be879c5.hot-update.js",
|
||||
"/js/main.60e7443fa7dee86c85d8.hot-update.js": "/js/main.60e7443fa7dee86c85d8.hot-update.js",
|
||||
"/js/main.3e4d2dc845d6e6fd27a1.hot-update.js": "/js/main.3e4d2dc845d6e6fd27a1.hot-update.js",
|
||||
"/js/main.c072ce5e1e8ee60ff114.hot-update.js": "/js/main.c072ce5e1e8ee60ff114.hot-update.js",
|
||||
"/js/main.435a7170ae4c41a507bf.hot-update.js": "/js/main.435a7170ae4c41a507bf.hot-update.js",
|
||||
"/js/main.3e5be2b0dcd70adc5f07.hot-update.js": "/js/main.3e5be2b0dcd70adc5f07.hot-update.js",
|
||||
"/js/main.c1e5ceaa30c4a222234b.hot-update.js": "/js/main.c1e5ceaa30c4a222234b.hot-update.js",
|
||||
"/js/main.430a9eb6b1382f42d8f6.hot-update.js": "/js/main.430a9eb6b1382f42d8f6.hot-update.js",
|
||||
"/js/main.c962104d9cc0e244dbcf.hot-update.js": "/js/main.c962104d9cc0e244dbcf.hot-update.js",
|
||||
"/js/main.631a573d0816d40f99b3.hot-update.js": "/js/main.631a573d0816d40f99b3.hot-update.js",
|
||||
"/js/main.c4966c4a540e5ed0e0fe.hot-update.js": "/js/main.c4966c4a540e5ed0e0fe.hot-update.js",
|
||||
"/js/main.a7e2cb4059892a5ce2d1.hot-update.js": "/js/main.a7e2cb4059892a5ce2d1.hot-update.js",
|
||||
"/js/main.c1a278d80d8245b8dbed.hot-update.js": "/js/main.c1a278d80d8245b8dbed.hot-update.js",
|
||||
"/js/main.6f0d43bf3f52d2c4ac14.hot-update.js": "/js/main.6f0d43bf3f52d2c4ac14.hot-update.js",
|
||||
"/js/main.e784ffe94b54d5a998ab.hot-update.js": "/js/main.e784ffe94b54d5a998ab.hot-update.js",
|
||||
"/js/main.dea1f26cd34f991d67e1.hot-update.js": "/js/main.dea1f26cd34f991d67e1.hot-update.js",
|
||||
"/js/main.061ee62ce1874101ac2a.hot-update.js": "/js/main.061ee62ce1874101ac2a.hot-update.js",
|
||||
"/js/main.85875fb8da3b6c2c9b22.hot-update.js": "/js/main.85875fb8da3b6c2c9b22.hot-update.js",
|
||||
"/js/main.db7c288c6b109145c54f.hot-update.js": "/js/main.db7c288c6b109145c54f.hot-update.js",
|
||||
"/js/main.70d8638e1b3444f4775f.hot-update.js": "/js/main.70d8638e1b3444f4775f.hot-update.js",
|
||||
"/js/main.0d29c7bec145fcf354fb.hot-update.js": "/js/main.0d29c7bec145fcf354fb.hot-update.js",
|
||||
"/js/main.9cd13670523ef48d28e6.hot-update.js": "/js/main.9cd13670523ef48d28e6.hot-update.js",
|
||||
"/js/main.47ee00b321282e6ae987.hot-update.js": "/js/main.47ee00b321282e6ae987.hot-update.js",
|
||||
"/js/main.5ef029b918e611550c36.hot-update.js": "/js/main.5ef029b918e611550c36.hot-update.js",
|
||||
"/js/main.f6719ad9576c258cf584.hot-update.js": "/js/main.f6719ad9576c258cf584.hot-update.js",
|
||||
"/js/main.e7ccbb9786d4116e87e5.hot-update.js": "/js/main.e7ccbb9786d4116e87e5.hot-update.js",
|
||||
"/js/main.9ca0d30ea69682a73a3f.hot-update.js": "/js/main.9ca0d30ea69682a73a3f.hot-update.js",
|
||||
"/js/main.aea23c89a4d4cb490f38.hot-update.js": "/js/main.aea23c89a4d4cb490f38.hot-update.js",
|
||||
"/js/main.2a2df9603b1822c15a5e.hot-update.js": "/js/main.2a2df9603b1822c15a5e.hot-update.js",
|
||||
"/js/main.489f68ca99fda16cb5d1.hot-update.js": "/js/main.489f68ca99fda16cb5d1.hot-update.js",
|
||||
"/js/main.597a3d62f124fa4b1495.hot-update.js": "/js/main.597a3d62f124fa4b1495.hot-update.js",
|
||||
"/js/main.d5392b120f1eb2e4c816.hot-update.js": "/js/main.d5392b120f1eb2e4c816.hot-update.js",
|
||||
"/js/main.a7ae925207be44232c5c.hot-update.js": "/js/main.a7ae925207be44232c5c.hot-update.js",
|
||||
"/js/main.bb42904cd41c18389ec8.hot-update.js": "/js/main.bb42904cd41c18389ec8.hot-update.js",
|
||||
"/js/main.fe643a9998fdca67359e.hot-update.js": "/js/main.fe643a9998fdca67359e.hot-update.js",
|
||||
"/js/main.daf27f047d4b8810e2cf.hot-update.js": "/js/main.daf27f047d4b8810e2cf.hot-update.js",
|
||||
"/js/main.986dd7f8fc929c9c0b4f.hot-update.js": "/js/main.986dd7f8fc929c9c0b4f.hot-update.js",
|
||||
"/js/main.77d2a6871e82cc5d0d09.hot-update.js": "/js/main.77d2a6871e82cc5d0d09.hot-update.js",
|
||||
"/js/main.49faf863ade9028d0d34.hot-update.js": "/js/main.49faf863ade9028d0d34.hot-update.js",
|
||||
"/js/main.0ffae012a756027e52bd.hot-update.js": "/js/main.0ffae012a756027e52bd.hot-update.js",
|
||||
"/js/main.df15a1f233ee639ed364.hot-update.js": "/js/main.df15a1f233ee639ed364.hot-update.js",
|
||||
"/js/main.3d8a3e25947961464dcc.hot-update.js": "/js/main.3d8a3e25947961464dcc.hot-update.js",
|
||||
"/js/main.ef757ee6853c9f37b38c.hot-update.js": "/js/main.ef757ee6853c9f37b38c.hot-update.js",
|
||||
"/js/main.009a2af69a329c5f4ced.hot-update.js": "/js/main.009a2af69a329c5f4ced.hot-update.js",
|
||||
"/js/main.3eba90d0a4c80f1cc076.hot-update.js": "/js/main.3eba90d0a4c80f1cc076.hot-update.js",
|
||||
"/js/main.530a0e768d44eaffc432.hot-update.js": "/js/main.530a0e768d44eaffc432.hot-update.js",
|
||||
"/js/main.2e446e138db18ddc31a6.hot-update.js": "/js/main.2e446e138db18ddc31a6.hot-update.js",
|
||||
"/js/main.d53c4114c93122303427.hot-update.js": "/js/main.d53c4114c93122303427.hot-update.js"
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
'isLogged', 'isGuest'
|
||||
]),
|
||||
layout() {
|
||||
if (includes(['PurchaseCode', 'StripeCredentials', 'AppSetup', 'EnvironmentSetup', 'BillingsDetail', 'SubscriptionPlans', 'Database', 'VerifyByPassword', 'SharedPage', 'NotFoundShared', 'SignIn', 'SignUp', 'ForgottenPassword', 'CreateNewPassword'], this.$route.name)) {
|
||||
if (includes(['AdminAccount', 'PurchaseCode', 'SubscriptionService', 'StripeCredentials', 'AppSetup', 'EnvironmentSetup', 'BillingsDetail', 'SubscriptionPlans', 'Database', 'VerifyByPassword', 'SharedPage', 'NotFoundShared', 'SignIn', 'SignUp', 'ForgottenPassword', 'CreateNewPassword'], this.$route.name)) {
|
||||
return 'unauthorized'
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
/>
|
||||
|
||||
<div class="dropzone-message" v-show="! isData">
|
||||
<upload-icon size="19" class="icon-upload"></upload-icon>
|
||||
<image-icon size="28" class="icon-upload"></image-icon>
|
||||
<span class="dropzone-title">
|
||||
{{ $t('input_image.title') }}
|
||||
</span>
|
||||
@@ -26,7 +26,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { UploadIcon } from 'vue-feather-icons'
|
||||
import ImageIcon from "vue-feather-icons/icons/ImageIcon";
|
||||
|
||||
export default {
|
||||
name: 'ImageInput',
|
||||
@@ -34,7 +34,7 @@
|
||||
'image', 'error'
|
||||
],
|
||||
components: {
|
||||
UploadIcon
|
||||
ImageIcon,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -86,7 +86,7 @@
|
||||
text-align: center;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
min-height: 210px;
|
||||
min-height: 175px;
|
||||
|
||||
&.is-error {
|
||||
border: 2px dashed rgba(253, 57, 122, 0.3);
|
||||
@@ -95,8 +95,10 @@
|
||||
color: $danger;
|
||||
}
|
||||
|
||||
.icon-upload path {
|
||||
fill: $danger
|
||||
.icon-upload {
|
||||
rect, circle, polyline {
|
||||
stroke: $danger
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,6 +135,12 @@
|
||||
padding: 50px 0;
|
||||
width: 100%;
|
||||
|
||||
.icon-upload {
|
||||
rect, circle, polyline {
|
||||
stroke: $theme
|
||||
}
|
||||
}
|
||||
|
||||
.dropzone-title {
|
||||
@include font-size(16);
|
||||
font-weight: 700;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="info-box">
|
||||
<div class="info-box" :class="type">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</template>
|
||||
@@ -7,6 +7,7 @@
|
||||
<script>
|
||||
export default {
|
||||
name: 'InfoBox',
|
||||
props: ['type']
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -21,9 +22,18 @@
|
||||
background: $light_background;
|
||||
text-align: left;
|
||||
|
||||
&.error {
|
||||
background: rgba($danger, 0.1);
|
||||
|
||||
p, a {
|
||||
color: $danger;
|
||||
}
|
||||
}
|
||||
|
||||
p {
|
||||
@include font-size(15);
|
||||
line-height: 1.6;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
a {
|
||||
|
||||
22
resources/js/router.js
vendored
22
resources/js/router.js
vendored
@@ -59,10 +59,12 @@ import SetupWizard from './views/SetupWizard'
|
||||
import Database from './views/SetupWizard/Database'
|
||||
import AppSetup from './views/SetupWizard/AppSetup'
|
||||
import PurchaseCode from './views/SetupWizard/PurchaseCode'
|
||||
import AdminAccount from './views/SetupWizard/AdminAccount'
|
||||
import BillingsDetail from './views/SetupWizard/BillingsDetail'
|
||||
import EnvironmentSetup from './views/SetupWizard/EnvironmentSetup'
|
||||
import StripeCredentials from './views/SetupWizard/StripeCredentials'
|
||||
import SubscriptionPlans from './views/SetupWizard/SubscriptionPlans'
|
||||
import SubscriptionService from './views/SetupWizard/SubscriptionService'
|
||||
|
||||
Vue.use(Router)
|
||||
|
||||
@@ -465,6 +467,14 @@ const routesMaintenance = [
|
||||
requiresAuth: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'SubscriptionService',
|
||||
path: '/setup-wizard/subscription-service',
|
||||
component: SubscriptionService,
|
||||
meta: {
|
||||
requiresAuth: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'StripeCredentials',
|
||||
path: '/setup-wizard/stripe-credentials',
|
||||
@@ -475,7 +485,7 @@ const routesMaintenance = [
|
||||
},
|
||||
{
|
||||
name: 'BillingsDetail',
|
||||
path: '/setup-wizard/billings',
|
||||
path: '/setup-wizard/stripe-billings',
|
||||
component: BillingsDetail,
|
||||
meta: {
|
||||
requiresAuth: false,
|
||||
@@ -483,7 +493,7 @@ const routesMaintenance = [
|
||||
},
|
||||
{
|
||||
name: 'SubscriptionPlans',
|
||||
path: '/setup-wizard/subscription-plans',
|
||||
path: '/setup-wizard/stripe-plans',
|
||||
component: SubscriptionPlans,
|
||||
meta: {
|
||||
requiresAuth: false,
|
||||
@@ -505,6 +515,14 @@ const routesMaintenance = [
|
||||
requiresAuth: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'AdminAccount',
|
||||
path: '/setup-wizard/admin-setup',
|
||||
component: AdminAccount,
|
||||
meta: {
|
||||
requiresAuth: false,
|
||||
},
|
||||
},
|
||||
]
|
||||
},
|
||||
]
|
||||
|
||||
202
resources/js/views/SetupWIzard/AdminAccount.vue
Normal file
202
resources/js/views/SetupWIzard/AdminAccount.vue
Normal file
@@ -0,0 +1,202 @@
|
||||
<template>
|
||||
<AuthContentWrapper ref="auth">
|
||||
|
||||
<!--Database Credentials-->
|
||||
<AuthContent name="database-credentials" :visible="true">
|
||||
<div class="content-headline">
|
||||
<settings-icon size="40" class="title-icon"></settings-icon>
|
||||
<h1>Setup Wizard</h1>
|
||||
<h2>Create your admin account.</h2>
|
||||
</div>
|
||||
|
||||
<ValidationObserver @submit.prevent="adminAccountSubmit" ref="adminAccount" v-slot="{ invalid }" tag="form" class="form block-form">
|
||||
<FormLabel>Create Admin Account</FormLabel>
|
||||
|
||||
<div class="block-wrapper">
|
||||
<label>Avatar (optional):</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Avatar" v-slot="{ errors }">
|
||||
<ImageInput v-model="admin.avatar" :error="errors[0]" />
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
|
||||
<div class="block-wrapper">
|
||||
<label>Full Name:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Full Name" rules="required" v-slot="{ errors }">
|
||||
<input v-model="admin.name" placeholder="Type your full name" type="text" :class="{'is-error': errors[0]}" />
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
|
||||
<div class="block-wrapper">
|
||||
<label>Email:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Email" rules="required" v-slot="{ errors }">
|
||||
<input v-model="admin.email" placeholder="Type your email" type="email" :class="{'is-error': errors[0]}" />
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
|
||||
<div class="block-wrapper">
|
||||
<label>Password:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Password" rules="required" v-slot="{ errors }">
|
||||
<input v-model="admin.password" placeholder="Type your password" type="password" :class="{'is-error': errors[0]}" />
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
|
||||
<div class="block-wrapper">
|
||||
<label>Password Confirmation:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Password confirmation" rules="required" v-slot="{ errors }">
|
||||
<input v-model="admin.password_confirmation" placeholder="Confirm your password" type="password" :class="{'is-error': errors[0]}" />
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
|
||||
<div class="submit-wrapper">
|
||||
<AuthButton icon="chevron-right" text="Create Admin and Login" :loading="isLoading" :disabled="isLoading"/>
|
||||
</div>
|
||||
|
||||
</ValidationObserver>
|
||||
</AuthContent>
|
||||
</AuthContentWrapper>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {ValidationProvider, ValidationObserver} from 'vee-validate/dist/vee-validate.full'
|
||||
import AuthContentWrapper from '@/components/Auth/AuthContentWrapper'
|
||||
import SelectInput from '@/components/Others/Forms/SelectInput'
|
||||
import SwitchInput from '@/components/Others/Forms/SwitchInput'
|
||||
import ImageInput from '@/components/Others/Forms/ImageInput'
|
||||
import FormLabel from '@/components/Others/Forms/FormLabel'
|
||||
import InfoBox from '@/components/Others/Forms/InfoBox'
|
||||
import AuthContent from '@/components/Auth/AuthContent'
|
||||
import AuthButton from '@/components/Auth/AuthButton'
|
||||
import { SettingsIcon } from 'vue-feather-icons'
|
||||
import {required} from 'vee-validate/dist/rules'
|
||||
import {events} from "@/bus"
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
name: 'EnvironmentSetup',
|
||||
components: {
|
||||
AuthContentWrapper,
|
||||
ValidationProvider,
|
||||
ValidationObserver,
|
||||
SettingsIcon,
|
||||
SelectInput,
|
||||
SwitchInput,
|
||||
AuthContent,
|
||||
ImageInput,
|
||||
AuthButton,
|
||||
FormLabel,
|
||||
required,
|
||||
InfoBox,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: false,
|
||||
admin: {
|
||||
name: '',
|
||||
email: '',
|
||||
avatar: undefined,
|
||||
password: '',
|
||||
password_confirmation: '',
|
||||
},
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async adminAccountSubmit() {
|
||||
|
||||
// Validate fields
|
||||
const isValid = await this.$refs.adminAccount.validate();
|
||||
|
||||
if (!isValid) return;
|
||||
|
||||
// Start loading
|
||||
this.isLoading = true
|
||||
|
||||
// Create form
|
||||
let formData = new FormData()
|
||||
|
||||
// Add image to form
|
||||
formData.append('name', this.admin.name)
|
||||
formData.append('email', this.admin.email)
|
||||
formData.append('password', this.admin.password)
|
||||
formData.append('password_confirmation', this.admin.password_confirmation)
|
||||
|
||||
if (this.admin.avatar)
|
||||
formData.append('avatar', this.admin.avatar)
|
||||
|
||||
axios
|
||||
.post('/api/setup/admin-setup', formData, {
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
}
|
||||
})
|
||||
.then(response => {
|
||||
|
||||
// End loading
|
||||
this.isLoading = false
|
||||
|
||||
// Set login state
|
||||
this.$store.commit('SET_AUTHORIZED', true)
|
||||
|
||||
// Go to files page
|
||||
this.$router.push({name: 'Files'})
|
||||
})
|
||||
.catch(error => {
|
||||
|
||||
|
||||
if (error.response.status == 401) {
|
||||
|
||||
if (error.response.data.error === 'invalid_client') {
|
||||
events.$emit('alert:open', {
|
||||
emoji: '🤔',
|
||||
title: this.$t('popup_passport_error.title'),
|
||||
message: this.$t('popup_passport_error.message')
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if (error.response.status == 500) {
|
||||
|
||||
events.$emit('alert:open', {
|
||||
emoji: '🤔',
|
||||
title: this.$t('popup_signup_error.title'),
|
||||
message: this.$t('popup_signup_error.message')
|
||||
})
|
||||
}
|
||||
|
||||
if (error.response.status == 422) {
|
||||
|
||||
if (error.response.data.errors['email']) {
|
||||
|
||||
this.$refs.adminAccount.setErrors({
|
||||
'Email': error.response.data.errors['email']
|
||||
});
|
||||
}
|
||||
|
||||
if (error.response.data.errors['password']) {
|
||||
|
||||
this.$refs.adminAccount.setErrors({
|
||||
'Password': error.response.data.errors['password']
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// End loading
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
},
|
||||
created() {
|
||||
var container = document.getElementById('vue-file-manager')
|
||||
container.scrollTop = 0
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '@assets/vue-file-manager/_forms';
|
||||
@import '@assets/vue-file-manager/_auth';
|
||||
@import '@assets/vue-file-manager/_setup_wizard';
|
||||
</style>
|
||||
@@ -9,20 +9,97 @@
|
||||
<h2>Set up your application appearance, analytics, etc.</h2>
|
||||
</div>
|
||||
|
||||
<ValidationObserver @submit.prevent="appSetupSubmit" ref="appSetup" v-slot="{ invalid }" tag="form" class="form block-form">
|
||||
<ValidationObserver @submit.prevent="appSetupSubmit" ref="appSetup" v-slot="{ invalid }" tag="form"
|
||||
class="form block-form">
|
||||
<FormLabel>General Settings</FormLabel>
|
||||
|
||||
<div class="block-wrapper">
|
||||
<label>Mail Driver:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Mail Driver" rules="required" v-slot="{ errors }">
|
||||
<input v-model="mail.driver" placeholder="Type your mail driver" type="text" />
|
||||
<label>App Title:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="App Title" rules="required" v-slot="{ errors }">
|
||||
<input v-model="app.title" placeholder="Type your app title" type="text" :class="{'is-error': errors[0]}"/>
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
|
||||
<div class="block-wrapper">
|
||||
<label>App Description:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="App Description" rules="required" v-slot="{ errors }">
|
||||
<input v-model="app.description" placeholder="Type your app description" type="text" :class="{'is-error': errors[0]}"/>
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
|
||||
<div class="block-wrapper">
|
||||
<label>App Logo (optional):</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="App Logo" v-slot="{ errors }">
|
||||
<ImageInput v-model="app.logo" :error="errors[0]"/>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
|
||||
<div class="block-wrapper">
|
||||
<label>App Favicon (optional):</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="App Favicon" v-slot="{ errors }">
|
||||
<ImageInput v-model="app.favicon" :error="errors[0]"/>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
|
||||
<FormLabel class="mt-70">Others Information</FormLabel>
|
||||
|
||||
<div class="block-wrapper">
|
||||
<label>Contact Email:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Contact Email"
|
||||
rules="required" v-slot="{ errors }">
|
||||
<input v-model="app.contactMail" placeholder="Type your contact email" type="email" :class="{'is-error': errors[0]}"/>
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
|
||||
<div class="block-wrapper">
|
||||
<label>Google Analytics Code (optional):</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Google Analytics Code"
|
||||
v-slot="{ errors }">
|
||||
<input v-model="app.googleAnalytics" placeholder="Paste your Google Analytics Code"
|
||||
type="text" :class="{'is-error': errors[0]}"/>
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
|
||||
<div class="block-wrapper">
|
||||
<div class="input-wrapper">
|
||||
<div class="inline-wrapper">
|
||||
<div class="switch-label">
|
||||
<label class="input-label">Storage Limitation:</label>
|
||||
</div>
|
||||
<SwitchInput v-model="app.storageLimitation" class="switch" :state="app.storageLimitation"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="block-wrapper" v-if="app.storageLimitation">
|
||||
<label>Default Storage Space for Accounts:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Default Storage Space" rules="required" v-slot="{ errors }">
|
||||
<input v-model="app.defaultStorage"
|
||||
min="1"
|
||||
max="999999999"
|
||||
placeholder="Set default storage space in GB"
|
||||
type="number"
|
||||
:class="{'is-error': errors[0]}"
|
||||
/>
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
|
||||
<div class="block-wrapper">
|
||||
<div class="input-wrapper">
|
||||
<div class="inline-wrapper">
|
||||
<div class="switch-label">
|
||||
<label class="input-label">Allow User Registration:</label>
|
||||
</div>
|
||||
<SwitchInput v-model="app.userRegistration" class="switch" :state="app.userRegistration"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="submit-wrapper">
|
||||
<AuthButton icon="chevron-right" text="Save and Create Admin" :loading="isLoading" :disabled="isLoading"/>
|
||||
</div>
|
||||
@@ -36,6 +113,8 @@
|
||||
import {ValidationProvider, ValidationObserver} from 'vee-validate/dist/vee-validate.full'
|
||||
import AuthContentWrapper from '@/components/Auth/AuthContentWrapper'
|
||||
import SelectInput from '@/components/Others/Forms/SelectInput'
|
||||
import SwitchInput from '@/components/Others/Forms/SwitchInput'
|
||||
import ImageInput from '@/components/Others/Forms/ImageInput'
|
||||
import FormLabel from '@/components/Others/Forms/FormLabel'
|
||||
import InfoBox from '@/components/Others/Forms/InfoBox'
|
||||
import AuthContent from '@/components/Auth/AuthContent'
|
||||
@@ -53,7 +132,9 @@
|
||||
ValidationObserver,
|
||||
SettingsIcon,
|
||||
SelectInput,
|
||||
SwitchInput,
|
||||
AuthContent,
|
||||
ImageInput,
|
||||
AuthButton,
|
||||
FormLabel,
|
||||
required,
|
||||
@@ -62,51 +143,68 @@
|
||||
data() {
|
||||
return {
|
||||
isLoading: false,
|
||||
storageServiceList: [
|
||||
{
|
||||
label: 'Local Driver',
|
||||
value: 'local',
|
||||
app: {
|
||||
title: '',
|
||||
description: '',
|
||||
logo: undefined,
|
||||
favicon: undefined,
|
||||
contactMail: '',
|
||||
googleAnalytics: '',
|
||||
defaultStorage: '',
|
||||
userRegistration: 1,
|
||||
storageLimitation: 1,
|
||||
},
|
||||
{
|
||||
label: 'Amazon Web Services S3',
|
||||
value: 's3',
|
||||
},
|
||||
{
|
||||
label: 'Digital Ocean Spaces',
|
||||
value: 'spaces',
|
||||
},
|
||||
],
|
||||
encryptionList: [
|
||||
{
|
||||
label: 'TLS',
|
||||
value: 'tls',
|
||||
},
|
||||
{
|
||||
label: 'SSL',
|
||||
value: 'ssl',
|
||||
},
|
||||
],
|
||||
storage: {
|
||||
driver: 'local',
|
||||
key: '',
|
||||
secret: '',
|
||||
endpoint: '',
|
||||
region: '',
|
||||
bucket: '',
|
||||
},
|
||||
mail: {
|
||||
driver: '',
|
||||
host: '',
|
||||
port: '',
|
||||
username: '',
|
||||
password: '',
|
||||
encryption: '',
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async appSetupSubmit() {
|
||||
this.$router.push({name: 'AppSetup'})
|
||||
|
||||
// Validate fields
|
||||
const isValid = await this.$refs.appSetup.validate();
|
||||
|
||||
if (!isValid) return;
|
||||
|
||||
// Start loading
|
||||
this.isLoading = true
|
||||
|
||||
// Create form
|
||||
let formData = new FormData()
|
||||
|
||||
// Add image to form
|
||||
formData.append('title', this.app.title)
|
||||
formData.append('description', this.app.description)
|
||||
formData.append('contactMail', this.app.contactMail)
|
||||
formData.append('googleAnalytics', this.app.googleAnalytics)
|
||||
formData.append('defaultStorage', this.app.defaultStorage)
|
||||
formData.append('userRegistration', this.app.userRegistration)
|
||||
formData.append('storageLimitation', this.app.storageLimitation)
|
||||
|
||||
if (this.app.logo)
|
||||
formData.append('logo', this.app.logo)
|
||||
|
||||
if (this.app.favicon)
|
||||
formData.append('favicon', this.app.favicon)
|
||||
|
||||
// Send request to get verify account
|
||||
axios
|
||||
.post('/api/setup/app-setup', formData, {
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
}
|
||||
})
|
||||
.then(response => {
|
||||
|
||||
// End loading
|
||||
this.isLoading = false
|
||||
|
||||
// Redirect to next step
|
||||
this.$router.push({name: 'AdminAccount'})
|
||||
})
|
||||
.catch(error => {
|
||||
|
||||
// End loading
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
},
|
||||
created() {
|
||||
@@ -117,7 +215,6 @@
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
//@import '@assets/vue-file-manager/_auth-form';
|
||||
@import '@assets/vue-file-manager/_forms';
|
||||
@import '@assets/vue-file-manager/_auth';
|
||||
@import '@assets/vue-file-manager/_setup_wizard';
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<div class="content-headline">
|
||||
<settings-icon size="40" class="title-icon"></settings-icon>
|
||||
<h1>Setup Wizard</h1>
|
||||
<h2>Set up you billing information.</h2>
|
||||
<h2>Set up your billing information.</h2>
|
||||
</div>
|
||||
|
||||
<ValidationObserver @submit.prevent="billingInformationSubmit" ref="billingInformation" v-slot="{ invalid }"
|
||||
@@ -18,7 +18,7 @@
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Billing Name"
|
||||
rules="required" v-slot="{ errors }">
|
||||
<input v-model="billingInformation.billing_name" placeholder="Type your company name"
|
||||
type="text"/>
|
||||
type="text" :class="{'is-error': errors[0]}"/>
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
@@ -28,7 +28,7 @@
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Billing Vat Number"
|
||||
rules="required" v-slot="{ errors }">
|
||||
<input v-model="billingInformation.billing_vat_number" placeholder="Type your VAT number"
|
||||
type="text"/>
|
||||
type="text" :class="{'is-error': errors[0]}"/>
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
@@ -48,8 +48,8 @@
|
||||
<label>Billing Address:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Billing Address"
|
||||
rules="required" v-slot="{ errors }">
|
||||
<input v-model="billingInformation.billing_address" placeholder="Select your billing address"
|
||||
type="text"/>
|
||||
<input v-model="billingInformation.billing_address" placeholder="Type your billing address"
|
||||
type="text" :class="{'is-error': errors[0]}"/>
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
@@ -59,8 +59,8 @@
|
||||
<label>Billing City:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Billing City"
|
||||
rules="required" v-slot="{ errors }">
|
||||
<input v-model="billingInformation.billing_city" placeholder="Select your billing city"
|
||||
type="text"/>
|
||||
<input v-model="billingInformation.billing_city" placeholder="Type your billing city"
|
||||
type="text" :class="{'is-error': errors[0]}"/>
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
@@ -69,7 +69,7 @@
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Billing Postal Code"
|
||||
rules="required" v-slot="{ errors }">
|
||||
<input v-model="billingInformation.billing_postal_code"
|
||||
placeholder="Select your billing postal code" type="text"/>
|
||||
placeholder="Type your billing postal code" type="text" :class="{'is-error': errors[0]}"/>
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
@@ -79,8 +79,18 @@
|
||||
<label>Billing State:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Billing State"
|
||||
rules="required" v-slot="{ errors }">
|
||||
<input v-model="billingInformation.billing_state" placeholder="Select your billing state"
|
||||
type="text"/>
|
||||
<input v-model="billingInformation.billing_state" placeholder="Type your billing state"
|
||||
type="text" :class="{'is-error': errors[0]}"/>
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
|
||||
<div class="block-wrapper">
|
||||
<label>Billing Phone Number (optional):</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Billing Phone Number"
|
||||
v-slot="{ errors }">
|
||||
<input v-model="billingInformation.billing_phone_number" placeholder="Type your billing phone number"
|
||||
type="text" :class="{'is-error': errors[0]}"/>
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
@@ -384,7 +394,31 @@
|
||||
},
|
||||
methods: {
|
||||
async billingInformationSubmit() {
|
||||
|
||||
// Validate fields
|
||||
const isValid = await this.$refs.billingInformation.validate();
|
||||
|
||||
if (!isValid) return;
|
||||
|
||||
// Start loading
|
||||
this.isLoading = true
|
||||
|
||||
// Send request to get verify account
|
||||
axios
|
||||
.post('/api/setup/stripe-billings', this.billingInformation)
|
||||
.then(response => {
|
||||
|
||||
// End loading
|
||||
this.isLoading = false
|
||||
|
||||
// Redirect to next step
|
||||
this.$router.push({name: 'SubscriptionPlans'})
|
||||
})
|
||||
.catch(error => {
|
||||
|
||||
// End loading
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
},
|
||||
created() {
|
||||
|
||||
@@ -6,24 +6,24 @@
|
||||
<div class="content-headline">
|
||||
<settings-icon size="40" class="title-icon"></settings-icon>
|
||||
<h1>Setup Wizard</h1>
|
||||
<h2>Set up your database credentials.</h2>
|
||||
<h2>Set up your database connection to install application database.</h2>
|
||||
</div>
|
||||
|
||||
<ValidationObserver @submit.prevent="databaseCredentialsSubmit" ref="verifyPurchaseCode" v-slot="{ invalid }" tag="form" class="form block-form">
|
||||
<FormLabel>Database Credentials</FormLabel>
|
||||
<InfoBox>
|
||||
<p>Firstly, create your database credentials in your database client. For how to, here is Usefull resources:</p>
|
||||
<p>We strongly recommend use MySQL or MariaDB database. Create new database and get credentials in your locale database client. For those who use cPanel or Plesk, here is useful resources:</p>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="#" target="_blank">1. cPanel - MySQL Database Wizard</a>
|
||||
<a href="#" target="_blank">2. Plesk - Website databases</a>
|
||||
<a href="https://www.inmotionhosting.com/support/edu/cpanel/create-database-2/" target="_blank">1. cPanel - MySQL Database Wizard</a>
|
||||
<a href="https://docs.plesk.com/en-US/obsidian/customer-guide/65157/" target="_blank">2. Plesk - Website databases</a>
|
||||
</li>
|
||||
</ul>
|
||||
</InfoBox>
|
||||
|
||||
<div class="block-wrapper">
|
||||
<label>Connection:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="connection" rules="required" v-slot="{ errors }">
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Connection" rules="required" v-slot="{ errors }">
|
||||
<SelectInput v-model="databaseCredentials.connection" :options="connectionList" default="mysql" placeholder="Select your database connection" :isError="errors[0]"/>
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
@@ -31,38 +31,52 @@
|
||||
|
||||
<div class="block-wrapper">
|
||||
<label>Host:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="connection" rules="required" v-slot="{ errors }">
|
||||
<input v-model="databaseCredentials.host" placeholder="Type your database host" type="text" />
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Host" rules="required" v-slot="{ errors }">
|
||||
<input v-model="databaseCredentials.host" placeholder="Type your database host" type="text" :class="{'is-error': errors[0]}" />
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
|
||||
<div class="block-wrapper">
|
||||
<label>Port:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="connection" rules="required" v-slot="{ errors }">
|
||||
<input v-model="databaseCredentials.port" placeholder="Type your database port" type="text" />
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Port" rules="required" v-slot="{ errors }">
|
||||
<input v-model="databaseCredentials.port" placeholder="Type your database port" type="text" :class="{'is-error': errors[0]}" />
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
|
||||
<div class="block-wrapper">
|
||||
<label>Database Name:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="connection" rules="required" v-slot="{ errors }">
|
||||
<input v-model="databaseCredentials.name" placeholder="Select your database name" type="text" />
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Database Name" rules="required" v-slot="{ errors }">
|
||||
<input v-model="databaseCredentials.name" placeholder="Select your database name" type="text" :class="{'is-error': errors[0]}" />
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
|
||||
<div class="block-wrapper">
|
||||
<label>Database Username:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Database Username" rules="required" v-slot="{ errors }">
|
||||
<input v-model="databaseCredentials.username" placeholder="Select your database name" type="text" :class="{'is-error': errors[0]}" />
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
|
||||
<div class="block-wrapper">
|
||||
<label>Database Password:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="connection" rules="required" v-slot="{ errors }">
|
||||
<input v-model="databaseCredentials.password" placeholder="Select your database password" type="text" />
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Database Password" rules="required" v-slot="{ errors }">
|
||||
<input v-model="databaseCredentials.password" placeholder="Select your database password" type="text" :class="{'is-error': errors[0]}" />
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
|
||||
<InfoBox v-if="isError" type="error" style="margin-bottom: 10px">
|
||||
<p>We couldn't establish database connection. Please double check your database credentials.</p>
|
||||
<br>
|
||||
<p>Detailed error: {{ errorMessage }}</p>
|
||||
</InfoBox>
|
||||
|
||||
<div class="submit-wrapper">
|
||||
<AuthButton icon="chevron-right" text="Test your Connection and Continue" :loading="isLoading" :disabled="isLoading"/>
|
||||
<AuthButton icon="chevron-right" :text="submitButtonText" :loading="isLoading" :disabled="isLoading"/>
|
||||
</div>
|
||||
|
||||
</ValidationObserver>
|
||||
@@ -97,15 +111,22 @@
|
||||
required,
|
||||
InfoBox,
|
||||
},
|
||||
computed: {
|
||||
submitButtonText() {
|
||||
return this.isLoading ? 'Testing Database Connection' : 'Test your Connection and Continue'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: false,
|
||||
isError: false,
|
||||
errorMessage: '',
|
||||
connectionList: [
|
||||
{
|
||||
label: 'MySQL',
|
||||
value: 'mysql',
|
||||
},
|
||||
{
|
||||
/*{
|
||||
label: 'SQLite',
|
||||
value: 'sqlite',
|
||||
},
|
||||
@@ -116,20 +137,51 @@
|
||||
{
|
||||
label: 'SQLSry',
|
||||
value: 'sqlsrv',
|
||||
},
|
||||
},*/
|
||||
],
|
||||
databaseCredentials: {
|
||||
connection: '',
|
||||
host: '',
|
||||
port: '',
|
||||
name: '',
|
||||
password: '',
|
||||
connection: 'mysql',
|
||||
host: '127.0.0.1',
|
||||
port: '8889',
|
||||
name: 'file-manager',
|
||||
username: 'root',
|
||||
password: 'root',
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async databaseCredentialsSubmit() {
|
||||
this.$router.push({name: 'StripeCredentials'})
|
||||
|
||||
// Validate fields
|
||||
const isValid = await this.$refs.verifyPurchaseCode.validate();
|
||||
|
||||
if (!isValid) return;
|
||||
|
||||
// Start loading
|
||||
this.isLoading = true
|
||||
this.isError = false
|
||||
|
||||
// Send request to get verify account
|
||||
axios
|
||||
.post('/api/setup/database', this.databaseCredentials)
|
||||
.then(response => {
|
||||
|
||||
// End loading
|
||||
this.isLoading = false
|
||||
|
||||
// Redirect to next step
|
||||
this.$router.push({name: 'SubscriptionService'})
|
||||
})
|
||||
.catch(error => {
|
||||
|
||||
if (error.response.status = 500) {
|
||||
this.isError = true
|
||||
this.errorMessage = error.response.data.message
|
||||
}
|
||||
|
||||
// End loading
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
},
|
||||
created() {
|
||||
|
||||
@@ -9,9 +9,9 @@
|
||||
<h2>Set up your storage driver and email client.</h2>
|
||||
</div>
|
||||
|
||||
<ValidationObserver @submit.prevent="EnvironmentSetupSubmit" ref="stripeCredentials" v-slot="{ invalid }" tag="form" class="form block-form">
|
||||
<ValidationObserver @submit.prevent="EnvironmentSetupSubmit" ref="environmentSetup" v-slot="{ invalid }" tag="form" class="form block-form">
|
||||
<InfoBox>
|
||||
<p>If you don’t know which storage set, select <b>'Local Driver'</b>. For more info, where
|
||||
<p>If you don’t know which storage driver set, keep selected <b>'Local Driver'</b>. For more info, where
|
||||
you can host your files <a href="https://vuefilemanager.com/docs/guide/storage.html#introduction" target="_blank">visit our guide</a>.</p>
|
||||
</InfoBox>
|
||||
|
||||
@@ -29,35 +29,35 @@
|
||||
<div class="block-wrapper">
|
||||
<label>Key:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Key" rules="required" v-slot="{ errors }">
|
||||
<input v-model="storage.key" placeholder="Paste your key" type="text" />
|
||||
<input v-model="storage.key" placeholder="Paste your key" type="text" :class="{'is-error': errors[0]}" />
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
<div class="block-wrapper">
|
||||
<label>Secret:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Secret" rules="required" v-slot="{ errors }">
|
||||
<input v-model="storage.secret" placeholder="Paste your secret" type="text" />
|
||||
<input v-model="storage.secret" placeholder="Paste your secret" type="text" :class="{'is-error': errors[0]}" />
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
<div class="block-wrapper">
|
||||
<div class="block-wrapper" v-if="storage.driver !== 's3'">
|
||||
<label>Endpoint:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Endpoint" rules="required" v-slot="{ errors }">
|
||||
<input v-model="storage.endpoint" placeholder="Type your endpoint" type="text" />
|
||||
<input v-model="storage.endpoint" placeholder="Type your endpoint" type="text" :class="{'is-error': errors[0]}" />
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
<div class="block-wrapper">
|
||||
<label>Region:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Region" rules="required" v-slot="{ errors }">
|
||||
<input v-model="storage.region" placeholder="Type your region" type="text" />
|
||||
<input v-model="storage.region" placeholder="Type your region" type="text" :class="{'is-error': errors[0]}" />
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
<div class="block-wrapper">
|
||||
<label>Bucket:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Bucket" rules="required" v-slot="{ errors }">
|
||||
<input v-model="storage.bucket" placeholder="Type your bucket name" type="text" />
|
||||
<input v-model="storage.bucket" placeholder="Type your bucket name" type="text" :class="{'is-error': errors[0]}" />
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
@@ -72,7 +72,7 @@
|
||||
<div class="block-wrapper">
|
||||
<label>Mail Driver:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Mail Driver" rules="required" v-slot="{ errors }">
|
||||
<input v-model="mail.driver" placeholder="Type your mail driver" type="text" />
|
||||
<input v-model="mail.driver" placeholder="Type your mail driver" type="text" :class="{'is-error': errors[0]}" />
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
@@ -80,7 +80,7 @@
|
||||
<div class="block-wrapper">
|
||||
<label>Mail Host:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Mail Host" rules="required" v-slot="{ errors }">
|
||||
<input v-model="mail.host" placeholder="Type your mail host" type="text" />
|
||||
<input v-model="mail.host" placeholder="Type your mail host" type="text" :class="{'is-error': errors[0]}" />
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
@@ -88,7 +88,7 @@
|
||||
<div class="block-wrapper">
|
||||
<label>Mail Port:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Mail Port" rules="required" v-slot="{ errors }">
|
||||
<input v-model="mail.port" placeholder="Type your mail port" type="text" />
|
||||
<input v-model="mail.port" placeholder="Type your mail port" type="text" :class="{'is-error': errors[0]}" />
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
@@ -96,7 +96,7 @@
|
||||
<div class="block-wrapper">
|
||||
<label>Mail Username:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Mail Username" rules="required" v-slot="{ errors }">
|
||||
<input v-model="mail.username" placeholder="Type your mail username" type="text" />
|
||||
<input v-model="mail.username" placeholder="Type your mail username" type="text" :class="{'is-error': errors[0]}" />
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
@@ -104,7 +104,7 @@
|
||||
<div class="block-wrapper">
|
||||
<label>Mail Password:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Mail Password" rules="required" v-slot="{ errors }">
|
||||
<input v-model="mail.password" placeholder="Type your mail password" type="text" />
|
||||
<input v-model="mail.password" placeholder="Type your mail password" type="text" :class="{'is-error': errors[0]}" />
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
@@ -118,7 +118,7 @@
|
||||
</div>
|
||||
|
||||
<div class="submit-wrapper">
|
||||
<AuthButton icon="chevron-right" text="Save and Set Billings" :loading="isLoading" :disabled="isLoading"/>
|
||||
<AuthButton icon="chevron-right" text="Save and Set General Settings" :loading="isLoading" :disabled="isLoading"/>
|
||||
</div>
|
||||
|
||||
</ValidationObserver>
|
||||
@@ -169,6 +169,14 @@
|
||||
label: 'Digital Ocean Spaces',
|
||||
value: 'spaces',
|
||||
},
|
||||
{
|
||||
label: 'Object Cloud Storage by Wasabi',
|
||||
value: 'wasabi',
|
||||
},
|
||||
{
|
||||
label: 'Backblaze B2 Cloud Storage',
|
||||
value: 'backblaze',
|
||||
},
|
||||
],
|
||||
encryptionList: [
|
||||
{
|
||||
@@ -200,7 +208,34 @@
|
||||
},
|
||||
methods: {
|
||||
async EnvironmentSetupSubmit() {
|
||||
|
||||
// Validate fields
|
||||
const isValid = await this.$refs.environmentSetup.validate();
|
||||
|
||||
if (!isValid) return;
|
||||
|
||||
// Start loading
|
||||
this.isLoading = true
|
||||
|
||||
// Send request to get verify account
|
||||
axios
|
||||
.post('/api/setup/environment-setup', {
|
||||
storage: this.storage,
|
||||
mail: this.mail,
|
||||
})
|
||||
.then(response => {
|
||||
|
||||
// End loading
|
||||
this.isLoading = false
|
||||
|
||||
// Redirect to next step
|
||||
this.$router.push({name: 'AppSetup'})
|
||||
})
|
||||
.catch(error => {
|
||||
|
||||
// End loading
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
},
|
||||
created() {
|
||||
|
||||
@@ -7,12 +7,12 @@
|
||||
<div class="content-headline">
|
||||
<settings-icon size="40" class="title-icon"></settings-icon>
|
||||
<h1>Setup Wizard</h1>
|
||||
<h2>Please set up your application before continue.</h2>
|
||||
<h2>Please verify your purchase code before continue to set up your application.</h2>
|
||||
</div>
|
||||
|
||||
<ValidationObserver @submit.prevent="verifyPurchaseCode" ref="verifyPurchaseCode" v-slot="{ invalid }" tag="form" class="form inline-form">
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Purchase Code" rules="required" v-slot="{ errors }">
|
||||
<input v-model="licence.purchaseCode" placeholder="Paste your purchase code" type="text" :class="{'is-error': errors[0]}"/>
|
||||
<input v-model="purchaseCode" placeholder="Paste your purchase code" type="text" :class="{'is-error': errors[0]}"/>
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
<AuthButton icon="chevron-right" text="Verify" :loading="isLoading" :disabled="isLoading"/>
|
||||
@@ -22,7 +22,9 @@
|
||||
<a href="https://help.market.envato.com/hc/en-us/articles/202822600-Where-Is-My-Purchase-Code-" target="_blank">
|
||||
Where I can find purchase code?
|
||||
</a>
|
||||
<a class="black-link" href="https://codecanyon.net/item/vue-file-manager-with-laravel-backend/25815986" target="_blank">
|
||||
Don’t have purchase code?
|
||||
</a>
|
||||
</p>
|
||||
</AuthContent>
|
||||
</AuthContentWrapper>
|
||||
@@ -31,6 +33,7 @@
|
||||
<script>
|
||||
import AuthContentWrapper from '@/components/Auth/AuthContentWrapper'
|
||||
import {ValidationProvider, ValidationObserver} from 'vee-validate/dist/vee-validate.full'
|
||||
import InfoBox from '@/components/Others/Forms/InfoBox'
|
||||
import AuthContent from '@/components/Auth/AuthContent'
|
||||
import AuthButton from '@/components/Auth/AuthButton'
|
||||
import { SettingsIcon } from 'vue-feather-icons'
|
||||
@@ -48,22 +51,17 @@
|
||||
AuthContent,
|
||||
AuthButton,
|
||||
required,
|
||||
InfoBox,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: false,
|
||||
|
||||
licence: {
|
||||
purchaseCode: ''
|
||||
},
|
||||
purchaseCode: 'e3420e63-ce6f-4d04-9b3e-f7f5cc6af7c6'
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async verifyPurchaseCode() {
|
||||
|
||||
this.$router.push({name: 'Database'})
|
||||
return
|
||||
|
||||
// Validate fields
|
||||
const isValid = await this.$refs.verifyPurchaseCode.validate();
|
||||
|
||||
@@ -74,22 +72,31 @@
|
||||
|
||||
// Send request to get verify account
|
||||
axios
|
||||
.post('/api/setup-wizard', {
|
||||
step: this.step,
|
||||
data: this.stepLicence,
|
||||
.post('/api/setup/purchase-code', {
|
||||
purchaseCode: this.purchaseCode,
|
||||
})
|
||||
.then(response => {
|
||||
|
||||
// End loading
|
||||
this.isLoading = false
|
||||
|
||||
// Go to new page
|
||||
this.step++
|
||||
// Redirect to next step
|
||||
this.$router.push({name: 'Database'})
|
||||
})
|
||||
.catch(error => {
|
||||
|
||||
// End loading
|
||||
this.isLoading = false
|
||||
|
||||
if (error.response.status == 400) {
|
||||
this.$refs.verifyPurchaseCode.setErrors({
|
||||
'Purchase Code': ['Purchase code is invalid.']
|
||||
});
|
||||
} else {
|
||||
this.$refs.verifyPurchaseCode.setErrors({
|
||||
'Purchase Code': ['Something is wrong. Please try again.']
|
||||
});
|
||||
}
|
||||
})
|
||||
},
|
||||
},
|
||||
@@ -101,6 +108,13 @@
|
||||
@import '@assets/vue-file-manager/_auth';
|
||||
@import '@assets/vue-file-manager/_setup_wizard';
|
||||
|
||||
.additional-link {
|
||||
|
||||
.black-link {
|
||||
color: $text;
|
||||
}
|
||||
}
|
||||
|
||||
.auth-form input {
|
||||
min-width: 380px;
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
<ValidationObserver @submit.prevent="stripeCredentialsSubmit" ref="stripeCredentials" v-slot="{ invalid }" tag="form" class="form block-form">
|
||||
<InfoBox>
|
||||
<p>If you don’t have stripe account, please <a href="#" target="_blank">register here</a> and get your Stripe Key, Stripe Secret and Stripe Webhook Secret.</p>
|
||||
<p>If you don’t have stripe account, please <a href="#" target="_blank">register here</a> and get your Publishable Key, Secret Key and create your webhook.</p>
|
||||
</InfoBox>
|
||||
|
||||
<FormLabel>Stripe Setup</FormLabel>
|
||||
@@ -19,7 +19,7 @@
|
||||
<div class="block-wrapper">
|
||||
<label>Stripe Currency:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Currency" rules="required" v-slot="{ errors }">
|
||||
<SelectInput v-model="stripeCredentials.currency" :options="currencyList" default="mysql" placeholder="Select your stripe currency" :isError="errors[0]"/>
|
||||
<SelectInput v-model="stripeCredentials.currency" :options="currencyList" default="mysql" placeholder="Select your Stripe currency" :isError="errors[0]"/>
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
@@ -27,39 +27,50 @@
|
||||
<FormLabel class="mt-70">Stripe Credentials</FormLabel>
|
||||
|
||||
<div class="block-wrapper">
|
||||
<label>Stripe Key:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Key" rules="required" v-slot="{ errors }">
|
||||
<input v-model="stripeCredentials.key" placeholder="Type your stripe key" type="text" />
|
||||
<label>Publishable Key:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Publishable Key" rules="required" v-slot="{ errors }">
|
||||
<input v-model="stripeCredentials.key" placeholder="Paste your publishable key" type="text" :class="{'is-error': errors[0]}"/>
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
|
||||
<div class="block-wrapper">
|
||||
<label>Stripe Secret:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Secret" rules="required" v-slot="{ errors }">
|
||||
<input v-model="stripeCredentials.secret" placeholder="Type your stripe secret" type="text" />
|
||||
<label>Secret Key:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Secret Key" rules="required" v-slot="{ errors }">
|
||||
<input v-model="stripeCredentials.secret" placeholder="Paste your secret key" type="text" :class="{'is-error': errors[0]}"/>
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
|
||||
<div class="block-wrapper">
|
||||
<label>Stripe Webhook Secret:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Webhook Secret" rules="required" v-slot="{ errors }">
|
||||
<input v-model="stripeCredentials.webhookSecret" placeholder="Type your stripe webhook secret" type="text" />
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
<FormLabel class="mt-70">Stripe Webhook</FormLabel>
|
||||
<InfoBox>
|
||||
<p>You have to create webhook endpoint in your Stripe Dashboard. You can find it in <b>Dashboard -> Developers -> Webhooks -> Add Endpoint</b>. In Endpoint URL
|
||||
please copy and paste url bellow. Make sure, this url is your public domain, not localhost. In events section, please click on <b>receive all events</b>.
|
||||
That's all.</p>
|
||||
</InfoBox>
|
||||
|
||||
<div class="block-wrapper">
|
||||
<label>Stripe Webhook URL:</label>
|
||||
<label>Endpoint URL:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Webhook URL" rules="required" v-slot="{ errors }">
|
||||
<input :value="config.host + '/stripe/webhook'" placeholder="" type="text" disabled />
|
||||
<input :value="stripeWebhookEndpoint" type="text" disabled/>
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
|
||||
<div class="block-wrapper">
|
||||
<label>Webhook Secret:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Webhook Secret" rules="required" v-slot="{ errors }">
|
||||
<input v-model="stripeCredentials.webhookSecret" placeholder="Type your stripe webhook secret" type="text" :class="{'is-error': errors[0]}"/>
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
|
||||
<InfoBox v-if="isError" type="error" style="margin-bottom: -20px">
|
||||
<p>{{ errorMessage }}</p>
|
||||
</InfoBox>
|
||||
|
||||
<div class="submit-wrapper">
|
||||
<AuthButton icon="chevron-right" text="Save and Set Billings" :loading="isLoading" :disabled="isLoading"/>
|
||||
<AuthButton icon="chevron-right" :text="submitButtonText" :loading="isLoading" :disabled="isLoading"/>
|
||||
</div>
|
||||
|
||||
</ValidationObserver>
|
||||
@@ -96,10 +107,18 @@
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['config']),
|
||||
stripeWebhookEndpoint() {
|
||||
return this.config.host + '/stripe/webhook'
|
||||
},
|
||||
submitButtonText() {
|
||||
return this.isLoading ? 'Testing Stripe Connection' : 'Save and Set Billings'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: false,
|
||||
isError: false,
|
||||
errorMessage: '',
|
||||
currencyList: [
|
||||
{
|
||||
label: 'USD - United States Dollar',
|
||||
@@ -652,7 +671,36 @@
|
||||
},
|
||||
methods: {
|
||||
async stripeCredentialsSubmit() {
|
||||
|
||||
// Validate fields
|
||||
const isValid = await this.$refs.stripeCredentials.validate();
|
||||
|
||||
if (!isValid) return;
|
||||
|
||||
// Start loading
|
||||
this.isLoading = true
|
||||
|
||||
// Send request to get verify account
|
||||
axios
|
||||
.post('/api/setup/stripe-credentials', this.stripeCredentials)
|
||||
.then(response => {
|
||||
|
||||
// End loading
|
||||
this.isLoading = false
|
||||
|
||||
// Redirect to next step
|
||||
this.$router.push({name: 'BillingsDetail'})
|
||||
})
|
||||
.catch(error => {
|
||||
|
||||
if (error.response.status = 401) {
|
||||
this.isError = true
|
||||
this.errorMessage = error.response.data.message
|
||||
}
|
||||
|
||||
// End loading
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
},
|
||||
created() {
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
<h2>Set up plans for your customers.</h2>
|
||||
</div>
|
||||
|
||||
<ValidationObserver @submit.prevent="subscriptionPlansSubmit" ref="subscriptionPlans" v-slot="{ invalid }" tag="form" class="form block-form">
|
||||
<ValidationObserver @submit.prevent="subscriptionPlansSubmit" ref="subscriptionPlans" v-slot="{ invalid }"
|
||||
tag="form" class="form block-form">
|
||||
<FormLabel>Create your plans</FormLabel>
|
||||
<InfoBox>
|
||||
<p>Your plans will be <b>sorted automatically</b> in ascent order by plan price.</p>
|
||||
@@ -23,8 +24,8 @@
|
||||
<label>Name:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Name"
|
||||
rules="required" v-slot="{ errors }">
|
||||
<input v-model="plan.name" placeholder="Type your plan name"
|
||||
type="text"/>
|
||||
<input v-model="plan.attributes.name" placeholder="Type your plan name"
|
||||
type="text" :class="{'is-error': errors[0]}"/>
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
@@ -32,8 +33,9 @@
|
||||
<div class="block-wrapper">
|
||||
<label>Description (optional):</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Description"
|
||||
rules="required" v-slot="{ errors }">
|
||||
<textarea v-model="plan.description" placeholder="Type your plan description"></textarea>
|
||||
v-slot="{ errors }">
|
||||
<textarea v-model="plan.attributes.description"
|
||||
placeholder="Type your plan description" :class="{'is-error': errors[0]}"></textarea>
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
@@ -42,7 +44,9 @@
|
||||
<label>Price:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Price"
|
||||
rules="required" v-slot="{ errors }">
|
||||
<input v-model="plan.price" placeholder="Type your plan price" type="text"/>
|
||||
<input v-model="plan.attributes.price" placeholder="Type your plan price" type="number"
|
||||
step="0.01" min="1" max="99999"
|
||||
:class="{'is-error': errors[0]}"/>
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
@@ -51,7 +55,12 @@
|
||||
<label>Storage Capacity:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Storage Capacity"
|
||||
rules="required" v-slot="{ errors }">
|
||||
<input v-model="plan.storage_capacity" placeholder="Type your storage capacity" type="text"/>
|
||||
<input v-model="plan.attributes.capacity"
|
||||
min="1"
|
||||
max="999999999"
|
||||
placeholder="Type storage capacity in GB"
|
||||
type="number"
|
||||
:class="{'is-error': errors[0]}"/>
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
@@ -61,11 +70,13 @@
|
||||
@click.native="addRow"
|
||||
class="duplicator-add-button"
|
||||
button-style="theme-solid"
|
||||
>Add New Plan</ButtonBase>
|
||||
>Add New Plan
|
||||
</ButtonBase>
|
||||
</div>
|
||||
|
||||
<div class="submit-wrapper">
|
||||
<AuthButton icon="chevron-right" text="Save and Go Next" :loading="isLoading" :disabled="isLoading"/>
|
||||
<AuthButton icon="chevron-right" :text="submitButtonText" :loading="isLoading"
|
||||
:disabled="isLoading"/>
|
||||
</div>
|
||||
|
||||
</ValidationObserver>
|
||||
@@ -104,31 +115,68 @@
|
||||
InfoBox,
|
||||
XIcon,
|
||||
},
|
||||
computed: {
|
||||
submitButtonText() {
|
||||
return this.isLoading ? 'Creating Subscription Stripe Plans' : 'Save and Go Next'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: false,
|
||||
subscriptionPlans: [
|
||||
{
|
||||
id: 1,
|
||||
type: 'plan',
|
||||
attributes: {
|
||||
name: '',
|
||||
description: '',
|
||||
price: '',
|
||||
storage_capacity: '',
|
||||
capacity: '',
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async subscriptionPlansSubmit() {
|
||||
|
||||
// Validate fields
|
||||
const isValid = await this.$refs.subscriptionPlans.validate();
|
||||
|
||||
if (!isValid) return;
|
||||
|
||||
// Start loading
|
||||
this.isLoading = true
|
||||
|
||||
// Send request to get verify account
|
||||
axios
|
||||
.post('/api/setup/stripe-plans', {
|
||||
plans: this.subscriptionPlans
|
||||
})
|
||||
.then(response => {
|
||||
|
||||
// End loading
|
||||
this.isLoading = false
|
||||
|
||||
// Redirect to next step
|
||||
this.$router.push({name: 'EnvironmentSetup'})
|
||||
})
|
||||
.catch(error => {
|
||||
|
||||
// End loading
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
addRow() {
|
||||
this.subscriptionPlans.push({
|
||||
id: Math.floor(Math.random() * 10000000),
|
||||
type: 'plans',
|
||||
attributes: {
|
||||
name: '',
|
||||
description: '',
|
||||
price: '',
|
||||
storage_capacity: '',
|
||||
capacity: '',
|
||||
}
|
||||
})
|
||||
},
|
||||
removeRow(plan) {
|
||||
|
||||
145
resources/js/views/SetupWIzard/SubscriptionService.vue
Normal file
145
resources/js/views/SetupWIzard/SubscriptionService.vue
Normal file
@@ -0,0 +1,145 @@
|
||||
<template>
|
||||
<AuthContentWrapper ref="auth">
|
||||
|
||||
<!--Licence Verify-->
|
||||
<AuthContent name="subscription-service" :visible="true">
|
||||
|
||||
<div class="content-headline">
|
||||
<settings-icon size="40" class="title-icon"></settings-icon>
|
||||
<h1>Setup Wizard</h1>
|
||||
<h2>You can charge users for storage space by monthly billing plans. Please, select your charging service or skip this step if you don't want charge users:</h2>
|
||||
</div>
|
||||
|
||||
<div class="services">
|
||||
<router-link :to="{name: 'StripeCredentials'}" tag="div" class="service-card">
|
||||
<img src="/assets/icons/stripe-service.svg" alt="Stripe" class="service-logo">
|
||||
|
||||
<div class="service-content">
|
||||
<b class="service-title">Charging with Stripe</b>
|
||||
<p class="service-description">You can create custom storage plans and charge your users with monthly subscription.</p>
|
||||
</div>
|
||||
|
||||
<router-link :to="{name: 'StripeCredentials'}" class="service-link">
|
||||
<span>Set Up Billing and Plans With Stripe</span>
|
||||
<chevron-right-icon size="22" class="icon"></chevron-right-icon>
|
||||
</router-link>
|
||||
</router-link>
|
||||
</div>
|
||||
|
||||
<p class="additional-link">
|
||||
<router-link :to="{name: 'EnvironmentSetup'}">
|
||||
<AuthButton class="skip-subscription-setup" icon="chevron-right" text="I will set up Stripe later" />
|
||||
</router-link>
|
||||
</p>
|
||||
</AuthContent>
|
||||
</AuthContentWrapper>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AuthContentWrapper from '@/components/Auth/AuthContentWrapper'
|
||||
import {ValidationProvider, ValidationObserver} from 'vee-validate/dist/vee-validate.full'
|
||||
import AuthContent from '@/components/Auth/AuthContent'
|
||||
import AuthButton from '@/components/Auth/AuthButton'
|
||||
import { SettingsIcon, ChevronRightIcon } from 'vue-feather-icons'
|
||||
import {required} from 'vee-validate/dist/rules'
|
||||
import {mapGetters} from 'vuex'
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
name: 'SubscriptionService',
|
||||
components: {
|
||||
AuthContentWrapper,
|
||||
ValidationProvider,
|
||||
ValidationObserver,
|
||||
ChevronRightIcon,
|
||||
SettingsIcon,
|
||||
AuthContent,
|
||||
AuthButton,
|
||||
required,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: false,
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '@assets/vue-file-manager/_auth-form';
|
||||
@import '@assets/vue-file-manager/_auth';
|
||||
@import '@assets/vue-file-manager/_setup_wizard';
|
||||
|
||||
.services {
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.service-card {
|
||||
text-align: left;
|
||||
box-shadow: 0 5px 30px 5px rgba(#3D4EFD, 0.25);
|
||||
border-radius: 20px;
|
||||
max-width: 415px;
|
||||
display: inline-block;
|
||||
padding: 30px;
|
||||
background: rgb(58,75,255);
|
||||
background: linear-gradient(135deg, rgba(58,75,255,1) 0%, rgba(103,114,229,1) 100%);
|
||||
@include transition(200ms);
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
box-shadow: 0 8px 35px 5px rgba(#3D4EFD, 0.4);
|
||||
@include transform(scale(1.02));
|
||||
}
|
||||
|
||||
.service-logo {
|
||||
margin-bottom: 30px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.service-content {
|
||||
margin-bottom: 65px;
|
||||
|
||||
.service-title {
|
||||
@include font-size(18);
|
||||
font-weight: 700;
|
||||
color: white;
|
||||
margin-bottom: 5px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.service-description {
|
||||
@include font-size(16);
|
||||
font-weight: 600;
|
||||
color: white;
|
||||
opacity: 0.8;
|
||||
}
|
||||
}
|
||||
|
||||
.service-link {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.icon {
|
||||
margin-left: 5px;
|
||||
|
||||
polyline {
|
||||
stroke: white
|
||||
}
|
||||
}
|
||||
|
||||
span {
|
||||
@include font-size(16);
|
||||
font-weight: 700;
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.skip-subscription-setup {
|
||||
border: none !important;
|
||||
}
|
||||
|
||||
.auth-form input {
|
||||
min-width: 380px;
|
||||
}
|
||||
</style>
|
||||
@@ -327,8 +327,6 @@
|
||||
// If user don't have credit card, register new
|
||||
if (!this.defaultPaymentMethod || this.payByNewCard) {
|
||||
|
||||
console.log('Payment by new card');
|
||||
|
||||
const {setupIntent, error} = await stripe.confirmCardSetup(this.clientSecret, {
|
||||
payment_method: {
|
||||
card: card,
|
||||
@@ -367,8 +365,6 @@
|
||||
// if user has credit card
|
||||
if (this.defaultPaymentMethod && !this.payByNewCard) {
|
||||
|
||||
console.log('Payment by default card');
|
||||
|
||||
axios
|
||||
.post('/api/subscription/upgrade', {
|
||||
billing: this.billing,
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
.content-headline {
|
||||
max-width: 630px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.auth-form {
|
||||
|
||||
input {
|
||||
|
||||
@@ -16,6 +16,20 @@
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
// Setup Wizard
|
||||
Route::group(['middleware' => ['api'], 'prefix' => 'setup'], function () {
|
||||
Route::post('/purchase-code', 'General\SetupWizardController@verify_purchase_code');
|
||||
Route::post('/database', 'General\SetupWizardController@setup_database');
|
||||
|
||||
Route::post('/stripe-credentials', 'General\SetupWizardController@store_stripe_credentials');
|
||||
Route::post('/stripe-billings', 'General\SetupWizardController@store_stripe_billings');
|
||||
Route::post('/stripe-plans', 'General\SetupWizardController@store_stripe_plans');
|
||||
|
||||
Route::post('/environment-setup', 'General\SetupWizardController@store_environment_setup');
|
||||
Route::post('/app-setup', 'General\SetupWizardController@store_app_settings');
|
||||
Route::post('/admin-setup', 'General\SetupWizardController@create_admin_account');
|
||||
});
|
||||
|
||||
// Plans
|
||||
Route::group(['middleware' => ['api'], 'prefix' => 'public'], function () {
|
||||
Route::get('/pricing', 'General\PricingController@index');
|
||||
|
||||
3
storage/framework/cache/.gitignore
vendored
3
storage/framework/cache/.gitignore
vendored
@@ -1,3 +0,0 @@
|
||||
*
|
||||
!data/
|
||||
!.gitignore
|
||||
Reference in New Issue
Block a user