Compare commits
68 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b5963693e6 | ||
|
|
1b7ea67fde | ||
|
|
d4f2b9839e | ||
|
|
817f6a175c | ||
|
|
b3619e5941 | ||
|
|
33784410e5 | ||
|
|
6ecf7904fe | ||
|
|
21986f2394 | ||
|
|
4d8212e56f | ||
|
|
865f2958cf | ||
|
|
17890d13ad | ||
|
|
2d33455731 | ||
|
|
49481f9b6a | ||
|
|
7bb800cc0a | ||
|
|
1b8c2c764f | ||
|
|
cb1a1c4c06 | ||
|
|
ddd80a8687 | ||
|
|
010d4569c2 | ||
|
|
62ae0f8299 | ||
|
|
2a3d9cabd0 | ||
|
|
e2a58cf2df | ||
|
|
0fd6db251b | ||
|
|
94d50c11ef | ||
|
|
14c6faafa2 | ||
|
|
ea21076eda | ||
|
|
d378323602 | ||
|
|
f074dee990 | ||
|
|
7bd2917ec4 | ||
|
|
823a39ffa2 | ||
|
|
6953a8d2b2 | ||
|
|
fb40b450b6 | ||
|
|
a28c053945 | ||
|
|
ea0c4ed66d | ||
|
|
7a0716959a | ||
|
|
da322d7b1e | ||
|
|
bbff8a5403 | ||
|
|
c1ad600042 | ||
|
|
5fc32759fd | ||
|
|
59cfd8d71b | ||
|
|
51d5b89df7 | ||
|
|
7c0dcbeb88 | ||
|
|
b4467f8d5b | ||
|
|
363f4ed801 | ||
|
|
1b6b950fb5 | ||
|
|
90988f1538 | ||
|
|
139ba793d0 | ||
|
|
c505dd0924 | ||
|
|
ca5ee33978 | ||
|
|
c2fd5e3fa9 | ||
|
|
b04176ce48 | ||
|
|
5136a4b9f8 | ||
|
|
dcee703aa1 | ||
|
|
7c504339d9 | ||
|
|
5ea0761fe9 | ||
|
|
c9125c3be8 | ||
|
|
84503c19db | ||
|
|
cfd9eba5d7 | ||
|
|
10689d3d12 | ||
|
|
e190fb7805 | ||
|
|
c1351f7d28 | ||
|
|
01f5469e86 | ||
|
|
8c5c86eb6a | ||
|
|
995ada46aa | ||
|
|
2e79381872 | ||
|
|
d1c7b9a418 | ||
|
|
34da2f563d | ||
|
|
5cf77fde1c | ||
|
|
aabf6f27ac |
@@ -26,6 +26,7 @@ SESSION_LIFETIME=120
|
||||
REDIS_HOST=127.0.0.1
|
||||
REDIS_PASSWORD=null
|
||||
REDIS_PORT=6379
|
||||
REDIS_CLIENT=predis
|
||||
|
||||
MAIL_MAILER=smtp
|
||||
MAIL_HOST=smtp.mailtrap.io
|
||||
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -12,4 +12,9 @@ npm-debug.log
|
||||
yarn-error.log
|
||||
.idea
|
||||
.php_cs.cache
|
||||
.php-cs-fixer.cache
|
||||
/public/js/resources*.js
|
||||
/storage/views/header.blade.php
|
||||
/storage/views/footer.blade.php
|
||||
rr
|
||||
.rr.yaml
|
||||
|
||||
26
app/Casts/SiteAlias.php
Normal file
26
app/Casts/SiteAlias.php
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace App\Casts;
|
||||
|
||||
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
|
||||
|
||||
class SiteAlias implements CastsAttributes
|
||||
{
|
||||
public function get($model, string $key, $value, array $attributes)
|
||||
{
|
||||
if (!$value) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$data = json_decode($value, true);
|
||||
|
||||
sort($data);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function set($model, string $key, $value, array $attributes)
|
||||
{
|
||||
return json_encode($value);
|
||||
}
|
||||
}
|
||||
60
app/Console/Commands/Core/Cleanup.php
Normal file
60
app/Console/Commands/Core/Cleanup.php
Normal file
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands\Core;
|
||||
|
||||
use App\Models\SystemLog;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
class Cleanup extends Command
|
||||
{
|
||||
protected $signature = 'core:cleanup';
|
||||
|
||||
protected $description = 'Clean up any old logs';
|
||||
|
||||
public function handle()
|
||||
{
|
||||
if (!setting('rotate_logs_after')) {
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
$rotationDate = $this->getRotationDate();
|
||||
|
||||
$rotated = SystemLog::query()
|
||||
->where('created_at', '<', $rotationDate)
|
||||
->delete();
|
||||
|
||||
$this->info('Rotated ' . $rotated . ' system logs!');
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
protected function getRotationDate()
|
||||
{
|
||||
switch (setting('rotate_logs_after')) {
|
||||
case 'weeks-1':
|
||||
return now()->subWeek();
|
||||
break;
|
||||
case 'months-1':
|
||||
return now()->subMonth();
|
||||
break;
|
||||
case 'months-3':
|
||||
return now()->subMonths(3);
|
||||
break;
|
||||
case 'months-6':
|
||||
return now()->subMonths(6);
|
||||
break;
|
||||
case 'years-1':
|
||||
return now()->subYear();
|
||||
break;
|
||||
case 'years-2':
|
||||
return now()->subYears(2);
|
||||
break;
|
||||
case 'years-3':
|
||||
return now()->subYears(3);
|
||||
break;
|
||||
case 'years-4':
|
||||
return now()->subYears(4);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -42,6 +42,9 @@ class Install extends Command
|
||||
$this->line(' ');
|
||||
$this->writeSeparationLine();
|
||||
$this->info('Make sure to also setup emailing, the cronjob and the queue worker.');
|
||||
$this->line(' ');
|
||||
$this->info('Setting up emailing: https://docs.ploi-core.io/getting-started/setting-up-email');
|
||||
$this->info('Setting up cronjob & queue worker: https://docs.ploi-core.io/getting-started/installation');
|
||||
$this->writeSeparationLine();
|
||||
$this->line(' ');
|
||||
$this->info('Visit your platform at ' . env('APP_URL'));
|
||||
@@ -54,28 +57,32 @@ class Install extends Command
|
||||
|
||||
protected function askAboutAdministrationAccount()
|
||||
{
|
||||
$this->info('Let\'s start by setting up your administration account.');
|
||||
if (!User::query()->where('role', User::ADMIN)->count()) {
|
||||
$this->info('Let\'s start by setting up your administration account.');
|
||||
|
||||
$name = $this->ask('What is your name', $this->company['user_name']);
|
||||
$email = $this->ask('What is your e-mail address', $this->company['email']);
|
||||
$password = $this->secret('What password do you desire');
|
||||
$name = $this->ask('What is your name', $this->company['user_name']);
|
||||
$email = $this->ask('What is your e-mail address', $this->company['email']);
|
||||
$password = $this->secret('What password do you desire');
|
||||
|
||||
$check = User::where('email', $email)->count();
|
||||
$check = User::where('email', $email)->count();
|
||||
|
||||
if ($check) {
|
||||
$this->line('');
|
||||
$this->comment('This user is already present in your system, please refresh your database or use different credentials.');
|
||||
$this->comment('Aborting installation..');
|
||||
if ($check) {
|
||||
$this->line('');
|
||||
$this->comment('This user is already present in your system, please refresh your database or use different credentials.');
|
||||
$this->comment('Aborting installation..');
|
||||
|
||||
exit();
|
||||
exit();
|
||||
}
|
||||
|
||||
User::forceCreate([
|
||||
'name' => $name,
|
||||
'email' => $email,
|
||||
'password' => $password,
|
||||
'role' => User::ADMIN
|
||||
]);
|
||||
} else {
|
||||
$this->line('Already found a administrator user in your system. Use that user to login.');
|
||||
}
|
||||
|
||||
User::forceCreate([
|
||||
'name' => $name,
|
||||
'email' => $email,
|
||||
'password' => $password,
|
||||
'role' => User::ADMIN
|
||||
]);
|
||||
}
|
||||
|
||||
protected function askAboutDefaultPackages()
|
||||
@@ -195,9 +202,9 @@ class Install extends Command
|
||||
{
|
||||
if (!config('app.key')) {
|
||||
$this->call('key:generate');
|
||||
}
|
||||
|
||||
$this->info('Application key has been set');
|
||||
$this->info('Application key has been set');
|
||||
}
|
||||
}
|
||||
|
||||
protected function checkApplicationUrl()
|
||||
@@ -308,7 +315,7 @@ class Install extends Command
|
||||
protected function runDatabaseMigrations()
|
||||
{
|
||||
$this->info('Running database migrations..');
|
||||
$this->call('migrate');
|
||||
$this->call('migrate', ['--force' => true]);
|
||||
$this->info('Database migrations successful');
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ class Synchronize extends Command
|
||||
{
|
||||
protected $signature = 'core:synchronize';
|
||||
|
||||
protected $description = 'Synchronze data';
|
||||
protected $description = 'Synchronize data';
|
||||
|
||||
public function handle()
|
||||
{
|
||||
|
||||
24
app/Console/Commands/Core/Trial.php
Normal file
24
app/Console/Commands/Core/Trial.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands\Core;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
class Trial extends Command
|
||||
{
|
||||
protected $signature = 'core:trial';
|
||||
|
||||
protected $description = 'Check for expired trials';
|
||||
|
||||
public function handle()
|
||||
{
|
||||
User::query()
|
||||
->where('trial_ends_at', '<', now())
|
||||
->each(function (User $user) {
|
||||
$user->trial_ends_at = null;
|
||||
$user->package_id = setting('default_package');
|
||||
$user->save();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -2,8 +2,10 @@
|
||||
|
||||
namespace App\Console;
|
||||
|
||||
use App\Console\Commands\Core\Trial;
|
||||
use App\Jobs\Core\Ping;
|
||||
use App\Console\Commands\Core\Css;
|
||||
use App\Console\Commands\Core\Cleanup;
|
||||
use App\Console\Commands\Core\Install;
|
||||
use App\Console\Commands\Core\CssBackup;
|
||||
use App\Console\Commands\Core\Synchronize;
|
||||
@@ -17,6 +19,8 @@ class Kernel extends ConsoleKernel
|
||||
CssBackup::class,
|
||||
Install::class,
|
||||
Synchronize::class,
|
||||
Cleanup::class,
|
||||
Trial::class,
|
||||
];
|
||||
|
||||
protected function schedule(Schedule $schedule)
|
||||
@@ -24,5 +28,8 @@ class Kernel extends ConsoleKernel
|
||||
$schedule->call(function () {
|
||||
dispatch(new Ping())->delay(now()->addMinutes(rand(1, 30)));
|
||||
})->dailyAt('02:00');
|
||||
|
||||
$schedule->command('core:cleanup')->daily();
|
||||
$schedule->command('core:trial')->dailyAt('10:00');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ if (!function_exists('setting')) {
|
||||
$value = Arr::get(app('settings'), $key, $default);
|
||||
|
||||
// Boolean casting
|
||||
if ($value === "0" || $value === "1") {
|
||||
if ($value === "0" || $value === "1" && $key !== 'trial_package') {
|
||||
return (bool) $value;
|
||||
}
|
||||
|
||||
|
||||
@@ -10,14 +10,17 @@ use App\Http\Controllers\Controller;
|
||||
|
||||
class DashboardController extends Controller
|
||||
{
|
||||
public function index()
|
||||
public function __invoke()
|
||||
{
|
||||
return inertia('Admin/Dashboard', [
|
||||
'servers' => Server::count(),
|
||||
'sites' => Site::count(),
|
||||
'users' => User::count(),
|
||||
'logs' => SystemLog::latest()->limit(10)->with('model')->get()
|
||||
->map(function (SystemLog $systemLog) {
|
||||
'logs' => SystemLog::query()
|
||||
->latest()
|
||||
->with('model')
|
||||
->paginate(5)
|
||||
->through(function (SystemLog $systemLog) {
|
||||
return [
|
||||
'title' => __($systemLog->title, [
|
||||
'site' => $systemLog->model->domain ?? '-Unknown-'
|
||||
|
||||
@@ -4,12 +4,39 @@ namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Models\Server;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Resources\Admin\ServerResource;
|
||||
use App\Http\Requests\Admin\ServerAttachRequest;
|
||||
|
||||
class ServerController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
return inertia('Admin/Servers/Index', [
|
||||
'filters' => request()->all('search'),
|
||||
'servers' => ServerResource::collection(
|
||||
Server::query()
|
||||
->when(request()->input('search'), function (Builder $query, $value) {
|
||||
return $query
|
||||
->where('name', 'like', '%' . $value . '%')
|
||||
->orWhere('ip', 'like', '%' . $value . '%')
|
||||
->orWhereHas('users', function (Builder $query) use ($value) {
|
||||
return $query
|
||||
->where('name', 'LIKE', '%' . $value . '%')
|
||||
->orWhere('email', 'LIKE', '%' . $value . '%');
|
||||
});
|
||||
})
|
||||
->with('users:id,name')
|
||||
->withCount('sites')
|
||||
->latest()
|
||||
->paginate(config('core.pagination.per_page'))
|
||||
->withQueryString()
|
||||
)
|
||||
]);
|
||||
}
|
||||
|
||||
public function edit($id)
|
||||
{
|
||||
$server = Server::findOrFail($id);
|
||||
|
||||
@@ -12,12 +12,12 @@ class ServiceController extends Controller
|
||||
public function index()
|
||||
{
|
||||
return inertia('Admin/Services/Index', [
|
||||
'servers' => Server::query()->withCount('sites', 'users')->latest()->paginate(5, ['*'], 'servers_per_page'),
|
||||
'sites' => Site::with('server:id,name')->withCount('users')->latest()->paginate(5, ['*'], 'sites_per_page'),
|
||||
'servers' => Server::query()->withCount('sites', 'users')->latest()->paginate(config('core.pagination.per_page'), ['*'], 'servers_per_page'),
|
||||
'sites' => Site::with('server:id,name')->withCount('users')->latest()->paginate(config('core.pagination.per_page'), ['*'], 'sites_per_page'),
|
||||
'providers' => Provider::query()
|
||||
->withCount('regions', 'plans', 'servers')
|
||||
->latest()
|
||||
->paginate(5, ['*'], 'providers_per_page'),
|
||||
->paginate(config('core.pagination.per_page'), ['*'], 'providers_per_page'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Models\Package;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use App\Http\Requests\Admin\SettingRequest;
|
||||
@@ -22,10 +22,15 @@ class SettingController extends Controller
|
||||
'allow_registration' => setting('allow_registration'),
|
||||
'default_package' => setting('default_package'),
|
||||
'receive_email_on_server_creation' => setting('receive_email_on_server_creation'),
|
||||
'receive_email_on_site_creation' => setting('receive_email_on_site_creation'),
|
||||
'isolate_per_site_per_user' => setting('isolate_per_site_per_user'),
|
||||
'enable_api' => setting('enable_api'),
|
||||
'api_token' => setting('api_token') ? decrypt(setting('api_token')) : null,
|
||||
'default_language' => setting('default_language', 'en')
|
||||
'rotate_logs_after' => setting('rotate_logs_after') ? setting('rotate_logs_after') : null,
|
||||
'default_language' => setting('default_language', 'en'),
|
||||
'has_logo' => (bool)setting('logo'),
|
||||
'trial' => setting('trial'),
|
||||
'trial_package' => setting('trial_package'),
|
||||
];
|
||||
|
||||
$packages = Package::pluck('name', 'id');
|
||||
@@ -48,10 +53,14 @@ class SettingController extends Controller
|
||||
'documentation',
|
||||
'default_package',
|
||||
'receive_email_on_server_creation',
|
||||
'receive_email_on_site_creation',
|
||||
'isolate_per_site_per_user',
|
||||
'enable_api',
|
||||
'api_token',
|
||||
'default_language'
|
||||
'default_language',
|
||||
'rotate_logs_after',
|
||||
'trial',
|
||||
'trial_package'
|
||||
]) as $key => $value) {
|
||||
if ($key === 'api_token') {
|
||||
$value = encrypt($value);
|
||||
@@ -92,7 +101,7 @@ class SettingController extends Controller
|
||||
public function terms()
|
||||
{
|
||||
return inertia('Admin/Terms', [
|
||||
'settings' => [
|
||||
'terms_settings' => [
|
||||
'logo' => setting('logo'),
|
||||
'name' => setting('name'),
|
||||
'terms_required' => setting('accept_terms_required'),
|
||||
@@ -126,4 +135,13 @@ class SettingController extends Controller
|
||||
|
||||
return ['content' => $template];
|
||||
}
|
||||
|
||||
public function removeLogo(Request $request)
|
||||
{
|
||||
Storage::delete(setting('logo'));
|
||||
|
||||
setting(['logo' => null]);
|
||||
|
||||
return redirect()->back()->with('success', 'Logo has ben removed');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Resources\Admin\SiteResource;
|
||||
use App\Models\Site;
|
||||
use App\Models\User;
|
||||
use Illuminate\Http\Request;
|
||||
@@ -10,6 +11,23 @@ use App\Http\Requests\Admin\ServerAttachRequest;
|
||||
|
||||
class SiteController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
return inertia('Admin/Sites/Index', [
|
||||
'filters' => request()->all('search'),
|
||||
'sites' => SiteResource::collection(
|
||||
Site::query()
|
||||
->when(request()->input('search'), function ($query, $value) {
|
||||
return $query->where('domain', 'like', '%' . $value . '%');
|
||||
})
|
||||
->with('server:id,name', 'users:id,name')
|
||||
->latest()
|
||||
->paginate(config('core.pagination.per_page'))
|
||||
->withQueryString()
|
||||
)
|
||||
]);
|
||||
}
|
||||
|
||||
public function edit($id)
|
||||
{
|
||||
$site = Site::findOrFail($id);
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Models\Provider;
|
||||
use App\Services\Ploi\Ploi;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
|
||||
@@ -31,17 +31,36 @@ class SynchronizeSiteController extends Controller
|
||||
{
|
||||
$server = Server::query()->where('ploi_id', $request->input('server_id'))->firstOrFail();
|
||||
|
||||
/* @var $site \App\Models\Site */
|
||||
$site = Site::query()
|
||||
->updateOrCreate([
|
||||
'ploi_id' => $request->input('id')
|
||||
], [
|
||||
'domain' => $request->input('domain'),
|
||||
'php_version' => $request->input('php_version'),
|
||||
'project' => $request->input('project_type')
|
||||
]);
|
||||
|
||||
$site->status = $request->input('status');
|
||||
$site->server_id = $server->id;
|
||||
$site->save();
|
||||
|
||||
$certificates = $this->getPloi()->server($request->input('server_id'))->sites($request->input('id'))->certificates()->get()->getData();
|
||||
|
||||
if ($certificates) {
|
||||
foreach ($certificates as $certificate) {
|
||||
$site->certificates()->updateOrCreate([
|
||||
'ploi_id' => $certificate->id,
|
||||
], [
|
||||
'status' => $certificate->status,
|
||||
'ploi_id' => $certificate->id,
|
||||
'domain' => $certificate->domain,
|
||||
'type' => $certificate->type,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
return response('ok');
|
||||
}
|
||||
|
||||
public function synchronizeAll(Request $request)
|
||||
@@ -53,7 +72,7 @@ class SynchronizeSiteController extends Controller
|
||||
|
||||
$site = Site::query()
|
||||
->updateOrCreate([
|
||||
'ploi_id' => $availableSite->server_id
|
||||
'ploi_id' => $availableSite->id
|
||||
], [
|
||||
'domain' => $availableSite->domain,
|
||||
'php_version' => $availableSite->php_version,
|
||||
|
||||
@@ -12,24 +12,15 @@ class SystemController extends Controller
|
||||
{
|
||||
public function index(MasterSupervisorRepository $masterSupervisorRepository)
|
||||
{
|
||||
if (config('app.demo')) {
|
||||
return redirect('/')->with('info', __('This feature is not available in demo mode.'));
|
||||
}
|
||||
|
||||
$version = (new VersionChecker)->getVersions();
|
||||
|
||||
$horizonRunning = true;
|
||||
if (!$masterSupervisorRepository->all()) {
|
||||
$horizonRunning = false;
|
||||
}
|
||||
|
||||
return inertia('Admin/System', [
|
||||
'version' => [
|
||||
'out_of_date' => $version->isOutOfDate(),
|
||||
'current' => $version->currentVersion,
|
||||
'remote' => $version->remoteVersion
|
||||
],
|
||||
'horizonRunning' => $horizonRunning
|
||||
'horizonRunning' => !!$masterSupervisorRepository->all()
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
@@ -11,12 +11,14 @@ class UserController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
$users = User::with('package:id,name')
|
||||
$users = User::query()
|
||||
->withCount('sites', 'servers')
|
||||
->with('package:id,name')
|
||||
->when(request()->input('search'), function ($query, $value) {
|
||||
return $query->where('name', 'like', '%' . $value . '%')->orWhere('email', 'like', '%' . $value . '%');
|
||||
})
|
||||
->latest()
|
||||
->paginate(5);
|
||||
->paginate(config('core.pagination.per_page'));
|
||||
|
||||
return inertia('Admin/Users/Index', [
|
||||
'filters' => request()->all('search'),
|
||||
@@ -57,9 +59,9 @@ class UserController extends Controller
|
||||
{
|
||||
$user = User::query()->findOrFail($id);
|
||||
|
||||
$servers = $user->servers()->withCount('sites')->latest()->paginate(5, ['*'], 'page_servers');
|
||||
$servers = $user->servers()->withCount('sites')->latest()->paginate(config('core.pagination.per_page'), ['*'], 'page_servers');
|
||||
|
||||
$sites = $user->sites()->with('server:id,name')->latest()->paginate(5, ['*'], 'page_sites');
|
||||
$sites = $user->sites()->with('server:id,name')->latest()->paginate(config('core.pagination.per_page'), ['*'], 'page_sites');
|
||||
|
||||
return inertia('Admin/Users/Show', [
|
||||
'user' => $user,
|
||||
|
||||
@@ -35,10 +35,7 @@ class RegisterController extends Controller
|
||||
'required',
|
||||
'string',
|
||||
'confirmed',
|
||||
Password::min(6)
|
||||
->letters()
|
||||
->numbers()
|
||||
->uncompromised()
|
||||
Password::defaults()
|
||||
],
|
||||
];
|
||||
|
||||
@@ -53,18 +50,33 @@ class RegisterController extends Controller
|
||||
|
||||
protected function create(array $data)
|
||||
{
|
||||
return User::create([
|
||||
$fields = [
|
||||
'name' => $data['name'],
|
||||
'email' => $data['email'],
|
||||
'password' => $data['password'],
|
||||
]);
|
||||
];
|
||||
|
||||
if ($days = setting('trial')) {
|
||||
$fields['trial_ends_at'] = now()->addDays($days);
|
||||
}
|
||||
|
||||
return User::create($fields);
|
||||
}
|
||||
|
||||
protected function registered(Request $request, $user)
|
||||
{
|
||||
if (setting('default_package') && setting('default_package') != 'false') {
|
||||
if (
|
||||
setting('default_package') &&
|
||||
setting('default_package') != 'false' &&
|
||||
!setting('trial')
|
||||
) {
|
||||
$user->package_id = setting('default_package');
|
||||
$user->save();
|
||||
}
|
||||
|
||||
if (setting('trial') && setting('trial_package')) {
|
||||
$user->package_id = setting('trial_package');
|
||||
$user->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,11 +77,14 @@ class ProfileBillingController extends Controller
|
||||
return inertia('Profile/BillingError');
|
||||
}
|
||||
|
||||
$subscription = $user->subscription();
|
||||
|
||||
return inertia('Profile/Billing', [
|
||||
'packages' => $packages,
|
||||
'countries' => countries(),
|
||||
'subscription' => $user->subscription('default'),
|
||||
'subscription' => $subscription,
|
||||
'public_key' => config('cashier.key'),
|
||||
'ends' => $subscription ? Carbon::createFromTimeStamp($subscription->asStripeSubscription()->current_period_end)->format('F jS, Y') ?? null : null,
|
||||
'data_client_secret' => $clientSecret,
|
||||
'card' => [
|
||||
'last_four' => $user->card_last_four,
|
||||
@@ -122,6 +125,16 @@ class ProfileBillingController extends Controller
|
||||
return redirect()->route('profile.billing.index')->with('success', 'Your card has been added, you can now update your plan');
|
||||
}
|
||||
|
||||
public function deleteCard(Request $request)
|
||||
{
|
||||
/** @var User $user */
|
||||
$user = $request->user();
|
||||
|
||||
$user->deletePaymentMethods();
|
||||
|
||||
return redirect()->route('profile.billing.index')->with('success', 'Your credit card has been removed from your account');
|
||||
}
|
||||
|
||||
public function updatePlan(Request $request)
|
||||
{
|
||||
/** @var User $user */
|
||||
@@ -210,6 +223,7 @@ class ProfileBillingController extends Controller
|
||||
Package::CURRENCY_GBP => 'GBP £',
|
||||
Package::CURRENCY_INR => 'INR ₹',
|
||||
Package::CURRENCY_THB => 'THB ',
|
||||
Package::CURRENCY_BRL=> 'BRL R$ ',
|
||||
];
|
||||
|
||||
return $currencies[strtolower($key)] ?? '$';
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Server;
|
||||
use App\Models\User;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Jobs\Servers\CreateServer;
|
||||
@@ -38,7 +39,8 @@ class ServerController extends Controller
|
||||
|
||||
/* @var $server \App\Models\Server */
|
||||
$server = $request->user()->servers()->create([
|
||||
'name' => $request->input('name')
|
||||
'name' => $request->input('name'),
|
||||
'database_type' => $request->input('database_type', 'mysql')
|
||||
]);
|
||||
|
||||
$server->provider()->associate($provider);
|
||||
@@ -65,6 +67,10 @@ class ServerController extends Controller
|
||||
{
|
||||
$server = auth()->user()->servers()->findOrFail($id);
|
||||
|
||||
if ($server->status === Server::STATUS_BUSY) {
|
||||
return redirect()->back()->with('info', 'This server is currently busy, please check back later.');
|
||||
}
|
||||
|
||||
return inertia('Servers/Show', [
|
||||
'server' => $server,
|
||||
'sites' => $server->sites()->latest()->paginate(5, ['*'], 'sites_per_page'),
|
||||
|
||||
44
app/Http/Controllers/SiteAliasController.php
Normal file
44
app/Http/Controllers/SiteAliasController.php
Normal file
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Http\Requests\SiteAliasRequest;
|
||||
use App\Http\Resources\SiteAliasResource;
|
||||
use App\Jobs\Aliases\CreateAlias;
|
||||
use App\Jobs\Aliases\DeleteAlias;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class SiteAliasController extends Controller
|
||||
{
|
||||
public function index($id)
|
||||
{
|
||||
$site = auth()->user()->sites()->findOrFail($id);
|
||||
|
||||
return inertia('Sites/Aliases', [
|
||||
'site' => $site,
|
||||
'aliases' => $site->aliases
|
||||
]);
|
||||
}
|
||||
|
||||
public function store(SiteAliasRequest $request, $id)
|
||||
{
|
||||
$site = $request->user()->sites()->findOrFail($id);
|
||||
|
||||
$site->addAlias($request->input('domain'));
|
||||
|
||||
dispatch(new CreateAlias($site, $request->input('domain')));
|
||||
|
||||
return redirect()->route('sites.aliases.index', $id)->with('success', __('Alias has been created'));
|
||||
}
|
||||
|
||||
public function destroy($id, $alias)
|
||||
{
|
||||
$site = auth()->user()->sites()->findOrFail($id);
|
||||
|
||||
dispatch(new DeleteAlias($site, $alias));
|
||||
|
||||
$site->removeAlias($alias);
|
||||
|
||||
return redirect()->route('sites.aliases.index', $id)->with('success', __('Alias has been deleted'));
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,9 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Mail\Admin\Site\AdminSiteCreatedEmail;
|
||||
use App\Models\Server;
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Jobs\Sites\CreateSite;
|
||||
@@ -10,6 +12,7 @@ use App\Jobs\Sites\DeleteSite;
|
||||
use App\Http\Requests\SiteRequest;
|
||||
use App\Http\Resources\SiteResource;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
|
||||
class SiteController extends Controller
|
||||
{
|
||||
@@ -17,11 +20,12 @@ class SiteController extends Controller
|
||||
{
|
||||
$sites = auth()->user()
|
||||
->sites()
|
||||
->with('server:id,name')
|
||||
->when(request('server'), function ($query, $value) {
|
||||
return $query->where('server_id', $value);
|
||||
})
|
||||
->latest()
|
||||
->paginate(10);
|
||||
->paginate(config('core.pagination.per_page'));
|
||||
|
||||
$availableServers = auth()->user()->servers()->pluck('name', 'id');
|
||||
|
||||
@@ -75,6 +79,14 @@ class SiteController extends Controller
|
||||
'description' => 'A new site has been created'
|
||||
])->model()->associate($site)->save();
|
||||
|
||||
if (setting('receive_email_on_site_creation')) {
|
||||
$admins = User::query()->where('role', User::ADMIN)->get();
|
||||
|
||||
foreach ($admins as $admin) {
|
||||
Mail::to($admin)->send(new AdminSiteCreatedEmail($request->user(), $server, $site));
|
||||
}
|
||||
}
|
||||
|
||||
return redirect()->route('sites.index')->with('success', __('Your website is being created'));
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ class Kernel extends HttpKernel
|
||||
protected $middleware = [
|
||||
// \App\Http\Middleware\TrustHosts::class,
|
||||
\App\Http\Middleware\TrustProxies::class,
|
||||
\Fruitcake\Cors\HandleCors::class,
|
||||
\Illuminate\Http\Middleware\HandleCors::class,
|
||||
\App\Http\Middleware\PreventRequestsDuringMaintenance::class,
|
||||
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
|
||||
\App\Http\Middleware\TrimStrings::class,
|
||||
|
||||
@@ -68,7 +68,8 @@ class HandleInertiaRequests extends Middleware
|
||||
] : null,
|
||||
'package' => auth()->user() && auth()->user()->package ? [
|
||||
'name' => auth()->user()->package->name,
|
||||
'maximum_sites' => auth()->user()->package->maximum_sites
|
||||
'maximum_sites' => auth()->user()->package->maximum_sites,
|
||||
'trial' => auth()->user()->onTrial()
|
||||
] : [
|
||||
'name' => __('None')
|
||||
],
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class HasAccessToThisGroup
|
||||
{
|
||||
|
||||
@@ -2,15 +2,15 @@
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Illuminate\Http\Middleware\TrustProxies as Middleware;
|
||||
use Illuminate\Http\Request;
|
||||
use Fideloper\Proxy\TrustProxies as Middleware;
|
||||
|
||||
class TrustProxies extends Middleware
|
||||
{
|
||||
/**
|
||||
* The trusted proxies for this application.
|
||||
*
|
||||
* @var array|string|null
|
||||
* @var array<int, string>|string|null
|
||||
*/
|
||||
protected $proxies;
|
||||
|
||||
@@ -19,5 +19,10 @@ class TrustProxies extends Middleware
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $headers = Request::HEADER_X_FORWARDED_ALL;
|
||||
protected $headers =
|
||||
Request::HEADER_X_FORWARDED_FOR |
|
||||
Request::HEADER_X_FORWARDED_HOST |
|
||||
Request::HEADER_X_FORWARDED_PORT |
|
||||
Request::HEADER_X_FORWARDED_PROTO |
|
||||
Request::HEADER_X_FORWARDED_AWS_ELB;
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ class PackageRequest extends FormRequest
|
||||
Package::CURRENCY_GBP,
|
||||
Package::CURRENCY_INR,
|
||||
Package::CURRENCY_THB,
|
||||
Package::CURRENCY_BRL,
|
||||
])
|
||||
],
|
||||
'maximum_sites' => [
|
||||
|
||||
@@ -39,6 +39,10 @@ class SettingRequest extends FormRequest
|
||||
'nullable',
|
||||
'image',
|
||||
'max:2000'
|
||||
],
|
||||
|
||||
'trial_package' => [
|
||||
'required_with:trial'
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace App\Http\Requests;
|
||||
|
||||
use App\Models\Server;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class ServerRequest extends FormRequest
|
||||
{
|
||||
@@ -45,6 +46,11 @@ class ServerRequest extends FormRequest
|
||||
'required',
|
||||
'not_in:0',
|
||||
'exists:provider_plans,id'
|
||||
],
|
||||
'database_type' => [
|
||||
'required',
|
||||
'string',
|
||||
Rule::in(['mysql', 'mariadb', 'postgresql', 'postgresql13'])
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
25
app/Http/Requests/SiteAliasRequest.php
Normal file
25
app/Http/Requests/SiteAliasRequest.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use App\Rules\Hostname;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class SiteAliasRequest extends FormRequest
|
||||
{
|
||||
public function authorize()
|
||||
{
|
||||
return auth()->check();
|
||||
}
|
||||
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'domain' => [
|
||||
'required',
|
||||
'string',
|
||||
new Hostname,
|
||||
]
|
||||
];
|
||||
}
|
||||
}
|
||||
21
app/Http/Resources/Admin/ServerResource.php
Normal file
21
app/Http/Resources/Admin/ServerResource.php
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Resources\Admin;
|
||||
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class ServerResource extends JsonResource
|
||||
{
|
||||
public function toArray($request)
|
||||
{
|
||||
return [
|
||||
'id' => $this->id,
|
||||
'name' => $this->name,
|
||||
'ip' => $this->ip,
|
||||
'users' => $this->users,
|
||||
'sites_count' => $this->sites_count,
|
||||
'maximum_sites' => $this->maximum_sites,
|
||||
'created_at' => $this->created_at->format('Y-m-d H:i:s')
|
||||
];
|
||||
}
|
||||
}
|
||||
13
app/Http/Resources/Admin/SiteResource.php
Normal file
13
app/Http/Resources/Admin/SiteResource.php
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Resources\Admin;
|
||||
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class SiteResource extends JsonResource
|
||||
{
|
||||
public function toArray($request)
|
||||
{
|
||||
return parent::toArray($request);
|
||||
}
|
||||
}
|
||||
@@ -7,12 +7,6 @@ use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class SiteResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return array
|
||||
*/
|
||||
public function toArray($request)
|
||||
{
|
||||
/* @var $this \App\Models\Site */
|
||||
@@ -20,7 +14,11 @@ class SiteResource extends JsonResource
|
||||
'id' => $this->id,
|
||||
'status' => $this->parseStatus($this->status),
|
||||
'domain' => $this->domain,
|
||||
'php_version' => $this->php_version,
|
||||
'project' => $this->project,
|
||||
'server' => $this->server ? [
|
||||
'name' => $this->server->name
|
||||
] : null,
|
||||
'created_at' => $this->created_at
|
||||
];
|
||||
}
|
||||
|
||||
41
app/Jobs/Aliases/CreateAlias.php
Normal file
41
app/Jobs/Aliases/CreateAlias.php
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace App\Jobs\Aliases;
|
||||
|
||||
use App\Models\Site;
|
||||
use App\Traits\HasPloi;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldBeUnique;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class CreateAlias implements ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels, HasPloi;
|
||||
|
||||
public Site $site;
|
||||
public string $alias;
|
||||
|
||||
public function __construct(Site $site, $alias)
|
||||
{
|
||||
$this->site = $site;
|
||||
$this->alias = $alias;
|
||||
}
|
||||
|
||||
public function handle()
|
||||
{
|
||||
$this->getPloi()
|
||||
->server($this->site->server->ploi_id)
|
||||
->sites($this->site->ploi_id)
|
||||
->aliases()
|
||||
->create([$this->alias]);
|
||||
}
|
||||
|
||||
public function failed()
|
||||
{
|
||||
$this->site->aliases = array_diff($this->site->aliases, [$this->alias]);
|
||||
$this->site->save();
|
||||
}
|
||||
}
|
||||
35
app/Jobs/Aliases/DeleteAlias.php
Normal file
35
app/Jobs/Aliases/DeleteAlias.php
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace App\Jobs\Aliases;
|
||||
|
||||
use App\Models\Site;
|
||||
use App\Traits\HasPloi;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldBeUnique;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class DeleteAlias implements ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels, HasPloi;
|
||||
|
||||
public Site $site;
|
||||
public string $alias;
|
||||
|
||||
public function __construct(Site $site, $alias)
|
||||
{
|
||||
$this->site = $site;
|
||||
$this->alias = $alias;
|
||||
}
|
||||
|
||||
public function handle()
|
||||
{
|
||||
$this->getPloi()
|
||||
->server($this->site->server->ploi_id)
|
||||
->sites($this->site->ploi_id)
|
||||
->aliases()
|
||||
->delete($this->alias);
|
||||
}
|
||||
}
|
||||
@@ -2,14 +2,15 @@
|
||||
|
||||
namespace App\Jobs\Apps;
|
||||
|
||||
use App\Models\Database;
|
||||
use App\Models\Site;
|
||||
use App\Services\Ploi\Ploi;
|
||||
use App\Traits\HasPloi;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Support\Arr;
|
||||
|
||||
class InstallApp implements ShouldQueue
|
||||
{
|
||||
@@ -19,13 +20,6 @@ class InstallApp implements ShouldQueue
|
||||
public $type;
|
||||
public $options;
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*
|
||||
* @param Site $site
|
||||
* @param string $type
|
||||
* @param array $options
|
||||
*/
|
||||
public function __construct(Site $site, string $type = Site::PROJECT_WORDPRESS, array $options = [])
|
||||
{
|
||||
$this->site = $site;
|
||||
@@ -33,17 +27,21 @@ class InstallApp implements ShouldQueue
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$this->getPloi()
|
||||
$response = $this->getPloi()
|
||||
->server($this->site->server->ploi_id)
|
||||
->sites($this->site->ploi_id)
|
||||
->app()
|
||||
->install($this->type, $this->options);
|
||||
|
||||
if (Arr::get($this->options, 'create_database', false)) {
|
||||
$database = $this->site->databases()->create([
|
||||
'name' => $response->database_name,
|
||||
]);
|
||||
|
||||
$database->status = Database::STATUS_ACTIVE;
|
||||
$database->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
namespace App\Jobs\Apps;
|
||||
|
||||
use App\Models\Site;
|
||||
use App\Services\Ploi\Ploi;
|
||||
use App\Traits\HasPloi;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
@@ -2,9 +2,8 @@
|
||||
|
||||
namespace App\Jobs\Certificates;
|
||||
|
||||
use App\Models\Certificate;
|
||||
use App\Services\Ploi\Ploi;
|
||||
use App\Traits\HasPloi;
|
||||
use App\Models\Certificate;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
namespace App\Jobs\Certificates;
|
||||
|
||||
use App\Services\Ploi\Ploi;
|
||||
use App\Traits\HasPloi;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
@@ -2,9 +2,8 @@
|
||||
|
||||
namespace App\Jobs\Certificates;
|
||||
|
||||
use App\Models\Certificate;
|
||||
use App\Services\Ploi\Ploi;
|
||||
use App\Traits\HasPloi;
|
||||
use App\Models\Certificate;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use App\Traits\JobHasThresholds;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
namespace App\Jobs\Cronjobs;
|
||||
|
||||
use App\Models\Cronjob;
|
||||
use App\Services\Ploi\Ploi;
|
||||
use App\Traits\HasPloi;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
namespace App\Jobs\Cronjobs;
|
||||
|
||||
use App\Services\Ploi\Ploi;
|
||||
use App\Traits\HasPloi;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
namespace App\Jobs\Cronjobs;
|
||||
|
||||
use App\Models\Cronjob;
|
||||
use App\Services\Ploi\Ploi;
|
||||
use App\Traits\HasPloi;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use App\Traits\JobHasThresholds;
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
namespace App\Jobs\Databases;
|
||||
|
||||
use App\Services\Ploi\Ploi;
|
||||
use App\Traits\HasPloi;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
@@ -17,21 +17,11 @@ class CreateServer implements ShouldQueue
|
||||
public $server;
|
||||
public $tries = 1;
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*
|
||||
* @param Server $server
|
||||
*/
|
||||
public function __construct(Server $server)
|
||||
{
|
||||
$this->server = $server;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$ploiServer = $this->getPloi()->server()->create(
|
||||
@@ -39,12 +29,14 @@ class CreateServer implements ShouldQueue
|
||||
$this->server->provider->ploi_id,
|
||||
$this->server->providerRegion->region_id,
|
||||
$this->server->providerPlan->plan_id,
|
||||
'server',
|
||||
$this->server->database_type
|
||||
);
|
||||
|
||||
$this->server->ploi_id = $ploiServer->id;
|
||||
$this->server->save();
|
||||
|
||||
// Lets fetch the status after 5 minutes
|
||||
// Let's fetch the status after 5 minutes
|
||||
dispatch(new FetchServerStatus($this->server))->delay(now()->addMinutes(5));
|
||||
}
|
||||
|
||||
|
||||
@@ -13,26 +13,15 @@ class AdminServerCreatedEmail extends Mailable implements ShouldQueue
|
||||
{
|
||||
use Queueable, SerializesModels;
|
||||
|
||||
public $user;
|
||||
public $server;
|
||||
public User $user;
|
||||
public Server $server;
|
||||
|
||||
/**
|
||||
* Create a new message instance.
|
||||
*
|
||||
* @param User $user
|
||||
* @param Server $server
|
||||
*/
|
||||
public function __construct(User $user, Server $server)
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->server = $server;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the message.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function build()
|
||||
{
|
||||
return $this
|
||||
|
||||
34
app/Mail/Admin/Site/AdminSiteCreatedEmail.php
Normal file
34
app/Mail/Admin/Site/AdminSiteCreatedEmail.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace App\Mail\Admin\Site;
|
||||
|
||||
use App\Models\Server;
|
||||
use App\Models\Site;
|
||||
use App\Models\User;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class AdminSiteCreatedEmail extends Mailable implements ShouldQueue
|
||||
{
|
||||
use Queueable, SerializesModels;
|
||||
|
||||
public User $user;
|
||||
public Server $server;
|
||||
public Site $site;
|
||||
|
||||
public function __construct(User $user, Server $server, Site $site)
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->server = $server;
|
||||
$this->site = $site;
|
||||
}
|
||||
|
||||
public function build()
|
||||
{
|
||||
return $this
|
||||
->subject(__('A user has created a new site'))
|
||||
->markdown('emails.admin.site.new-site');
|
||||
}
|
||||
}
|
||||
@@ -21,5 +21,7 @@ class Certificate extends Model
|
||||
'type',
|
||||
'certificate',
|
||||
'private',
|
||||
'ploi_id',
|
||||
'status'
|
||||
];
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ class Package extends Model
|
||||
const CURRENCY_GBP = 'gbp';
|
||||
const CURRENCY_INR = 'inr';
|
||||
const CURRENCY_THB = 'thb';
|
||||
const CURRENCY_BRL = 'brl';
|
||||
|
||||
public $fillable = [
|
||||
'name',
|
||||
|
||||
@@ -17,7 +17,8 @@ class Server extends Model
|
||||
'internal_ip',
|
||||
'ssh_port',
|
||||
'maximum_sites',
|
||||
'available_php_versions'
|
||||
'available_php_versions',
|
||||
'database_type'
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Casts\SiteAlias;
|
||||
use DateTimeInterface;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
@@ -18,8 +19,15 @@ class Site extends Model
|
||||
const PROJECT_OCTOBERCMS = 'october-cms';
|
||||
|
||||
public $fillable = [
|
||||
'ploi_id',
|
||||
'domain',
|
||||
'dns_id'
|
||||
'dns_id',
|
||||
'project',
|
||||
'aliases'
|
||||
];
|
||||
|
||||
public $casts = [
|
||||
'aliases' => SiteAlias::class,
|
||||
];
|
||||
|
||||
public function setDnsIdAttribute($value)
|
||||
@@ -96,6 +104,22 @@ class Site extends Model
|
||||
] + ($withPassword ? ['ftp_password' => $user->ftp_password] : []);
|
||||
}
|
||||
|
||||
public function addAlias($alias)
|
||||
{
|
||||
$aliases = $this->aliases;
|
||||
|
||||
$aliases[] = $alias;
|
||||
|
||||
$this->aliases = $aliases;
|
||||
$this->save();
|
||||
}
|
||||
|
||||
public function removeAlias($alias)
|
||||
{
|
||||
$this->aliases = array_diff($this->aliases, [$alias]);
|
||||
$this->save();
|
||||
}
|
||||
|
||||
public static function booted()
|
||||
{
|
||||
static::creating(function (self $site) {
|
||||
|
||||
@@ -47,7 +47,8 @@ class User extends Authenticatable implements HasLocalePreference
|
||||
'email_verified_at' => 'datetime',
|
||||
'ftp_password' => Encrypted::class,
|
||||
'keyboard_shortcuts' => 'boolean',
|
||||
'requires_password_for_ftp' => 'boolean'
|
||||
'requires_password_for_ftp' => 'boolean',
|
||||
'trial_ends_at' => 'datetime',
|
||||
];
|
||||
|
||||
protected $appends = [
|
||||
@@ -134,6 +135,10 @@ class User extends Authenticatable implements HasLocalePreference
|
||||
if (!$user->language) {
|
||||
$user->language = setting('default_language', 'en');
|
||||
}
|
||||
|
||||
if($days = setting('trial')){
|
||||
$user->trial_ends_at = now()->addDays($days);
|
||||
}
|
||||
});
|
||||
|
||||
static::created(function (self $user) {
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace App\Providers;
|
||||
|
||||
use App\Models\Setting;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Illuminate\Validation\Rules\Password;
|
||||
|
||||
class AppServiceProvider extends ServiceProvider
|
||||
{
|
||||
@@ -19,4 +20,15 @@ class AppServiceProvider extends ServiceProvider
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public function boot()
|
||||
{
|
||||
Password::defaults(function () {
|
||||
$rule = Password::min(6);
|
||||
|
||||
return $this->app->isProduction()
|
||||
? $rule->letters()->numbers()->uncompromised()
|
||||
: $rule;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
44
app/Services/Ploi/Resources/Alias.php
Normal file
44
app/Services/Ploi/Resources/Alias.php
Normal file
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Ploi\Resources;
|
||||
|
||||
class Alias extends Resource
|
||||
{
|
||||
public function __construct(Server $server, Site $site)
|
||||
{
|
||||
parent::__construct($server->getPloi());
|
||||
|
||||
$this->setServer($server);
|
||||
$this->setSite($site);
|
||||
|
||||
$this->buildEndpoint();
|
||||
}
|
||||
|
||||
public function buildEndpoint(): self
|
||||
{
|
||||
$this->setEndpoint($this->getSite()->getEndpoint() . '/aliases');
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function get()
|
||||
{
|
||||
return $this->getPloi()->makeAPICall($this->getEndpoint());
|
||||
}
|
||||
|
||||
public function create(array $aliases)
|
||||
{
|
||||
$options = [
|
||||
'body' => json_encode([
|
||||
'aliases' => $aliases,
|
||||
]),
|
||||
];
|
||||
|
||||
return $this->getPloi()->makeAPICall($this->getEndpoint(), 'post', $options);
|
||||
}
|
||||
|
||||
public function delete(string $alias)
|
||||
{
|
||||
return $this->getPloi()->makeAPICall($this->getEndpoint() . '/' . $alias , 'delete');
|
||||
}
|
||||
}
|
||||
@@ -66,7 +66,7 @@ class App extends Resource
|
||||
$this->setId($response->getJson()->data->id);
|
||||
|
||||
// Return the data
|
||||
return $response->getJson()->data;
|
||||
return $response->getJson();
|
||||
}
|
||||
|
||||
public function uninstall($type): bool
|
||||
|
||||
@@ -63,7 +63,11 @@ class Server extends Resource
|
||||
string $name,
|
||||
$provider,
|
||||
$region,
|
||||
$plan
|
||||
$plan,
|
||||
$type = 'server',
|
||||
$databaseType = 'mysql',
|
||||
$webserverType = 'nginx',
|
||||
$phpVersion = '7.4'
|
||||
): stdClass {
|
||||
|
||||
// Remove the id
|
||||
@@ -76,10 +80,10 @@ class Server extends Resource
|
||||
'plan' => $plan,
|
||||
'region' => $region,
|
||||
'credential' => $provider,
|
||||
'type' => 'server',
|
||||
'database_type' => 'mysql',
|
||||
'webserver_type' => 'nginx',
|
||||
'php_version' => '7.4'
|
||||
'type' => $type,
|
||||
'database_type' => $databaseType,
|
||||
'webserver_type' => $webserverType,
|
||||
'php_version' => $phpVersion
|
||||
]),
|
||||
];
|
||||
|
||||
|
||||
@@ -204,4 +204,9 @@ class Site extends Resource
|
||||
{
|
||||
return new App($this->getServer(), $this, $id);
|
||||
}
|
||||
|
||||
public function aliases($id = null): Alias
|
||||
{
|
||||
return new Alias($this->getServer(), $this, $id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,31 +9,34 @@
|
||||
],
|
||||
"license": "MIT",
|
||||
"require": {
|
||||
"php": "^7.4|^8.0",
|
||||
"php": "^8.0.2",
|
||||
"ext-json": "*",
|
||||
"cloudflare/sdk": "^1.1",
|
||||
"fideloper/proxy": "^4.2",
|
||||
"fruitcake/laravel-cors": "^1.0",
|
||||
"guzzlehttp/guzzle": "^6.2|^7.0.1",
|
||||
"inertiajs/inertia-laravel": "^v0.4.3",
|
||||
"laravel/cashier": "^12.3",
|
||||
"laravel/framework": "^8.4",
|
||||
"laravel/horizon": "^5.0",
|
||||
"aws/aws-sdk-php": "^3.224",
|
||||
"cloudflare/sdk": "^1.3",
|
||||
"guzzlehttp/guzzle": "^7.4.1",
|
||||
"inertiajs/inertia-laravel": "^0.5.4",
|
||||
"laravel/cashier": "^12.16",
|
||||
"laravel/framework": "^9.0.2",
|
||||
"laravel/horizon": "^5.8",
|
||||
"laravel/octane": "^1.2",
|
||||
"laravel/tinker": "^2.0",
|
||||
"laravel/ui": "^2.1|^3.3.0",
|
||||
"league/glide": "^1.6",
|
||||
"pragmarx/google2fa-laravel": "^1.3",
|
||||
"predis/predis": "^1.1",
|
||||
"spiral/roadrunner": "^2.8.2",
|
||||
"symfony/http-client": "^6.1",
|
||||
"symfony/mailgun-mailer": "^6.1",
|
||||
"symfony/postmark-mailer": "^6.1",
|
||||
"tightenco/ziggy": "^1.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"barryvdh/laravel-debugbar": "^3.3",
|
||||
"facade/ignition": "^2.3",
|
||||
"friendsofphp/php-cs-fixer": "^2.16",
|
||||
"spatie/laravel-ignition": "^1.0",
|
||||
"friendsofphp/php-cs-fixer": "^3.1.0",
|
||||
"fzaninotto/faker": "^1.9.1",
|
||||
"laravel/dusk": "^6.15",
|
||||
"mockery/mockery": "^1.3.1",
|
||||
"nunomaduro/collision": "^5.0",
|
||||
"nunomaduro/collision": "^6.1",
|
||||
"phpunit/phpunit": "^9.5.4"
|
||||
},
|
||||
"config": {
|
||||
|
||||
4903
composer.lock
generated
4903
composer.lock
generated
File diff suppressed because it is too large
Load Diff
7
config/core.php
Normal file
7
config/core.php
Normal file
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'pagination' => [
|
||||
'per_page' => env('PAGINATION_PER_PAGE', 5)
|
||||
]
|
||||
];
|
||||
221
config/octane.php
Normal file
221
config/octane.php
Normal file
@@ -0,0 +1,221 @@
|
||||
<?php
|
||||
|
||||
use Laravel\Octane\Contracts\OperationTerminated;
|
||||
use Laravel\Octane\Events\RequestHandled;
|
||||
use Laravel\Octane\Events\RequestReceived;
|
||||
use Laravel\Octane\Events\RequestTerminated;
|
||||
use Laravel\Octane\Events\TaskReceived;
|
||||
use Laravel\Octane\Events\TaskTerminated;
|
||||
use Laravel\Octane\Events\TickReceived;
|
||||
use Laravel\Octane\Events\TickTerminated;
|
||||
use Laravel\Octane\Events\WorkerErrorOccurred;
|
||||
use Laravel\Octane\Events\WorkerStarting;
|
||||
use Laravel\Octane\Events\WorkerStopping;
|
||||
use Laravel\Octane\Listeners\CollectGarbage;
|
||||
use Laravel\Octane\Listeners\DisconnectFromDatabases;
|
||||
use Laravel\Octane\Listeners\EnsureUploadedFilesAreValid;
|
||||
use Laravel\Octane\Listeners\EnsureUploadedFilesCanBeMoved;
|
||||
use Laravel\Octane\Listeners\FlushTemporaryContainerInstances;
|
||||
use Laravel\Octane\Listeners\FlushUploadedFiles;
|
||||
use Laravel\Octane\Listeners\ReportException;
|
||||
use Laravel\Octane\Listeners\StopWorkerIfNecessary;
|
||||
use Laravel\Octane\Octane;
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Octane Server
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This value determines the default "server" that will be used by Octane
|
||||
| when starting, restarting, or stopping your server via the CLI. You
|
||||
| are free to change this to the supported server of your choosing.
|
||||
|
|
||||
| Supported: "roadrunner", "swoole"
|
||||
|
|
||||
*/
|
||||
|
||||
'server' => env('OCTANE_SERVER', 'roadrunner'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Force HTTPS
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| When this configuration value is set to "true", Octane will inform the
|
||||
| framework that all absolute links must be generated using the HTTPS
|
||||
| protocol. Otherwise your links may be generated using plain HTTP.
|
||||
|
|
||||
*/
|
||||
|
||||
'https' => env('OCTANE_HTTPS', false),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Octane Listeners
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| All of the event listeners for Octane's events are defined below. These
|
||||
| listeners are responsible for resetting your application's state for
|
||||
| the next request. You may even add your own listeners to the list.
|
||||
|
|
||||
*/
|
||||
|
||||
'listeners' => [
|
||||
WorkerStarting::class => [
|
||||
EnsureUploadedFilesAreValid::class,
|
||||
EnsureUploadedFilesCanBeMoved::class,
|
||||
],
|
||||
|
||||
RequestReceived::class => [
|
||||
...Octane::prepareApplicationForNextOperation(),
|
||||
...Octane::prepareApplicationForNextRequest(),
|
||||
//
|
||||
],
|
||||
|
||||
RequestHandled::class => [
|
||||
//
|
||||
],
|
||||
|
||||
RequestTerminated::class => [
|
||||
// FlushUploadedFiles::class,
|
||||
],
|
||||
|
||||
TaskReceived::class => [
|
||||
...Octane::prepareApplicationForNextOperation(),
|
||||
//
|
||||
],
|
||||
|
||||
TaskTerminated::class => [
|
||||
//
|
||||
],
|
||||
|
||||
TickReceived::class => [
|
||||
...Octane::prepareApplicationForNextOperation(),
|
||||
//
|
||||
],
|
||||
|
||||
TickTerminated::class => [
|
||||
//
|
||||
],
|
||||
|
||||
OperationTerminated::class => [
|
||||
FlushTemporaryContainerInstances::class,
|
||||
// DisconnectFromDatabases::class,
|
||||
// CollectGarbage::class,
|
||||
],
|
||||
|
||||
WorkerErrorOccurred::class => [
|
||||
ReportException::class,
|
||||
StopWorkerIfNecessary::class,
|
||||
],
|
||||
|
||||
WorkerStopping::class => [
|
||||
//
|
||||
],
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Warm / Flush Bindings
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The bindings listed below will either be pre-warmed when a worker boots
|
||||
| or they will be flushed before every new request. Flushing a binding
|
||||
| will force the container to resolve that binding again when asked.
|
||||
|
|
||||
*/
|
||||
|
||||
'warm' => [
|
||||
...Octane::defaultServicesToWarm(),
|
||||
],
|
||||
|
||||
'flush' => [
|
||||
//
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Octane Cache Table
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| While using Swoole, you may leverage the Octane cache, which is powered
|
||||
| by a Swoole table. You may set the maximum number of rows as well as
|
||||
| the number of bytes per row using the configuration options below.
|
||||
|
|
||||
*/
|
||||
|
||||
'cache' => [
|
||||
'rows' => 1000,
|
||||
'bytes' => 10000,
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Octane Swoole Tables
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| While using Swoole, you may define additional tables as required by the
|
||||
| application. These tables can be used to store data that needs to be
|
||||
| quickly accessed by other workers on the particular Swoole server.
|
||||
|
|
||||
*/
|
||||
|
||||
'tables' => [
|
||||
'example:1000' => [
|
||||
'name' => 'string:1000',
|
||||
'votes' => 'int',
|
||||
],
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| File Watching
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The following list of files and directories will be watched when using
|
||||
| the --watch option offered by Octane. If any of the directories and
|
||||
| files are changed, Octane will automatically reload your workers.
|
||||
|
|
||||
*/
|
||||
|
||||
'watch' => [
|
||||
'app',
|
||||
'bootstrap',
|
||||
'config',
|
||||
'database',
|
||||
'public/**/*.php',
|
||||
'resources/**/*.php',
|
||||
'routes',
|
||||
'composer.lock',
|
||||
'.env',
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Garbage Collection Threshold
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| When executing long-lived PHP scripts such as Octane, memory can build
|
||||
| up before being cleared by PHP. You can force Octane to run garbage
|
||||
| collection if your application consumes this amount of megabytes.
|
||||
|
|
||||
*/
|
||||
|
||||
'garbage' => 50,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Maximum Execution Time
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The following setting configures the maximum execution time for requests
|
||||
| being handled by Octane. You may set this value to 0 to indicate that
|
||||
| there isn't a specific time limit on Octane request execution time.
|
||||
|
|
||||
*/
|
||||
|
||||
'max_execution_time' => 30,
|
||||
|
||||
];
|
||||
@@ -15,6 +15,7 @@ return [
|
||||
|
||||
'paths' => [
|
||||
resource_path('views'),
|
||||
storage_path('views'),
|
||||
],
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class AddAllowedRegionsAndPlansToProvidersTable extends Migration
|
||||
{
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AddColumnsToServersTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('servers', function (Blueprint $table) {
|
||||
$table->after('available_php_versions', function (Blueprint $table) {
|
||||
$table->string('type')->default('server');
|
||||
$table->string('database_type')->default('mysql');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('servers', function (Blueprint $table) {
|
||||
$table->dropColumn('type', 'database_type');
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration {
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('sites', function (Blueprint $table) {
|
||||
$table->json('aliases')->nullable()->after('php_version');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('sites', function (Blueprint $table) {
|
||||
$table->dropColumn('aliases');
|
||||
});
|
||||
}
|
||||
};
|
||||
6495
package-lock.json
generated
6495
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
14
package.json
14
package.json
@@ -13,24 +13,24 @@
|
||||
"@inertiajs/inertia": "^0.10.0",
|
||||
"@inertiajs/inertia-vue": "^0.7.1",
|
||||
"@inertiajs/progress": "^0.2.6",
|
||||
"@tailwindcss/forms": "^0.3.2",
|
||||
"@tailwindcss/typography": "^0.4.1",
|
||||
"autoprefixer": "^10.2.5",
|
||||
"@tailwindcss/forms": "^0.4.0",
|
||||
"@tailwindcss/typography": "^0.5.0",
|
||||
"autoprefixer": "^10.4.0",
|
||||
"axios": "^0.21.1",
|
||||
"balloon-css": "^1.2.0",
|
||||
"cross-env": "^7.0.3",
|
||||
"laravel-mix": "^6.0.25",
|
||||
"laravel-mix": "^6.0.41",
|
||||
"lodash": "^4.17.15",
|
||||
"portal-vue": "^2.1.7",
|
||||
"postcss": "^8.2.13",
|
||||
"postcss": "^8.4.5",
|
||||
"resolve-url-loader": "^3.1.0",
|
||||
"sass": "^1.15.2",
|
||||
"sass-loader": "^8.0.0",
|
||||
"tailwindcss": "^2.2.4",
|
||||
"tailwindcss": "^3.0.7",
|
||||
"v-click-outside": "^3.1.2",
|
||||
"vue": "^2.6.11",
|
||||
"vue-clipboard2": "^0.3.1",
|
||||
"vue-loader": "^15.9.6",
|
||||
"vue-loader": "^15.9.8",
|
||||
"vue-meta": "^2.4.0",
|
||||
"vue-template-compiler": "^2.6.11",
|
||||
"vuex": "^3.6.2"
|
||||
|
||||
6
public/css/app.css
vendored
6
public/css/app.css
vendored
File diff suppressed because one or more lines are too long
1
public/js/1035.js
vendored
Normal file
1
public/js/1035.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
public/js/1042.js
vendored
Normal file
1
public/js/1042.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
public/js/1081.js
vendored
Normal file
1
public/js/1081.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
public/js/1304.js
vendored
Normal file
1
public/js/1304.js
vendored
Normal file
File diff suppressed because one or more lines are too long
2
public/js/1331.js
vendored
2
public/js/1331.js
vendored
File diff suppressed because one or more lines are too long
1
public/js/1438.js
vendored
Normal file
1
public/js/1438.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
public/js/1439.js
vendored
Normal file
1
public/js/1439.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
public/js/1532.js
vendored
Normal file
1
public/js/1532.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
public/js/1533.js
vendored
Normal file
1
public/js/1533.js
vendored
Normal file
File diff suppressed because one or more lines are too long
2
public/js/1535.js
vendored
2
public/js/1535.js
vendored
File diff suppressed because one or more lines are too long
1
public/js/1582.js
vendored
Normal file
1
public/js/1582.js
vendored
Normal file
File diff suppressed because one or more lines are too long
2
public/js/1603.js
vendored
2
public/js/1603.js
vendored
File diff suppressed because one or more lines are too long
1
public/js/1654.js
vendored
Normal file
1
public/js/1654.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
public/js/1670.js
vendored
Normal file
1
public/js/1670.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
public/js/1899.js
vendored
Normal file
1
public/js/1899.js
vendored
Normal file
@@ -0,0 +1 @@
|
||||
"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[1899],{1899:(t,e,n)=>{n.r(e),n.d(e,{default:()=>r});const i={data:function(){return{items:[{title:this.__("Categories"),to:this.route("admin.documentation.index"),active:this.route().current("admin.documentation.index")},{title:this.__("Create category"),to:this.route("admin.documentation.create"),active:this.route().current("admin.documentation.create")},{title:this.__("Articles"),to:this.route("admin.documentation.articles.index"),active:this.route().current("admin.documentation.articles.index")},{title:this.__("Create article"),to:this.route("admin.documentation.articles.create"),active:this.route().current("admin.documentation.articles.create")}]}}};const r=(0,n(1900).Z)(i,(function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("ul",{staticClass:"-ml-4 space-y-1"},t._l(t.items,(function(e){return n("li",[n("inertia-link",{staticClass:"flex items-center h-10 px-4 font-medium text-medium-emphasis",class:{"rounded shadow text-primary bg-surface-3":e.active},attrs:{href:e.to}},[t._v(t._s(e.title)+" "+t._s(e.route)+"\n ")])],1)})),0)}),[],!1,null,null,null).exports},1900:(t,e,n)=>{function i(t,e,n,i,r,o,s,a){var c,u="function"==typeof t?t.options:t;if(e&&(u.render=e,u.staticRenderFns=n,u._compiled=!0),i&&(u.functional=!0),o&&(u._scopeId="data-v-"+o),s?(c=function(t){(t=t||this.$vnode&&this.$vnode.ssrContext||this.parent&&this.parent.$vnode&&this.parent.$vnode.ssrContext)||"undefined"==typeof __VUE_SSR_CONTEXT__||(t=__VUE_SSR_CONTEXT__),r&&r.call(this,t),t&&t._registeredComponents&&t._registeredComponents.add(s)},u._ssrRegister=c):r&&(c=a?function(){r.call(this,(u.functional?this.parent:this).$root.$options.shadowRoot)}:r),c)if(u.functional){u._injectStyles=c;var d=u.render;u.render=function(t,e){return c.call(e),d(t,e)}}else{var l=u.beforeCreate;u.beforeCreate=l?[].concat(l,c):[c]}return{exports:t,options:u}}n.d(e,{Z:()=>i})}}]);
|
||||
1
public/js/1903.js
vendored
Normal file
1
public/js/1903.js
vendored
Normal file
File diff suppressed because one or more lines are too long
2
public/js/1971.js
vendored
2
public/js/1971.js
vendored
File diff suppressed because one or more lines are too long
1
public/js/1973.js
vendored
Normal file
1
public/js/1973.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
public/js/1986.js
vendored
Normal file
1
public/js/1986.js
vendored
Normal file
@@ -0,0 +1 @@
|
||||
"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[1986],{1986:(t,e,i)=>{i.r(e),i.d(e,{default:()=>n});const s={data:function(){return{items:[{title:this.__("Overview"),to:this.route("admin.dashboard"),active:this.route().current("admin.dashboard")},{title:this.__("Settings"),to:this.route("admin.settings"),active:this.route().current("admin.settings")},{title:this.__("System"),to:this.route("admin.system"),active:this.route().current("admin.system")},{title:this.__("Terms"),to:this.route("admin.settings.terms"),active:this.route().current("admin.settings.terms")},{title:this.__("Alert messages"),to:this.route("admin.alerts.index"),active:this.route().current("admin.alerts.*")},{title:this.__("Application logs"),to:this.route("admin.application-logs"),active:this.route().current("admin.application-logs")}]}}};const n=(0,i(1900).Z)(s,(function(){var t=this,e=t.$createElement,i=t._self._c||e;return i("ul",{staticClass:"-ml-4 space-y-1"},t._l(t.items,(function(e){return i("li",[i("inertia-link",{staticClass:"flex items-center h-10 px-4 font-medium text-medium-emphasis",class:{"rounded shadow text-primary bg-surface-3":e.active},attrs:{href:e.to}},[t._v(t._s(e.title)+" "+t._s(e.route))])],1)})),0)}),[],!1,null,null,null).exports},1900:(t,e,i)=>{function s(t,e,i,s,n,r,o,a){var c,u="function"==typeof t?t.options:t;if(e&&(u.render=e,u.staticRenderFns=i,u._compiled=!0),s&&(u.functional=!0),r&&(u._scopeId="data-v-"+r),o?(c=function(t){(t=t||this.$vnode&&this.$vnode.ssrContext||this.parent&&this.parent.$vnode&&this.parent.$vnode.ssrContext)||"undefined"==typeof __VUE_SSR_CONTEXT__||(t=__VUE_SSR_CONTEXT__),n&&n.call(this,t),t&&t._registeredComponents&&t._registeredComponents.add(o)},u._ssrRegister=c):n&&(c=a?function(){n.call(this,(u.functional?this.parent:this).$root.$options.shadowRoot)}:n),c)if(u.functional){u._injectStyles=c;var l=u.render;u.render=function(t,e){return c.call(e),l(t,e)}}else{var d=u.beforeCreate;u.beforeCreate=d?[].concat(d,c):[c]}return{exports:t,options:u}}i.d(e,{Z:()=>s})}}]);
|
||||
2
public/js/2035.js
vendored
2
public/js/2035.js
vendored
File diff suppressed because one or more lines are too long
2
public/js/2158.js
vendored
2
public/js/2158.js
vendored
File diff suppressed because one or more lines are too long
1
public/js/2232.js
vendored
Normal file
1
public/js/2232.js
vendored
Normal file
File diff suppressed because one or more lines are too long
2
public/js/2254.js
vendored
2
public/js/2254.js
vendored
File diff suppressed because one or more lines are too long
1
public/js/2306.js
vendored
Normal file
1
public/js/2306.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
public/js/2309.js
vendored
Normal file
1
public/js/2309.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
public/js/2316.js
vendored
Normal file
1
public/js/2316.js
vendored
Normal file
File diff suppressed because one or more lines are too long
2
public/js/2407.js
vendored
2
public/js/2407.js
vendored
File diff suppressed because one or more lines are too long
1
public/js/2426.js
vendored
Normal file
1
public/js/2426.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
public/js/2454.js
vendored
Normal file
1
public/js/2454.js
vendored
Normal file
File diff suppressed because one or more lines are too long
2
public/js/2502.js
vendored
2
public/js/2502.js
vendored
File diff suppressed because one or more lines are too long
1
public/js/2566.js
vendored
Normal file
1
public/js/2566.js
vendored
Normal file
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user