get(); $currentAdmin = config_cache('instance.admin.pid') ? AccountService::get(config_cache('instance.admin.pid'), true) : null; $openReg = (bool) config_cache('pixelfed.open_registration'); $curOnboarding = (bool) config_cache('instance.curated_registration.enabled'); $regState = $openReg ? 'open' : ($curOnboarding ? 'filtered' : 'closed'); $accountMigration = (bool) config_cache('federation.migration'); return view('admin.settings.home', compact( 'jpeg', 'png', 'gif', 'mp4', 'webp', 'rules', 'cloud_storage', 'cloud_disk', 'cloud_ready', 'availableAdmins', 'currentAdmin', 'regState', 'accountMigration' )); } public function settingsHomeStore(Request $request) { $this->validate($request, [ 'name' => 'nullable|string', 'short_description' => 'nullable', 'long_description' => 'nullable', 'max_photo_size' => 'nullable|integer|min:1', 'max_album_length' => 'nullable|integer|min:1|max:100', 'image_quality' => 'nullable|integer|min:1|max:100', 'type_jpeg' => 'nullable', 'type_png' => 'nullable', 'type_gif' => 'nullable', 'type_mp4' => 'nullable', 'type_webp' => 'nullable', 'admin_account_id' => 'nullable', 'regs' => 'required|in:open,filtered,closed', 'account_migration' => 'nullable', 'rule_delete' => 'sometimes' ]); $orb = false; $cob = false; switch ($request->input('regs')) { case 'open': $orb = true; $cob = false; break; case 'filtered': $orb = false; $cob = true; break; case 'closed': $orb = false; $cob = false; break; } ConfigCacheService::put('pixelfed.open_registration', (bool) $orb); ConfigCacheService::put('instance.curated_registration.enabled', (bool) $cob); if ($request->filled('admin_account_id')) { ConfigCacheService::put('instance.admin.pid', $request->admin_account_id); Cache::forget('api:v1:instance-data:contact'); Cache::forget('api:v1:instance-data-response-v1'); } if ($request->filled('rule_delete')) { $index = (int) $request->input('rule_delete'); $rules = ConfigCacheService::get('app.rules'); $json = json_decode($rules, true); if (! $rules || empty($json)) { return; } unset($json[$index]); $json = json_encode(array_values($json)); ConfigCacheService::put('app.rules', $json); Cache::forget('api:v1:instance-data:rules'); Cache::forget('api:v1:instance-data-response-v1'); return 200; } $media_types = explode(',', config_cache('pixelfed.media_types')); $media_types_original = $media_types; $mimes = [ 'type_jpeg' => 'image/jpeg', 'type_png' => 'image/png', 'type_gif' => 'image/gif', 'type_mp4' => 'video/mp4', 'type_webp' => 'image/webp', ]; foreach ($mimes as $key => $value) { if ($request->input($key) == 'on') { if (! in_array($value, $media_types)) { array_push($media_types, $value); } } else { $media_types = array_diff($media_types, [$value]); } } if ($media_types !== $media_types_original) { ConfigCacheService::put('pixelfed.media_types', implode(',', array_unique($media_types))); } $keys = [ 'name' => 'app.name', 'short_description' => 'app.short_description', 'long_description' => 'app.description', 'max_photo_size' => 'pixelfed.max_photo_size', 'max_album_length' => 'pixelfed.max_album_length', 'image_quality' => 'pixelfed.image_quality', 'account_limit' => 'pixelfed.max_account_size', 'custom_css' => 'uikit.custom.css', 'custom_js' => 'uikit.custom.js', 'about_title' => 'about.title', ]; foreach ($keys as $key => $value) { $cc = ConfigCache::whereK($value)->first(); $val = $request->input($key); if ($cc && $cc->v != $val) { ConfigCacheService::put($value, $val); } elseif (! empty($val)) { ConfigCacheService::put($value, $val); } } $bools = [ 'activitypub' => 'federation.activitypub.enabled', // 'open_registration' => 'pixelfed.open_registration', 'mobile_apis' => 'pixelfed.oauth_enabled', 'stories' => 'instance.stories.enabled', 'ig_import' => 'pixelfed.import.instagram.enabled', 'spam_detection' => 'pixelfed.bouncer.enabled', 'require_email_verification' => 'pixelfed.enforce_email_verification', 'enforce_account_limit' => 'pixelfed.enforce_account_limit', 'show_custom_css' => 'uikit.show_custom.css', 'show_custom_js' => 'uikit.show_custom.js', 'cloud_storage' => 'pixelfed.cloud_storage', 'account_autofollow' => 'account.autofollow', 'show_directory' => 'instance.landing.show_directory', 'show_explore_feed' => 'instance.landing.show_explore', 'account_migration' => 'federation.migration', ]; foreach ($bools as $key => $value) { $active = $request->input($key) == 'on'; if ($key == 'activitypub' && $active && ! InstanceActor::exists()) { Artisan::call('instance:actor'); } if ($key == 'mobile_apis' && $active && ! file_exists(storage_path('oauth-public.key')) && ! file_exists(storage_path('oauth-private.key')) ) { Artisan::call('passport:keys'); Artisan::call('route:cache'); } if (config_cache($value) !== $active) { ConfigCacheService::put($value, (bool) $active); } } if ($request->filled('new_rule')) { $rules = ConfigCacheService::get('app.rules'); $val = $request->input('new_rule'); if (! $rules) { ConfigCacheService::put('app.rules', json_encode([$val])); } else { $json = json_decode($rules, true); $json[] = $val; ConfigCacheService::put('app.rules', json_encode(array_values($json))); } Cache::forget('api:v1:instance-data:rules'); Cache::forget('api:v1:instance-data-response-v1'); } if ($request->filled('account_autofollow_usernames')) { $usernames = explode(',', $request->input('account_autofollow_usernames')); $names = []; foreach ($usernames as $n) { $p = Profile::whereUsername($n)->first(); if (! $p) { continue; } array_push($names, $p->username); } ConfigCacheService::put('account.autofollow_usernames', implode(',', $names)); } Cache::forget(Config::CACHE_KEY); return redirect('/i/admin/settings')->with('status', 'Successfully updated settings!'); } public function settingsBackups(Request $request) { $path = storage_path('app/'.config('app.name')); $files = is_dir($path) ? new \DirectoryIterator($path) : []; return view('admin.settings.backups', compact('files')); } public function settingsMaintenance(Request $request) { return view('admin.settings.maintenance'); } public function settingsStorage(Request $request) { $storage = []; return view('admin.settings.storage', compact('storage')); } public function settingsFeatures(Request $request) { return view('admin.settings.features'); } public function settingsPages(Request $request) { $pages = Page::orderByDesc('updated_at')->paginate(10); return view('admin.pages.home', compact('pages')); } public function settingsPageEdit(Request $request) { return view('admin.pages.edit'); } public function settingsSystem(Request $request) { $sys = [ 'pixelfed' => config('pixelfed.version'), 'php' => phpversion(), 'laravel' => app()->version(), ]; switch (config('database.default')) { case 'pgsql': $exp = DB::raw('select version();'); $expQuery = $exp->getValue(DB::connection()->getQueryGrammar()); $sys['database'] = [ 'name' => 'Postgres', 'version' => explode(' ', DB::select($expQuery)[0]->version)[1], ]; break; case 'mysql': $exp = DB::raw('select version()'); $expQuery = $exp->getValue(DB::connection()->getQueryGrammar()); $sys['database'] = [ 'name' => 'MySQL', 'version' => DB::select($expQuery)[0]->{'version()'}, ]; break; default: $sys['database'] = [ 'name' => 'Unknown', 'version' => '?', ]; break; } return view('admin.settings.system', compact('sys')); } public function settingsApiFetch(Request $request) { $cloud_storage = ConfigCacheService::get('pixelfed.cloud_storage'); $cloud_disk = config('filesystems.cloud'); $cloud_ready = ! empty(config('filesystems.disks.'.$cloud_disk.'.key')) && ! empty(config('filesystems.disks.'.$cloud_disk.'.secret')); $types = explode(',', ConfigCacheService::get('pixelfed.media_types')); $rules = ConfigCacheService::get('app.rules') ? json_decode(ConfigCacheService::get('app.rules'), true) : []; $jpeg = in_array('image/jpg', $types) || in_array('image/jpeg', $types); $png = in_array('image/png', $types); $gif = in_array('image/gif', $types); $mp4 = in_array('video/mp4', $types); $webp = in_array('image/webp', $types); $availableAdmins = User::whereIsAdmin(true)->get(); $currentAdmin = config_cache('instance.admin.pid') ? AccountService::get(config_cache('instance.admin.pid'), true) : null; $openReg = (bool) config_cache('pixelfed.open_registration'); $curOnboarding = (bool) config_cache('instance.curated_registration.enabled'); $regState = $openReg ? 'open' : ($curOnboarding ? 'filtered' : 'closed'); $accountMigration = (bool) config_cache('federation.migration'); $autoFollow = config_cache('account.autofollow_usernames'); if(strlen($autoFollow) > 3) { $autoFollow = explode(',', $autoFollow); } $res = AdminSettingsService::getAll(); return response()->json($res); } public function settingsApiRulesAdd(Request $request) { $this->validate($request, [ 'rule' => 'required|string|min:5|max:1000' ]); $rules = ConfigCacheService::get('app.rules'); $val = $request->input('rule'); if (! $rules) { ConfigCacheService::put('app.rules', json_encode([$val])); } else { $json = json_decode($rules, true); $count = count($json); if($count >= 30) { return response()->json(['message' => 'Max rules limit reached, you can set up to 30 rules at a time.'], 400); } $json[] = $val; ConfigCacheService::put('app.rules', json_encode(array_values($json))); } Cache::forget('api:v1:instance-data:rules'); Cache::forget('api:v1:instance-data-response-v1'); Cache::forget('api:v2:instance-data-response-v2'); Config::refresh(); return [$val]; } public function settingsApiRulesDelete(Request $request) { $this->validate($request, [ 'rule' => 'required|string', ]); $rules = ConfigCacheService::get('app.rules'); $val = $request->input('rule'); if (! $rules) { return []; } else { $json = json_decode($rules, true); $idx = array_search($val, $json); if($idx !== false) { unset($json[$idx]); $json = array_values($json); } ConfigCacheService::put('app.rules', json_encode(array_values($json))); } Cache::forget('api:v1:instance-data:rules'); Cache::forget('api:v1:instance-data-response-v1'); Cache::forget('api:v2:instance-data-response-v2'); Config::refresh(); return response()->json($json); } public function settingsApiRulesDeleteAll(Request $request) { $rules = ConfigCacheService::get('app.rules'); if (! $rules) { return []; } else { ConfigCacheService::put('app.rules', json_encode([])); } Cache::forget('api:v1:instance-data:rules'); Cache::forget('api:v1:instance-data-response-v1'); Cache::forget('api:v2:instance-data-response-v2'); Config::refresh(); return response()->json([]); } public function settingsApiAutofollowDelete(Request $request) { $this->validate($request, [ 'username' => 'required|string', ]); $username = $request->input('username'); $names = []; $existing = config_cache('account.autofollow_usernames'); if($existing) { $names = explode(',', $existing); } if(in_array($username, $names)) { $key = array_search($username, $names); if($key !== false) { unset($names[$key]); } } ConfigCacheService::put('account.autofollow_usernames', implode(',', $names)); return response()->json(['accounts' => array_values($names)]); } public function settingsApiAutofollowAdd(Request $request) { $this->validate($request, [ 'username' => 'required|string', ]); $username = $request->input('username'); $names = []; $existing = config_cache('account.autofollow_usernames'); if($existing) { $names = explode(',', $existing); } $p = Profile::whereUsername($username)->whereNotNull('user_id')->first(); if (! $p || in_array($p->username, $names)) { abort(404); } array_push($names, strtolower($p->username)); ConfigCacheService::put('account.autofollow_usernames', implode(',', $names)); return response()->json(['accounts' => array_values($names)]); } public function settingsApiUpdateType(Request $request, $type) { abort_unless(in_array($type, [ 'posts', 'platform', 'home', 'landing', 'branding', 'media', 'users', 'storage', ]), 400); switch ($type) { case 'home': return $this->settingsApiUpdateHomeType($request); break; case 'landing': return $this->settingsApiUpdateLandingType($request); break; case 'posts': return $this->settingsApiUpdatePostsType($request); break; case 'platform': return $this->settingsApiUpdatePlatformType($request); break; case 'branding': return $this->settingsApiUpdateBrandingType($request); break; case 'media': return $this->settingsApiUpdateMediaType($request); break; case 'users': return $this->settingsApiUpdateUsersType($request); break; case 'storage': return $this->settingsApiUpdateStorageType($request); break; default: abort(404); break; } } public function settingsApiUpdateHomeType($request) { $this->validate($request, [ 'registration_status' => 'required|in:open,filtered,closed', 'cloud_storage' => 'required', 'activitypub_enabled' => 'required', 'account_migration' => 'required', 'mobile_apis' => 'required', 'stories' => 'required', 'instagram_import' => 'required', 'autospam_enabled' => 'required', ]); $regStatus = $request->input('registration_status'); ConfigCacheService::put('pixelfed.open_registration', $regStatus === 'open'); ConfigCacheService::put('instance.curated_registration.enabled', $regStatus === 'filtered'); $cloudStorage = $request->boolean('cloud_storage'); if($cloudStorage !== (bool) config_cache('pixelfed.cloud_storage')) { if(!$cloudStorage) { ConfigCacheService::put('pixelfed.cloud_storage', false); } else { $cloud_disk = config('filesystems.cloud'); $cloud_ready = ! empty(config('filesystems.disks.'.$cloud_disk.'.key')) && ! empty(config('filesystems.disks.'.$cloud_disk.'.secret')); if(!$cloud_ready) { return redirect()->back()->withErrors(['cloud_storage' => 'Must configure cloud storage before enabling!']); } else { ConfigCacheService::put('pixelfed.cloud_storage', true); } } } ConfigCacheService::put('federation.activitypub.enabled', $request->boolean('activitypub_enabled')); ConfigCacheService::put('federation.migration', $request->boolean('account_migration')); ConfigCacheService::put('pixelfed.oauth_enabled', $request->boolean('mobile_apis')); ConfigCacheService::put('instance.stories.enabled', $request->boolean('stories')); ConfigCacheService::put('pixelfed.import.instagram.enabled', $request->boolean('instagram_import')); ConfigCacheService::put('pixelfed.bouncer.enabled', $request->boolean('autospam_enabled')); Cache::forget('api:v1:instance-data-response-v1'); Cache::forget('api:v2:instance-data-response-v2'); Cache::forget('api:v1:instance-data:contact'); Config::refresh(); return $request->all(); } public function settingsApiUpdateLandingType($request) { $this->validate($request, [ 'current_admin' => 'required', 'show_directory' => 'required', 'show_explore' => 'required', ]); ConfigCacheService::put('instance.admin.pid', $request->input('current_admin')); ConfigCacheService::put('instance.landing.show_directory', $request->boolean('show_directory')); ConfigCacheService::put('instance.landing.show_explore', $request->boolean('show_explore')); Cache::forget('api:v1:instance-data:rules'); Cache::forget('api:v1:instance-data-response-v1'); Cache::forget('api:v2:instance-data-response-v2'); Cache::forget('api:v1:instance-data:contact'); Config::refresh(); return $request->all(); } public function settingsApiUpdateMediaType($request) { $this->validate($request, [ 'image_quality' => 'required|integer|min:1|max:100', 'max_album_length' => 'required|integer|min:1|max:20', 'max_photo_size' => 'required|integer|min:100|max:50000', 'media_types' => 'required', 'optimize_image' => 'required', 'optimize_video' => 'required', ]); $mediaTypes = $request->input('media_types'); $mediaArray = explode(',', $mediaTypes); foreach ($mediaArray as $mediaType) { if(!in_array($mediaType, ['image/jpeg', 'image/png', 'image/gif', 'image/webp', 'video/mp4'])) { return redirect()->back()->withErrors(['media_types' => 'Invalid media type']); } } ConfigCacheService::put('pixelfed.media_types', $request->input('media_types')); ConfigCacheService::put('pixelfed.image_quality', $request->input('image_quality')); ConfigCacheService::put('pixelfed.max_album_length', $request->input('max_album_length')); ConfigCacheService::put('pixelfed.max_photo_size', $request->input('max_photo_size')); ConfigCacheService::put('pixelfed.optimize_image', $request->boolean('optimize_image')); ConfigCacheService::put('pixelfed.optimize_video', $request->boolean('optimize_video')); Cache::forget('api:v1:instance-data:rules'); Cache::forget('api:v1:instance-data-response-v1'); Cache::forget('api:v2:instance-data-response-v2'); Cache::forget('api:v1:instance-data:contact'); Config::refresh(); return $request->all(); } public function settingsApiUpdateBrandingType($request) { $this->validate($request, [ 'name' => 'required', 'short_description' => 'required', 'long_description' => 'required', ]); ConfigCacheService::put('app.name', $request->input('name')); ConfigCacheService::put('app.short_description', $request->input('short_description')); ConfigCacheService::put('app.description', $request->input('long_description')); Cache::forget('api:v1:instance-data:rules'); Cache::forget('api:v1:instance-data-response-v1'); Cache::forget('api:v2:instance-data-response-v2'); Cache::forget('api:v1:instance-data:contact'); Config::refresh(); return $request->all(); } public function settingsApiUpdatePostsType($request) { $this->validate($request, [ 'max_caption_length' => 'required|integer|min:5|max:10000', 'max_altext_length' => 'required|integer|min:5|max:40000', ]); ConfigCacheService::put('pixelfed.max_caption_length', $request->input('max_caption_length')); ConfigCacheService::put('pixelfed.max_altext_length', $request->input('max_altext_length')); $res = [ 'max_caption_length' => $request->input('max_caption_length'), 'max_altext_length' => $request->input('max_altext_length'), ]; Cache::forget('api:v1:instance-data:rules'); Cache::forget('api:v1:instance-data-response-v1'); Cache::forget('api:v2:instance-data-response-v2'); Config::refresh(); return $res; } public function settingsApiUpdatePlatformType($request) { $this->validate($request, [ 'allow_app_registration' => 'required', 'app_registration_rate_limit_attempts' => 'required|integer|min:1', 'app_registration_rate_limit_decay' => 'required|integer|min:1', 'app_registration_confirm_rate_limit_attempts' => 'required|integer|min:1', 'app_registration_confirm_rate_limit_decay' => 'required|integer|min:1', 'allow_post_embeds' => 'required', 'allow_profile_embeds' => 'required', 'captcha_enabled' => 'required', 'captcha_on_login' => 'required_if_accepted:captcha_enabled', 'captcha_on_register' => 'required_if_accepted:captcha_enabled', 'captcha_secret' => 'required_if_accepted:captcha_enabled', 'captcha_sitekey' => 'required_if_accepted:captcha_enabled', 'custom_emoji_enabled' => 'required', ]); ConfigCacheService::put('pixelfed.allow_app_registration', $request->boolean('allow_app_registration')); ConfigCacheService::put('pixelfed.app_registration_rate_limit_attempts', $request->input('app_registration_rate_limit_attempts')); ConfigCacheService::put('pixelfed.app_registration_rate_limit_decay', $request->input('app_registration_rate_limit_decay')); ConfigCacheService::put('pixelfed.app_registration_confirm_rate_limit_attempts', $request->input('app_registration_confirm_rate_limit_attempts')); ConfigCacheService::put('pixelfed.app_registration_confirm_rate_limit_decay', $request->input('app_registration_confirm_rate_limit_decay')); ConfigCacheService::put('instance.embed.post', $request->boolean('allow_post_embeds')); ConfigCacheService::put('instance.embed.profile', $request->boolean('allow_profile_embeds')); ConfigCacheService::put('federation.custom_emoji.enabled', $request->boolean('custom_emoji_enabled')); $captcha = $request->boolean('captcha_enabled'); if($captcha) { $secret = $request->input('captcha_secret'); $sitekey = $request->input('captcha_sitekey'); if(config_cache('captcha.secret') != $secret && strpos($secret, '*') === false) { ConfigCacheService::put('captcha.secret', $secret); } if(config_cache('captcha.sitekey') != $sitekey && strpos($sitekey, '*') === false) { ConfigCacheService::put('captcha.sitekey', $sitekey); } ConfigCacheService::put('captcha.active.login', $request->boolean('captcha_on_login')); ConfigCacheService::put('captcha.active.register', $request->boolean('captcha_on_register')); ConfigCacheService::put('captcha.triggers.login.enabled', $request->boolean('captcha_on_login')); ConfigCacheService::put('captcha.enabled', true); } else { ConfigCacheService::put('captcha.enabled', false); } $res = [ 'allow_app_registration' => $request->boolean('allow_app_registration'), 'app_registration_rate_limit_attempts' => $request->input('app_registration_rate_limit_attempts'), 'app_registration_rate_limit_decay' => $request->input('app_registration_rate_limit_decay'), 'app_registration_confirm_rate_limit_attempts' => $request->input('app_registration_confirm_rate_limit_attempts'), 'app_registration_confirm_rate_limit_decay' => $request->input('app_registration_confirm_rate_limit_decay'), 'allow_post_embeds' => $request->boolean('allow_post_embeds'), 'allow_profile_embeds' => $request->boolean('allow_profile_embeds'), 'captcha_enabled' => $request->boolean('captcha_enabled'), 'captcha_on_login' => $request->boolean('captcha_on_login'), 'captcha_on_register' => $request->boolean('captcha_on_register'), 'captcha_secret' => $request->input('captcha_secret'), 'captcha_sitekey' => $request->input('captcha_sitekey'), 'custom_emoji_enabled' => $request->boolean('custom_emoji_enabled'), ]; Cache::forget('api:v1:instance-data:rules'); Cache::forget('api:v1:instance-data-response-v1'); Cache::forget('api:v2:instance-data-response-v2'); Config::refresh(); return $res; } public function settingsApiUpdateUsersType($request) { $this->validate($request, [ 'require_email_verification' => 'required', 'enforce_account_limit' => 'required', 'admin_autofollow' => 'required' ]); ConfigCacheService::put('pixelfed.enforce_email_verification', $request->boolean('require_email_verification')); ConfigCacheService::put('pixelfed.enforce_account_limit', $request->boolean('enforce_account_limit')); ConfigCacheService::put('account.autofollow', $request->boolean('admin_autofollow')); $res = [ 'require_email_verification' => $request->boolean('require_email_verification'), 'enforce_account_limit' => $request->boolean('enforce_account_limit'), 'admin_autofollow' => $request->boolean('admin_autofollow'), ]; Cache::forget('api:v1:instance-data:rules'); Cache::forget('api:v1:instance-data-response-v1'); Cache::forget('api:v2:instance-data-response-v2'); Config::refresh(); return $res; } public function settingsApiUpdateStorageType($request) { $this->validate($request, [ 'primary_disk' => 'required|in:local,cloud', 'update_disk' => 'sometimes', 'disk_config' => 'required_if_accepted:update_disk', 'disk_config.driver' => 'required|in:s3,spaces', 'disk_config.key' => 'required', 'disk_config.secret' => 'required', 'disk_config.region' => 'required', 'disk_config.bucket' => 'required', 'disk_config.visibility' => 'required', 'disk_config.endpoint' => 'required', 'disk_config.url' => 'nullable', ]); ConfigCacheService::put('pixelfed.cloud_storage', $request->input('primary_disk') === 'cloud'); $res = [ 'primary_disk' => $request->input('primary_disk'), ]; if($request->has('update_disk')) { $res['disk_config'] = $request->input('disk_config'); $changes = []; $dkey = $request->input('disk_config.driver') === 's3' ? 'filesystems.disks.s3.' : 'filesystems.disks.spaces.'; $key = $request->input('disk_config.key'); $ckey = null; $secret = $request->input('disk_config.secret'); $csecret = null; $region = $request->input('disk_config.region'); $bucket = $request->input('disk_config.bucket'); $visibility = $request->input('disk_config.visibility'); $url = $request->input('disk_config.url'); $endpoint = $request->input('disk_config.endpoint'); if(strpos($key, '*') === false && $key != config_cache($dkey . 'key')) { array_push($changes, 'key'); } else { $ckey = config_cache($dkey . 'key'); } if(strpos($secret, '*') === false && $secret != config_cache($dkey . 'secret')) { array_push($changes, 'secret'); } else { $csecret = config_cache($dkey . 'secret'); } if($region != config_cache($dkey . 'region')) { array_push($changes, 'region'); } if($bucket != config_cache($dkey . 'bucket')) { array_push($changes, 'bucket'); } if($visibility != config_cache($dkey . 'visibility')) { array_push($changes, 'visibility'); } if($url != config_cache($dkey . 'url')) { array_push($changes, 'url'); } if($endpoint != config_cache($dkey . 'endpoint')) { array_push($changes, 'endpoint'); } if($changes && count($changes)) { $isValid = FilesystemService::getVerifyCredentials( $ckey ?? $key, $csecret ?? $secret, $region, $bucket, $endpoint, ); if(!$isValid) { return response()->json(['error' => true, 's3_vce' => true, 'message' => "
The S3/Spaces credentials you provided are invalid, or the bucket does not have the proper permissions.

Please check all fields and try again.

Any cloud storage configuration changes you made have NOT been saved due to invalid credentials."], 400); } } $res['changes'] = json_encode($changes); } Cache::forget('api:v1:instance-data:rules'); Cache::forget('api:v1:instance-data-response-v1'); Cache::forget('api:v2:instance-data-response-v2'); Config::refresh(); return $res; } }