Compare commits
39 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2adc4bc7ca | ||
|
|
0a81d58051 | ||
|
|
cb84438778 | ||
|
|
b0a76d311c | ||
|
|
5604503d26 | ||
|
|
bf55092b3a | ||
|
|
8286e7f9af | ||
|
|
1255221550 | ||
|
|
f4062cd6e7 | ||
|
|
93377ae753 | ||
|
|
a43cd19efd | ||
|
|
e5eec000d3 | ||
|
|
e5c8a62b32 | ||
|
|
9ae1c145b6 | ||
|
|
eb8b75e4f9 | ||
|
|
7378b82adf | ||
|
|
6f3b588f3d | ||
|
|
a2154cf37c | ||
|
|
9dab5f8093 | ||
|
|
9c9469d2f6 | ||
|
|
94acc313b1 | ||
|
|
448398322f | ||
|
|
3a78339396 | ||
|
|
a925a70448 | ||
|
|
e283eacaa3 | ||
|
|
3df6b6baed | ||
|
|
b65526e040 | ||
|
|
673bbf73be | ||
|
|
094d22eaa8 | ||
|
|
0fdba5fdec | ||
|
|
cf0730be89 | ||
|
|
221e67fd12 | ||
|
|
f9074309d1 | ||
|
|
b2bdbb9e30 | ||
|
|
63d0cb9626 | ||
|
|
e3bb3ae4d1 | ||
|
|
31890005ac | ||
|
|
04a216dee1 | ||
|
|
5d403c1202 |
31
app/Console/Commands/Core/Css.php
Normal file
31
app/Console/Commands/Core/Css.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands\Core;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Filesystem\Filesystem;
|
||||
|
||||
class Css extends Command
|
||||
{
|
||||
protected $signature = 'core:css';
|
||||
|
||||
protected $description = 'Generates an theme.css file for you to customize';
|
||||
|
||||
public function handle()
|
||||
{
|
||||
if(file_exists(storage_path('app/public/theme.css')) && !$this->confirm('You seem to already have a theme.css published, are you sure you want to overwrite?')){
|
||||
$this->warn('Aborted publishing of theme.css.');
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
$this->info('Publishing theme.css file..');
|
||||
|
||||
(new Filesystem)->copy(
|
||||
__DIR__ . '/stubs/theme.css',
|
||||
storage_path('app/public/theme.css')
|
||||
);
|
||||
|
||||
$this->info('Done! You can edit the theme.css file inside storage/public/theme.css');
|
||||
}
|
||||
}
|
||||
31
app/Console/Commands/Core/CssBackup.php
Normal file
31
app/Console/Commands/Core/CssBackup.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands\Core;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Filesystem\Filesystem;
|
||||
|
||||
class CssBackup extends Command
|
||||
{
|
||||
protected $signature = 'core:css-backup';
|
||||
|
||||
protected $description = 'Creates a backup from your own created theme.css';
|
||||
|
||||
public function handle()
|
||||
{
|
||||
if(!file_exists(storage_path('app/public/theme.css'))){
|
||||
$this->warn('There is no custom theme.css, aborting backup.');
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
$this->info('Backing up theme.css file..');
|
||||
|
||||
(new Filesystem)->copy(
|
||||
storage_path('app/public/theme.css'),
|
||||
storage_path('app/public/theme-backup.css')
|
||||
);
|
||||
|
||||
$this->info('Done! You can find the CSS backup file here storage/public/theme-backup.css');
|
||||
}
|
||||
}
|
||||
78
app/Console/Commands/Core/stubs/theme.css
vendored
Normal file
78
app/Console/Commands/Core/stubs/theme.css
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
:root {
|
||||
--font-body: 'Inter', sans-serif;
|
||||
|
||||
--color-white: #fff;
|
||||
--color-gray-1: #f7f7f7;
|
||||
--color-gray-2: #e6e6e6;
|
||||
--color-gray-3: #cacaca;
|
||||
--color-gray-4: #888;
|
||||
--color-gray-5: #666;
|
||||
--color-gray-6: #2f2f2f;
|
||||
--color-gray-7: #1b1a1a;
|
||||
--color-gray-8: #101010;
|
||||
|
||||
--color-primary: #1b8ae8;
|
||||
--color-success: #17b35d;
|
||||
--color-warning: #f5a623;
|
||||
--color-danger: #c90c4c;
|
||||
|
||||
--color-text-high-emphasis: var(--color-gray-8);
|
||||
--color-text-medium-emphasis: var(--color-gray-5);
|
||||
--color-text-low-emphasis: var(--color-gray-3);
|
||||
|
||||
--color-text-on-primary: var(--color-white);
|
||||
--color-text-on-success: var(--color-gray-8);
|
||||
--color-text-on-warning: var(--color-white);
|
||||
--color-text-on-danger: var(--color-white);
|
||||
|
||||
--color-border-high-emphasis: var(--color-gray-4);
|
||||
--color-border-medium-emphasis: var(--color-gray-3);
|
||||
--color-border-low-emphasis: var(--color-gray-2);
|
||||
|
||||
--color-backdrop: rgba(0, 0, 0, 0.5);
|
||||
--color-overlay: rgba(255, 255, 255, 0.8);
|
||||
--color-surface-1: var(--color-white);
|
||||
--color-surface-2: var(--color-gray-1);
|
||||
--color-surface-3: var(--color-white);
|
||||
|
||||
--border-radius: 0.5rem;
|
||||
--border-radius-avatar: 4rem;
|
||||
--border-radius-circle: 100%;
|
||||
|
||||
--top-bar-container: 64rem;
|
||||
--top-bar-logo-height: 3.5rem;
|
||||
--top-bar-background-color: var(--color-surface-1);
|
||||
--top-bar-text-color: var(--color-text-medium-emphasis);
|
||||
|
||||
--tab-bar-background-color: var(--color-surface-2);
|
||||
--tab-bar-item-active-background-color: var(--color-surface-1);
|
||||
--tab-bar-item-text-color: var(--color-text-medium-emphasis);
|
||||
--tab-bar-item-active-text-color: var(--color-text-high-emphasis);
|
||||
|
||||
--breadcrumbs-text-color: var(--color-text-medium-emphasis);
|
||||
}
|
||||
|
||||
.theme--dark {
|
||||
--color-primary: #63a6f5;
|
||||
--color-success: #50e3c2;
|
||||
--color-warning: #f5a623;
|
||||
--color-danger: #d4667c;
|
||||
|
||||
--color-text-high-emphasis: var(--color-white);
|
||||
--color-text-medium-emphasis: var(--color-gray-3);
|
||||
--color-text-low-emphasis: var(--color-gray-5);
|
||||
|
||||
--color-text-on-primary: var(--color-gray-7);
|
||||
--color-text-on-success: var(--color-gray-7);
|
||||
--color-text-on-warning: var(--color-gray-7);
|
||||
--color-text-on-danger: var(--color-gray-7);
|
||||
|
||||
--color-border-high-emphasis: var(--color-gray-4);
|
||||
--color-border-medium-emphasis: var(--color-gray-5);
|
||||
--color-border-low-emphasis: var(--color-gray-6);
|
||||
|
||||
--color-surface-1: var(--color-gray-7);
|
||||
--color-surface-2: var(--color-gray-6);
|
||||
--color-surface-3: var(--color-gray-6);
|
||||
--color-overlay: rgba(0, 0, 0, 0.8);
|
||||
}
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace App\Console;
|
||||
|
||||
use App\Console\Commands\Core\Css;
|
||||
use App\Console\Commands\Core\CssBackup;
|
||||
use App\Jobs\Core\Ping;
|
||||
use App\Console\Commands\Core\Install;
|
||||
use App\Console\Commands\Core\Synchronize;
|
||||
@@ -11,6 +13,8 @@ use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
|
||||
class Kernel extends ConsoleKernel
|
||||
{
|
||||
protected $commands = [
|
||||
Css::class,
|
||||
CssBackup::class,
|
||||
Install::class,
|
||||
Synchronize::class,
|
||||
];
|
||||
|
||||
81
app/Http/Controllers/Admin/AlertController.php
Normal file
81
app/Http/Controllers/Admin/AlertController.php
Normal file
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Admin\AlertRequest;
|
||||
use App\Models\Alert;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class AlertController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
return inertia('Admin/Alerts/Index', [
|
||||
'alerts' => Alert::query()->latest()->paginate()
|
||||
]);
|
||||
}
|
||||
|
||||
public function create()
|
||||
{
|
||||
return inertia('Admin/Alerts/Create');
|
||||
}
|
||||
|
||||
public function store(AlertRequest $request)
|
||||
{
|
||||
Alert::create($request->all());
|
||||
|
||||
return redirect()->route('admin.alerts.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function show($id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function edit($id)
|
||||
{
|
||||
return inertia('Admin/Alerts/Edit', [
|
||||
'alert' => Alert::findOrFail($id)
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function update(AlertRequest $request, $id)
|
||||
{
|
||||
Alert::findOrFail($id)->update($request->all());
|
||||
|
||||
return redirect()->route('admin.alerts.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function destroy($id)
|
||||
{
|
||||
Alert::findOrFail($id)->delete();
|
||||
|
||||
return redirect()->route('admin.alerts.index');
|
||||
}
|
||||
}
|
||||
@@ -2,11 +2,10 @@
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Admin\DocumentationArticleRequest;
|
||||
use App\Models\DocumentationCategory;
|
||||
use App\Models\DocumentationItem;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\DocumentationCategory;
|
||||
use App\Http\Requests\Admin\DocumentationArticleRequest;
|
||||
|
||||
class DocumentationArticleController extends Controller
|
||||
{
|
||||
|
||||
@@ -3,9 +3,8 @@
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Admin\DocumentationCategoryRequest;
|
||||
use App\Models\DocumentationCategory;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Requests\Admin\DocumentationCategoryRequest;
|
||||
|
||||
class DocumentationController extends Controller
|
||||
{
|
||||
|
||||
@@ -25,4 +25,13 @@ class ProviderController extends Controller
|
||||
|
||||
return redirect()->route('admin.services.index')->with('success', __('Provider has been updated'));
|
||||
}
|
||||
|
||||
public function destroy($id)
|
||||
{
|
||||
$provider = Provider::findOrFail($id);
|
||||
|
||||
$provider->delete();
|
||||
|
||||
return redirect()->route('admin.services.index')->with('success', __('Provider has been deleted'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@ namespace App\Http\Controllers\Admin;
|
||||
use App\Models\Package;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Admin\SettingRequest;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class SettingController extends Controller
|
||||
{
|
||||
@@ -22,13 +24,15 @@ class SettingController extends Controller
|
||||
'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')
|
||||
];
|
||||
|
||||
$packages = Package::pluck('name', 'id');
|
||||
|
||||
return inertia('Admin/Settings', [
|
||||
'company_settings' => $settings,
|
||||
'packages' => $packages
|
||||
'packages' => $packages,
|
||||
'languages' => languages()
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -46,6 +50,7 @@ class SettingController extends Controller
|
||||
'isolate_per_site_per_user',
|
||||
'enable_api',
|
||||
'api_token',
|
||||
'default_language'
|
||||
]) as $key => $value) {
|
||||
if ($key === 'api_token') {
|
||||
$value = encrypt($value);
|
||||
@@ -54,6 +59,18 @@ class SettingController extends Controller
|
||||
setting([$key => $value]);
|
||||
}
|
||||
|
||||
if ($logo = $request->file('logo')) {
|
||||
// If we previously had a logo, rotate that
|
||||
if ($oldLogo = setting('logo')) {
|
||||
Storage::delete(str_replace('/storage/', '/public/', $oldLogo));
|
||||
}
|
||||
|
||||
$version = Str::random();
|
||||
|
||||
$request->file('logo')->storePubliclyAs('logo', 'logo-' . $version . '.' . $request->file('logo')->extension(), 'public');
|
||||
setting(['logo' => '/storage/logo/logo-' . $version . '.' . $request->file('logo')->extension()]);
|
||||
}
|
||||
|
||||
cache()->forget('core.settings');
|
||||
|
||||
return redirect()->route('admin.settings')->with('success', __('Settings have been updated'));
|
||||
|
||||
@@ -31,7 +31,8 @@ class UserController extends Controller
|
||||
return inertia('Admin/Users/Create', [
|
||||
'packages' => $packages,
|
||||
'languages' => languages(),
|
||||
'defaultPackage' => (string)setting('default_package')
|
||||
'defaultPackage' => (string)setting('default_package'),
|
||||
'defaultLanguage' => (string)setting('default_language', 'en'),
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,41 +5,83 @@ namespace App\Http\Controllers\Profile;
|
||||
use Carbon\Carbon;
|
||||
use App\Models\User;
|
||||
use App\Models\Package;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Stripe\Exception\InvalidRequestException;
|
||||
|
||||
class ProfileBillingController extends Controller
|
||||
{
|
||||
public function index()
|
||||
public function index(Request $request)
|
||||
{
|
||||
/* @var $user User */
|
||||
$user = auth()->user();
|
||||
|
||||
$sortByType = array_key_first($request->input('sortBy', []));
|
||||
|
||||
$packages = Package::query()
|
||||
->where(function ($query) {
|
||||
return $query
|
||||
->where('price_monthly', '>', 0)
|
||||
->whereNotNull('plan_id');
|
||||
})
|
||||
->when($request->input('sortBy.' . $sortByType), function ($query, $value) use ($sortByType) {
|
||||
if ($sortByType === 'price') {
|
||||
return $value === 'asc'
|
||||
? $query->orderBy('price_monthly', 'asc')
|
||||
: $query->orderBy('price_monthly', 'desc');
|
||||
}
|
||||
if ($sortByType === 'servers') {
|
||||
return $value === 'asc'
|
||||
? $query->orderBy('maximum_servers', 'asc')
|
||||
: $query->orderBy('maximum_servers', 'desc');
|
||||
}
|
||||
if ($sortByType === 'sites') {
|
||||
return $value === 'asc'
|
||||
? $query->orderBy('maximum_sites', 'asc')
|
||||
: $query->orderBy('maximum_sites', 'desc');
|
||||
}
|
||||
if ($sortByType === 'name') {
|
||||
return $value === 'asc'
|
||||
? $query->orderBy('name', 'asc')
|
||||
: $query->orderBy('name', 'desc');
|
||||
}
|
||||
|
||||
return $query;
|
||||
}, function ($query) {
|
||||
return $query->orderBy('price_monthly', 'asc');
|
||||
})
|
||||
->get()
|
||||
->transform(function (Package $package) {
|
||||
$symbol = $package->currency === Package::CURRENCY_EURO ? '€' : '$';
|
||||
$currencies = [
|
||||
Package::CURRENCY_EURO => '€',
|
||||
Package::CURRENCY_USD => '$',
|
||||
Package::CURRENCY_NOK => 'KR ',
|
||||
Package::CURRENCY_CAD => 'CAD $',
|
||||
Package::CURRENCY_AUD => 'AUD $',
|
||||
];
|
||||
|
||||
$package->price_monthly = $symbol . number_format($package->price_monthly, 2, ',', '.');
|
||||
$package->price_monthly = ($currencies[$package->currency] ?? '[Unknown currency]') . number_format($package->price_monthly, 2, ',', '.');
|
||||
|
||||
return $package;
|
||||
});
|
||||
|
||||
$intent = $user->createSetupIntent();
|
||||
|
||||
return inertia('Profile/Billing', [
|
||||
'packages' => $packages,
|
||||
'subscription' => $user->subscription('default'),
|
||||
'public_key' => config('cashier.key'),
|
||||
'data_client_secret' => $intent->client_secret,
|
||||
'data_client_secret' => function () use ($user) {
|
||||
$intent = $user->createSetupIntent();
|
||||
return $intent->client_secret;
|
||||
},
|
||||
'card' => [
|
||||
'last_four' => $user->card_last_four,
|
||||
'brand' => $user->card_brand
|
||||
],
|
||||
'filters' => [
|
||||
'sort' => [
|
||||
$sortByType => $request->input('sortBy.' . $sortByType, 'asc'),
|
||||
]
|
||||
]
|
||||
]);
|
||||
}
|
||||
@@ -84,16 +126,22 @@ class ProfileBillingController extends Controller
|
||||
}
|
||||
|
||||
// If the user is already subscribed to the default plan, we have to swap it. Otherwise create a new one.
|
||||
if ($user->subscribed('default')) {
|
||||
$user->subscription('default')->swap($planId);
|
||||
} else {
|
||||
if ($coupon = $request->input('coupon')) {
|
||||
$user->newSubscription('default', $planId)
|
||||
->withCoupon($coupon)
|
||||
->create($user->defaultPaymentMethod()->id);
|
||||
try {
|
||||
if ($user->subscribed('default')) {
|
||||
$user->subscription('default')->swap($planId);
|
||||
} else {
|
||||
$user->newSubscription('default', $planId)->create($user->defaultPaymentMethod()->id);
|
||||
if ($coupon = $request->input('coupon')) {
|
||||
$user->newSubscription('default', $planId)
|
||||
->withCoupon($coupon)
|
||||
->create($user->defaultPaymentMethod()->id);
|
||||
} else {
|
||||
$user->newSubscription('default', $planId)->create($user->defaultPaymentMethod()->id);
|
||||
}
|
||||
}
|
||||
} catch (InvalidRequestException $exception) {
|
||||
$error = $exception->getJsonBody();
|
||||
|
||||
return redirect()->route('profile.billing.index')->with('error', Arr::get($error, 'error.message'));
|
||||
}
|
||||
|
||||
$user->package_id = $plan->id;
|
||||
|
||||
@@ -4,7 +4,6 @@ namespace App\Http\Controllers\Profile;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use App\Http\Requests\UserProfileRequest;
|
||||
use App\Http\Resources\UserProfileResource;
|
||||
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Profile;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\ProfileIntegrationRequest;
|
||||
use App\Models\UserProvider;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ProfileIntegrationController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
$providers = auth()->user()->providers()->latest()->get()->map(function($provider){
|
||||
return [
|
||||
'id' => $provider->id,
|
||||
'type' => $provider->type,
|
||||
'created_at' => $provider->created_at->format('Y-m-d H:i:s')
|
||||
];
|
||||
});
|
||||
|
||||
return inertia('Profile/Integrations', [
|
||||
'providers' => $providers,
|
||||
]);
|
||||
}
|
||||
|
||||
public function store(ProfileIntegrationRequest $request)
|
||||
{
|
||||
$request->user()->providers()->updateOrCreate([
|
||||
'type' => UserProvider::TYPE_CLOUDFLARE
|
||||
],[
|
||||
'type' => UserProvider::TYPE_CLOUDFLARE,
|
||||
'token' => $request->input('meta.api_key'),
|
||||
'meta' => [
|
||||
'cloudflare_email' => encrypt($request->input('meta.cloudflare_email'))
|
||||
]
|
||||
]);
|
||||
|
||||
return redirect()->route('profile.integrations.index');
|
||||
}
|
||||
|
||||
public function destroy($providerId)
|
||||
{
|
||||
auth()->user()->providers()->findOrFail($providerId)->delete();
|
||||
|
||||
return redirect()->route('profile.integrations.index');
|
||||
}
|
||||
}
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Mail\Admin\Server\AdminServerCreatedEmail;
|
||||
use App\Models\Server;
|
||||
use App\Models\User;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Jobs\Servers\CreateServer;
|
||||
@@ -13,6 +11,7 @@ use Illuminate\Support\Facades\Mail;
|
||||
use App\Http\Resources\ServerResource;
|
||||
use App\Mail\Server\ServerCreatedEmail;
|
||||
use App\Http\Requests\ServerUpdateRequest;
|
||||
use App\Mail\Admin\Server\AdminServerCreatedEmail;
|
||||
|
||||
class ServerController extends Controller
|
||||
{
|
||||
@@ -54,7 +53,7 @@ class ServerController extends Controller
|
||||
if (setting('receive_email_on_server_creation')) {
|
||||
$admins = User::query()->where('role', User::ADMIN)->get();
|
||||
|
||||
foreach($admins as $admin){
|
||||
foreach ($admins as $admin) {
|
||||
Mail::to($admin)->send(new AdminServerCreatedEmail($request->user(), $server));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,12 +3,11 @@
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Server;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Jobs\Sites\CreateSite;
|
||||
use App\Jobs\Sites\DeleteSite;
|
||||
use App\Http\Requests\SiteRequest;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\Http\Resources\SiteResource;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
|
||||
|
||||
@@ -2,7 +2,12 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Http\Requests\SiteDnsRequest;
|
||||
use App\Models\Site;
|
||||
use App\Models\UserProvider;
|
||||
use App\Services\Cloudflare;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Arr;
|
||||
|
||||
class SiteDnsController extends Controller
|
||||
{
|
||||
@@ -16,9 +21,18 @@ class SiteDnsController extends Controller
|
||||
]);
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
public function store(SiteDnsRequest $request, $id)
|
||||
{
|
||||
//
|
||||
$site = auth()->user()->sites()->findOrFail($id);
|
||||
|
||||
$dns = $this->getDnsInstance($site);
|
||||
|
||||
$dns->addRecord(
|
||||
$request->input('name'),
|
||||
$request->input('address'),
|
||||
);
|
||||
|
||||
return redirect()->route('sites.dns.index', $id)->with('success', __('DNS record has been created'));
|
||||
}
|
||||
|
||||
public function update(Request $request, $id)
|
||||
@@ -28,10 +42,31 @@ class SiteDnsController extends Controller
|
||||
|
||||
public function records($id)
|
||||
{
|
||||
$site = auth()->user()->sites()->findOrFail($id);
|
||||
|
||||
$dns = $this->getDnsInstance($site);
|
||||
|
||||
return $dns->listRecords();
|
||||
}
|
||||
|
||||
public function destroy($id)
|
||||
public function destroy($id, $recordId)
|
||||
{
|
||||
//
|
||||
$site = auth()->user()->sites()->findOrFail($id);
|
||||
|
||||
$dns = $this->getDnsInstance($site);
|
||||
|
||||
$dns->deleteRecord($recordId);
|
||||
|
||||
return redirect()->route('sites.dns.index', $id)->with('success', __('DNS record has been removed'));
|
||||
}
|
||||
|
||||
private function getDnsInstance(Site $site)
|
||||
{
|
||||
$provider = auth()->user()->providers()->where('type', UserProvider::TYPE_CLOUDFLARE)->first();
|
||||
|
||||
$cloudflare = new Cloudflare(decrypt(Arr::get($provider->meta, 'cloudflare_email')), decrypt($provider->token));
|
||||
$cloudflare->zone(decrypt($site->dns_id));
|
||||
|
||||
return $cloudflare;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,11 +2,13 @@
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\Alert;
|
||||
use App\Models\UserProvider;
|
||||
use Inertia\Middleware;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
use Inertia\Middleware;
|
||||
|
||||
class HandleInertiaRequests extends Middleware
|
||||
{
|
||||
@@ -14,7 +16,7 @@ class HandleInertiaRequests extends Middleware
|
||||
* Determines the current asset version.
|
||||
*
|
||||
* @see https://inertiajs.com/asset-versioning
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return string|null
|
||||
*/
|
||||
public function version(Request $request)
|
||||
@@ -26,13 +28,13 @@ class HandleInertiaRequests extends Middleware
|
||||
* Defines the props that are shared by default.
|
||||
*
|
||||
* @see https://inertiajs.com/shared-data
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return array
|
||||
*/
|
||||
public function share(Request $request)
|
||||
{
|
||||
return array_merge(parent::share($request), [
|
||||
'auth' => function () use($request) {
|
||||
'auth' => function () use ($request) {
|
||||
$package = auth()->user()->package ?? [];
|
||||
|
||||
$can = $package ? [
|
||||
@@ -66,7 +68,10 @@ class HandleInertiaRequests extends Middleware
|
||||
] : [
|
||||
'name' => __('None')
|
||||
],
|
||||
'can' => $can
|
||||
'can' => $can,
|
||||
'integrations' => [
|
||||
'cloudflare' => (bool)auth()->user() ? auth()->user()->providers()->where('type', UserProvider::TYPE_CLOUDFLARE)->count() : false,
|
||||
]
|
||||
];
|
||||
},
|
||||
|
||||
@@ -98,6 +103,24 @@ class HandleInertiaRequests extends Middleware
|
||||
? count(Session::get('errors')->getBag('default')->getMessages())
|
||||
: 0;
|
||||
},
|
||||
'system_alert' => function () {
|
||||
$alert = Alert::query()
|
||||
->where(function ($query) {
|
||||
return $query
|
||||
->whereNull('expires_at')
|
||||
->orWhere('expires_at', '>', now());
|
||||
})
|
||||
->first(['message', 'expires_at', 'type']);
|
||||
|
||||
if (!$alert) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return [
|
||||
'message' => $alert->message,
|
||||
'type' => $alert->type
|
||||
];
|
||||
}
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
50
app/Http/Requests/Admin/AlertRequest.php
Normal file
50
app/Http/Requests/Admin/AlertRequest.php
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests\Admin;
|
||||
|
||||
use App\Models\Alert;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class AlertRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return auth()->check() && auth()->user()->isAdmin();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'message' => [
|
||||
'required',
|
||||
'string',
|
||||
'max:500'
|
||||
],
|
||||
'type' => [
|
||||
'required',
|
||||
'string',
|
||||
Rule::in([
|
||||
Alert::TYPE_INFO,
|
||||
Alert::TYPE_DANGER,
|
||||
Alert::TYPE_WARNING
|
||||
])
|
||||
],
|
||||
'expires_at' => [
|
||||
'nullable',
|
||||
'date',
|
||||
'date_format:Y-m-d H:i:s'
|
||||
]
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -33,6 +33,12 @@ class SettingRequest extends FormRequest
|
||||
'email' => [
|
||||
'nullable',
|
||||
'email'
|
||||
],
|
||||
|
||||
'logo' => [
|
||||
'nullable',
|
||||
'image',
|
||||
'max:2000'
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
63
app/Http/Requests/ProfileIntegrationRequest.php
Normal file
63
app/Http/Requests/ProfileIntegrationRequest.php
Normal file
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use App\Models\UserProvider;
|
||||
use App\Rules\CloudflareGeneralTest;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class ProfileIntegrationRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return auth()->check();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
$rules = [
|
||||
'provider' => [
|
||||
'required',
|
||||
'string',
|
||||
Rule::in([
|
||||
UserProvider::TYPE_CLOUDFLARE
|
||||
])
|
||||
]
|
||||
];
|
||||
|
||||
if ($this->input('provider') === UserProvider::TYPE_CLOUDFLARE) {
|
||||
$rules['meta.api_key'] = [
|
||||
'required',
|
||||
'string',
|
||||
new CloudflareGeneralTest($this->input('meta.cloudflare_email'))
|
||||
];
|
||||
|
||||
$rules['meta.cloudflare_email'] = [
|
||||
'required',
|
||||
'string',
|
||||
'email'
|
||||
];
|
||||
}
|
||||
|
||||
return $rules;
|
||||
}
|
||||
|
||||
public function messages()
|
||||
{
|
||||
return [
|
||||
'meta.api_key.required' => __('The API key field is required'),
|
||||
'meta.cloudflare_email.required' => __('The Cloudflare email field is required'),
|
||||
];
|
||||
}
|
||||
}
|
||||
37
app/Http/Requests/SiteDnsRequest.php
Normal file
37
app/Http/Requests/SiteDnsRequest.php
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class SiteDnsRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return auth()->check();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'name' => [
|
||||
'required',
|
||||
'string',
|
||||
],
|
||||
'address' => [
|
||||
'required',
|
||||
'ipv4'
|
||||
]
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace App\Jobs\Core;
|
||||
|
||||
use App\Services\Ploi\Ploi;
|
||||
use App\Services\VersionChecker;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
@@ -16,21 +17,27 @@ class Ping implements ShouldQueue
|
||||
|
||||
public function handle()
|
||||
{
|
||||
$version = new VersionChecker;
|
||||
|
||||
$response = Http::withHeaders([
|
||||
'Accept' => 'application/json',
|
||||
'Content-Type' => 'application/json',
|
||||
'X-Ploi-Core-Key' => config('services.ploi.core-token')
|
||||
])
|
||||
->withToken(config('services.ploi.token'))
|
||||
->get((new Ploi)->url . 'ping');
|
||||
->post((new Ploi)->url . 'ping', [
|
||||
'version' => $version->getApplicationVersion(),
|
||||
'php_version' => phpversion(),
|
||||
'panel_url' => config('app.url')
|
||||
]);
|
||||
|
||||
if (!$response->ok() || !$response->json()) {
|
||||
|
||||
// Something went wrong..
|
||||
|
||||
return;
|
||||
return 1;
|
||||
}
|
||||
|
||||
$response->json();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,12 +4,12 @@ namespace App\Jobs\Sites;
|
||||
|
||||
use App\Models\Site;
|
||||
use App\Services\Ploi\Ploi;
|
||||
use Illuminate\Support\Arr;
|
||||
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 CreateSite implements ShouldQueue
|
||||
{
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
|
||||
namespace App\Mail\Admin\Server;
|
||||
|
||||
use App\Models\Server;
|
||||
use App\Models\User;
|
||||
use App\Models\Server;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
|
||||
class AdminServerCreatedEmail extends Mailable implements ShouldQueue
|
||||
{
|
||||
|
||||
28
app/Models/Alert.php
Normal file
28
app/Models/Alert.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use DateTimeInterface;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Alert extends Model
|
||||
{
|
||||
const TYPE_INFO = 'info';
|
||||
const TYPE_WARNING = 'warning';
|
||||
const TYPE_DANGER = 'danger';
|
||||
|
||||
public $fillable = [
|
||||
'type',
|
||||
'message',
|
||||
'expires_at'
|
||||
];
|
||||
|
||||
public $dates = [
|
||||
'expires_at'
|
||||
];
|
||||
|
||||
protected function serializeDate(DateTimeInterface $date)
|
||||
{
|
||||
return $date->format('Y-m-d H:i:s');
|
||||
}
|
||||
}
|
||||
@@ -38,4 +38,20 @@ class Provider extends Model
|
||||
{
|
||||
return $this->hasMany(Server::class);
|
||||
}
|
||||
|
||||
public static function booted()
|
||||
{
|
||||
static::deleting(function(self $provider){
|
||||
$provider->regions()->delete();
|
||||
$provider->plans()->delete();
|
||||
$provider->packages()->detach();
|
||||
|
||||
foreach($provider->servers as $server){
|
||||
$server->provider_id = null;
|
||||
$server->provider_plan_id = null;
|
||||
$server->provider_region_id = null;
|
||||
$server->save();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,8 +89,8 @@ class Site extends Model
|
||||
}
|
||||
|
||||
return [
|
||||
'user_name' => $user->user_name,
|
||||
] + ($withPassword ? ['ftp_password' => $user->ftp_password] : []);
|
||||
'user_name' => $user->user_name,
|
||||
] + ($withPassword ? ['ftp_password' => $user->ftp_password] : []);
|
||||
}
|
||||
|
||||
public static function booted()
|
||||
@@ -103,6 +103,19 @@ class Site extends Model
|
||||
foreach ($site->databases as $database) {
|
||||
$database->delete();
|
||||
}
|
||||
|
||||
$ids = $site->systemUsers->pluck('id');
|
||||
// Detach all db users
|
||||
$site->systemUsers()->detach();
|
||||
|
||||
// Loop through ids an remove old users.
|
||||
foreach ($ids as $id) {
|
||||
$record = SiteSystemUser::find($id);
|
||||
if ($record) {
|
||||
$record->delete();
|
||||
}
|
||||
}
|
||||
|
||||
$site->redirects()->delete();
|
||||
$site->cronjobs()->delete();
|
||||
$site->certificates()->delete();
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
namespace App\Models;
|
||||
|
||||
use App\Casts\Encrypted;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class SiteSystemUser extends Model
|
||||
{
|
||||
@@ -32,7 +32,6 @@ class SiteSystemUser extends Model
|
||||
static::creating(function (self $siteSystemUser) {
|
||||
$siteSystemUser->user_name = strtolower(Str::random(10));
|
||||
$siteSystemUser->ftp_password = Str::random();
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,6 +124,10 @@ class User extends Authenticatable implements HasLocalePreference
|
||||
static::creating(function (self $user) {
|
||||
$user->user_name = strtolower(Str::random(10));
|
||||
$user->ftp_password = Str::random();
|
||||
|
||||
if (!$user->language) {
|
||||
$user->language = setting('default_language', 'en');
|
||||
}
|
||||
});
|
||||
|
||||
static::created(function (self $user) {
|
||||
|
||||
@@ -2,16 +2,29 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Casts\Encrypted;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class UserProvider extends Model
|
||||
{
|
||||
const TYPE_DNS = 'dns';
|
||||
const TYPE_CLOUDFLARE = 'cloudflare';
|
||||
|
||||
public $hidden = [
|
||||
'token'
|
||||
];
|
||||
|
||||
public $fillable = [
|
||||
'type',
|
||||
'token',
|
||||
'meta'
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'meta' => 'array',
|
||||
'token' => Encrypted::class,
|
||||
];
|
||||
|
||||
public function user()
|
||||
{
|
||||
return $this->belongsTo(User::class);
|
||||
|
||||
58
app/Rules/CloudflareGeneralTest.php
Normal file
58
app/Rules/CloudflareGeneralTest.php
Normal file
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
namespace App\Rules;
|
||||
|
||||
use App\Services\Cloudflare;
|
||||
use Illuminate\Contracts\Validation\Rule;
|
||||
|
||||
class CloudflareGeneralTest implements Rule
|
||||
{
|
||||
public $cloudflareEmail;
|
||||
|
||||
/**
|
||||
* Create a new rule instance.
|
||||
*
|
||||
* @param $cloudflareEmail
|
||||
*/
|
||||
public function __construct($cloudflareEmail)
|
||||
{
|
||||
$this->cloudflareEmail = $cloudflareEmail;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the validation rule passes.
|
||||
*
|
||||
* @param string $attribute
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function passes($attribute, $value)
|
||||
{
|
||||
if (!$this->cloudflareEmail) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
$cloudflare = new Cloudflare($this->cloudflareEmail, $value);
|
||||
|
||||
if ($cloudflare->user()) {
|
||||
return true;
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation error message.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function message()
|
||||
{
|
||||
return __('We could not authenticate you with Cloudflare, are you sure this is the right API key? Also make sure your profile e-mail matches the one in Cloudflare.');
|
||||
}
|
||||
}
|
||||
140
app/Services/Cloudflare.php
Normal file
140
app/Services/Cloudflare.php
Normal file
@@ -0,0 +1,140 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use GuzzleHttp\Exception\ClientException;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class Cloudflare
|
||||
{
|
||||
public $adapter;
|
||||
public $zoneId;
|
||||
|
||||
public function __construct($email, $key)
|
||||
{
|
||||
$key = new \Cloudflare\API\Auth\APIKey($email, $key);
|
||||
$this->adapter = new \Cloudflare\API\Adapter\Guzzle($key);
|
||||
}
|
||||
|
||||
public function domains($match = '')
|
||||
{
|
||||
$zones = new \Cloudflare\API\Endpoints\Zones($this->adapter);
|
||||
|
||||
return collect(object_get($zones->listZones($match), 'result'));
|
||||
}
|
||||
|
||||
public function zone($zoneId)
|
||||
{
|
||||
$this->zoneId = $zoneId;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function listRecords($page = 1, $perPage = 50, $order = '', $direction = '', $type = '', $name = '', $content = '', $match = 'all')
|
||||
{
|
||||
$dns = new \Cloudflare\API\Endpoints\DNS($this->adapter);
|
||||
|
||||
if (!$dns || !$this->zoneId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return collect($dns->listRecords($this->zoneId, $type, $name, $content, $page, $perPage, $order, $direction, $match)->result)
|
||||
->map(function ($record) {
|
||||
// We add this property so our UI panel can see whether a record is being edited.
|
||||
$record->edit = false;
|
||||
|
||||
$record->display_content = Str::limit($record->content, 25);
|
||||
|
||||
return $record;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param null $content
|
||||
* @param string $type
|
||||
* @param int $ttl
|
||||
* @param bool $proxied
|
||||
* @param int $priority
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function addRecord($name, $content = null, $type = 'A', $ttl = 0, $proxied = true, $priority = '0')
|
||||
{
|
||||
if ($content == null && $type = 'A') {
|
||||
$content = $_SERVER['SERVER_ADDR'];
|
||||
}
|
||||
|
||||
$dns = new \Cloudflare\API\Endpoints\DNS($this->adapter);
|
||||
|
||||
try {
|
||||
return $dns->addRecord($this->zoneId, $type, $name, $content, $ttl, $proxied, $priority);
|
||||
} catch (ClientException $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function getRecordByValues($name, $type)
|
||||
{
|
||||
$dns = new \Cloudflare\API\Endpoints\DNS($this->adapter);
|
||||
|
||||
try {
|
||||
return $dns->getRecordID($this->zoneId, $type, $name);
|
||||
} catch (ClientException $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function deleteRecord($id)
|
||||
{
|
||||
$dns = new \Cloudflare\API\Endpoints\DNS($this->adapter);
|
||||
|
||||
try {
|
||||
return $dns->deleteRecord($this->zoneId, $id);
|
||||
} catch (ClientException $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function updateRecord($id, array $data = [])
|
||||
{
|
||||
$dns = new \Cloudflare\API\Endpoints\DNS($this->adapter);
|
||||
|
||||
try {
|
||||
$record = $dns->getRecordDetails($this->zoneId, $id);
|
||||
|
||||
return $dns->updateRecordDetails($this->zoneId, $id, [
|
||||
'type' => object_get($record, 'type'),
|
||||
'name' => array_get($data, 'name'),
|
||||
'content' => array_get($data, 'content'),
|
||||
]);
|
||||
} catch (ClientException $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function toggleProxy($id)
|
||||
{
|
||||
$dns = new \Cloudflare\API\Endpoints\DNS($this->adapter);
|
||||
|
||||
try {
|
||||
$record = $dns->getRecordDetails($this->zoneId, $id);
|
||||
|
||||
return $dns->updateRecordDetails($this->zoneId, $id, [
|
||||
'type' => object_get($record, 'type'),
|
||||
'name' => object_get($record, 'name'),
|
||||
'content' => object_get($record, 'content'),
|
||||
'proxied' => !object_get($record, 'proxied')
|
||||
]);
|
||||
} catch (ClientException $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function user()
|
||||
{
|
||||
$user = new \Cloudflare\API\Endpoints\User($this->adapter);
|
||||
|
||||
return $user->getUserDetails();
|
||||
}
|
||||
}
|
||||
@@ -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 AddKeyboardShortcutsToUsersTable extends Migration
|
||||
{
|
||||
|
||||
@@ -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 CreateDocumentationCategoriesTable extends Migration
|
||||
{
|
||||
|
||||
@@ -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 CreateSiteSystemUsersTable extends Migration
|
||||
{
|
||||
|
||||
@@ -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 CreateSiteSystemUserAttached extends Migration
|
||||
{
|
||||
|
||||
@@ -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 AddRequiresPasswordForFtpToUsersTable extends Migration
|
||||
{
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateAlertsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('alerts', function (Blueprint $table) {
|
||||
$table->id();
|
||||
|
||||
$table->text('message')->nullable();
|
||||
$table->string('type')->nullable()->default(\App\Models\Alert::TYPE_INFO);
|
||||
|
||||
$table->timestamp('expires_at')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('alerts');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AddMetaToUserProvidersTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('user_providers', function (Blueprint $table) {
|
||||
$table->json('meta')->nullable()->after('token');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('user_providers', function (Blueprint $table) {
|
||||
$table->dropColumn('meta');
|
||||
});
|
||||
}
|
||||
}
|
||||
6
package-lock.json
generated
6
package-lock.json
generated
@@ -9031,9 +9031,9 @@
|
||||
}
|
||||
},
|
||||
"tailwindcss": {
|
||||
"version": "1.9.1",
|
||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-1.9.1.tgz",
|
||||
"integrity": "sha512-3faxlyPlcWN8AoNEIVQFNsDcrdXS/D9nOGtdknrXvZp4D4E3AGPO2KRPiGG69B2ZUO0V6RvYiW91L2/n9QnBxg==",
|
||||
"version": "1.9.6",
|
||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-1.9.6.tgz",
|
||||
"integrity": "sha512-nY8WYM/RLPqGsPEGEV2z63riyQPcHYZUJpAwdyBzVpxQHOHqHE+F/fvbCeXhdF1+TA5l72vSkZrtYCB9hRcwkQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@fullhuman/postcss-purgecss": "^2.1.2",
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
"resolve-url-loader": "^3.1.0",
|
||||
"sass": "^1.15.2",
|
||||
"sass-loader": "^8.0.0",
|
||||
"tailwindcss": "^1.9.0",
|
||||
"tailwindcss": "^1.9.6",
|
||||
"v-click-outside": "^3.0.1",
|
||||
"vue": "^2.6.11",
|
||||
"vue-clipboard2": "^0.3.1",
|
||||
|
||||
4
public/css/app.css
vendored
4
public/css/app.css
vendored
File diff suppressed because one or more lines are too long
2
public/js/0.js
vendored
2
public/js/0.js
vendored
File diff suppressed because one or more lines are too long
2
public/js/1.js
vendored
2
public/js/1.js
vendored
File diff suppressed because one or more lines are too long
2
public/js/10.js
vendored
2
public/js/10.js
vendored
File diff suppressed because one or more lines are too long
2
public/js/11.js
vendored
2
public/js/11.js
vendored
File diff suppressed because one or more lines are too long
2
public/js/12.js
vendored
2
public/js/12.js
vendored
File diff suppressed because one or more lines are too long
2
public/js/13.js
vendored
2
public/js/13.js
vendored
File diff suppressed because one or more lines are too long
2
public/js/14.js
vendored
2
public/js/14.js
vendored
File diff suppressed because one or more lines are too long
2
public/js/15.js
vendored
2
public/js/15.js
vendored
File diff suppressed because one or more lines are too long
2
public/js/16.js
vendored
2
public/js/16.js
vendored
File diff suppressed because one or more lines are too long
2
public/js/17.js
vendored
2
public/js/17.js
vendored
File diff suppressed because one or more lines are too long
2
public/js/18.js
vendored
2
public/js/18.js
vendored
File diff suppressed because one or more lines are too long
2
public/js/19.js
vendored
2
public/js/19.js
vendored
File diff suppressed because one or more lines are too long
2
public/js/2.js
vendored
2
public/js/2.js
vendored
File diff suppressed because one or more lines are too long
2
public/js/20.js
vendored
2
public/js/20.js
vendored
File diff suppressed because one or more lines are too long
2
public/js/21.js
vendored
2
public/js/21.js
vendored
File diff suppressed because one or more lines are too long
2
public/js/22.js
vendored
2
public/js/22.js
vendored
File diff suppressed because one or more lines are too long
2
public/js/23.js
vendored
2
public/js/23.js
vendored
File diff suppressed because one or more lines are too long
2
public/js/24.js
vendored
2
public/js/24.js
vendored
File diff suppressed because one or more lines are too long
2
public/js/25.js
vendored
2
public/js/25.js
vendored
File diff suppressed because one or more lines are too long
2
public/js/26.js
vendored
2
public/js/26.js
vendored
File diff suppressed because one or more lines are too long
2
public/js/27.js
vendored
2
public/js/27.js
vendored
File diff suppressed because one or more lines are too long
2
public/js/28.js
vendored
2
public/js/28.js
vendored
File diff suppressed because one or more lines are too long
2
public/js/29.js
vendored
2
public/js/29.js
vendored
File diff suppressed because one or more lines are too long
2
public/js/3.js
vendored
2
public/js/3.js
vendored
File diff suppressed because one or more lines are too long
2
public/js/30.js
vendored
2
public/js/30.js
vendored
File diff suppressed because one or more lines are too long
2
public/js/31.js
vendored
2
public/js/31.js
vendored
File diff suppressed because one or more lines are too long
2
public/js/32.js
vendored
2
public/js/32.js
vendored
File diff suppressed because one or more lines are too long
2
public/js/33.js
vendored
2
public/js/33.js
vendored
File diff suppressed because one or more lines are too long
2
public/js/34.js
vendored
2
public/js/34.js
vendored
File diff suppressed because one or more lines are too long
2
public/js/35.js
vendored
2
public/js/35.js
vendored
File diff suppressed because one or more lines are too long
2
public/js/36.js
vendored
2
public/js/36.js
vendored
File diff suppressed because one or more lines are too long
2
public/js/37.js
vendored
2
public/js/37.js
vendored
File diff suppressed because one or more lines are too long
2
public/js/38.js
vendored
2
public/js/38.js
vendored
File diff suppressed because one or more lines are too long
2
public/js/39.js
vendored
2
public/js/39.js
vendored
File diff suppressed because one or more lines are too long
2
public/js/4.js
vendored
2
public/js/4.js
vendored
File diff suppressed because one or more lines are too long
2
public/js/40.js
vendored
2
public/js/40.js
vendored
File diff suppressed because one or more lines are too long
2
public/js/41.js
vendored
2
public/js/41.js
vendored
File diff suppressed because one or more lines are too long
2
public/js/42.js
vendored
2
public/js/42.js
vendored
File diff suppressed because one or more lines are too long
2
public/js/43.js
vendored
2
public/js/43.js
vendored
File diff suppressed because one or more lines are too long
2
public/js/44.js
vendored
2
public/js/44.js
vendored
File diff suppressed because one or more lines are too long
2
public/js/45.js
vendored
2
public/js/45.js
vendored
File diff suppressed because one or more lines are too long
2
public/js/46.js
vendored
2
public/js/46.js
vendored
File diff suppressed because one or more lines are too long
2
public/js/47.js
vendored
2
public/js/47.js
vendored
File diff suppressed because one or more lines are too long
2
public/js/48.js
vendored
2
public/js/48.js
vendored
File diff suppressed because one or more lines are too long
2
public/js/49.js
vendored
2
public/js/49.js
vendored
File diff suppressed because one or more lines are too long
2
public/js/5.js
vendored
2
public/js/5.js
vendored
File diff suppressed because one or more lines are too long
2
public/js/50.js
vendored
2
public/js/50.js
vendored
File diff suppressed because one or more lines are too long
2
public/js/51.js
vendored
2
public/js/51.js
vendored
File diff suppressed because one or more lines are too long
2
public/js/52.js
vendored
2
public/js/52.js
vendored
File diff suppressed because one or more lines are too long
2
public/js/53.js
vendored
2
public/js/53.js
vendored
File diff suppressed because one or more lines are too long
2
public/js/54.js
vendored
2
public/js/54.js
vendored
File diff suppressed because one or more lines are too long
2
public/js/55.js
vendored
2
public/js/55.js
vendored
File diff suppressed because one or more lines are too long
2
public/js/56.js
vendored
2
public/js/56.js
vendored
File diff suppressed because one or more lines are too long
2
public/js/57.js
vendored
2
public/js/57.js
vendored
File diff suppressed because one or more lines are too long
2
public/js/58.js
vendored
2
public/js/58.js
vendored
File diff suppressed because one or more lines are too long
2
public/js/59.js
vendored
2
public/js/59.js
vendored
File diff suppressed because one or more lines are too long
2
public/js/6.js
vendored
2
public/js/6.js
vendored
File diff suppressed because one or more lines are too long
2
public/js/60.js
vendored
2
public/js/60.js
vendored
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