diff --git a/app/Http/Controllers/SettingsController.php b/app/Http/Controllers/SettingsController.php index a3c3cab8f..7fefbf909 100755 --- a/app/Http/Controllers/SettingsController.php +++ b/app/Http/Controllers/SettingsController.php @@ -348,7 +348,6 @@ class SettingsController extends Controller } $setting->default_eula_text = $request->input('default_eula_text'); - $setting->load_remote = $request->input('load_remote', 0); $setting->thumbnail_max_h = $request->input('thumbnail_max_h'); $setting->privacy_policy_link = $request->input('privacy_policy_link'); $setting->depreciation_method = $request->input('depreciation_method'); @@ -393,10 +392,11 @@ class SettingsController extends Controller * * @since [v1.0] * - * @return View + * @return \Illuminate\Contracts\View\View | \Illuminate\Http\RedirectResponse */ public function postBranding(ImageUploadRequest $request) { + // Something has gone horribly wrong - no settings record exists! if (is_null($setting = Setting::getSettings())) { return redirect()->to('admin')->with('error', trans('admin/settings/message.update.error')); } @@ -407,51 +407,75 @@ class SettingsController extends Controller $setting->version_footer = $request->input('version_footer'); $setting->footer_text = $request->input('footer_text'); $setting->skin = $request->input('skin'); - $setting->allow_user_skin = $request->input('allow_user_skin'); + $setting->allow_user_skin = $request->input('allow_user_skin', '0'); $setting->show_url_in_emails = $request->input('show_url_in_emails', '0'); $setting->logo_print_assets = $request->input('logo_print_assets', '0'); + $setting->load_remote = $request->input('load_remote', 0); - // Only allow the site name and CSS to be changed if lock_passwords is false + // Only allow the site name, images, and CSS to be changed if lock_passwords is false // Because public demos make people act like dicks - if (! config('app.lock_passwords')) { - $request->validate(['site_name' => 'required']); - $setting->site_name = $request->input('site_name'); + if (!config('app.lock_passwords')) { + + if ($request->has('site_name')) { + $request->validate(['site_name' => 'required']); + } + + $setting->site_name = $request->input('site_name', 'Snipe-IT'); $setting->custom_css = $request->input('custom_css'); + + // Logo upload $setting = $request->handleImages($setting, 600, 'logo', '', 'logo'); - if ('1' == $request->input('clear_logo')) { - Storage::disk('public')->delete($setting->logo); + if ($request->input('clear_logo') == '1') { + + if (($setting->logo) && (Storage::exists($setting->logo))) { + Storage::disk('public')->delete($setting->logo); + } $setting->logo = null; $setting->brand = 1; } - + // Email logo upload $setting = $request->handleImages($setting, 600, 'email_logo', '', 'email_logo'); + if ($request->input('clear_email_logo') == '1') { - - if ('1' == $request->input('clear_email_logo')) { - Storage::disk('public')->delete($setting->email_logo); + if (($setting->email_logo) && (Storage::exists($setting->email_logo))) { + Storage::disk('public')->delete($setting->email_logo); + } $setting->email_logo = null; // If they are uploading an image, validate it and upload it } - + // Label logo upload $setting = $request->handleImages($setting, 600, 'label_logo', '', 'label_logo'); + if ($request->input('clear_label_logo') == '1') { - if ('1' == $request->input('clear_label_logo')) { - Storage::disk('public')->delete($setting->label_logo); + if (($setting->label_logo) && (Storage::exists($setting->label_logo))) { + Storage::disk('public')->delete($setting->label_logo); + } $setting->label_logo = null; } - - $setting = $request->handleImages($setting, 600, 'favicon', '', 'favicon'); - - // If the user wants to clear the favicon... + // Favicon upload + $setting = $request->handleImages($setting, 100, 'favicon', '', 'favicon'); if ('1' == $request->input('clear_favicon')) { - Storage::disk('public')->delete($setting->favicon); + + if (($setting->favicon) && (Storage::exists($setting->favicon))) { + Storage::disk('public')->delete($setting->favicon); + } $setting->favicon = null; } + + // Default avatar upload + $setting = $request->handleImages($setting, 500, 'default_avatar', 'avatars', 'default_avatar'); + if ($request->input('clear_default_avatar') == '1') { + + if (($setting->default_avatar) && (Storage::exists('avatars/'.$setting->default_avatar))) { + Storage::disk('public')->delete('avatars/'.$setting->default_avatar); + } + $setting->default_avatar = null; + } } if ($setting->save()) { diff --git a/app/Http/Requests/ImageUploadRequest.php b/app/Http/Requests/ImageUploadRequest.php index c75454d0f..8b9aed499 100644 --- a/app/Http/Requests/ImageUploadRequest.php +++ b/app/Http/Requests/ImageUploadRequest.php @@ -96,10 +96,7 @@ class ImageUploadRequest extends Request $ext = $image->guessExtension(); $file_name = $type.'-'.$form_fieldname.'-'.$item->id.'-'.str_random(10).'.'.$ext; - - Log::info('File name will be: '.$file_name); - Log::debug('File extension is: '.$ext); - + if (($image->getMimeType() == 'image/vnd.microsoft.icon') || ($image->getMimeType() == 'image/x-icon') || ($image->getMimeType() == 'image/avif') || ($image->getMimeType() == 'image/webp')) { // If the file is an icon, webp or avif, we need to just move it since gd doesn't support resizing // icons or avif, and webp support and needs to be compiled into gd for resizing to be available diff --git a/app/Http/Transformers/UsersTransformer.php b/app/Http/Transformers/UsersTransformer.php index 64752d044..0b573b838 100644 --- a/app/Http/Transformers/UsersTransformer.php +++ b/app/Http/Transformers/UsersTransformer.php @@ -24,7 +24,7 @@ class UsersTransformer $array = [ 'id' => (int) $user->id, - 'avatar' => e($user->present()->gravatar), + 'avatar' => e($user->present()->gravatar) ?? null, 'name' => e($user->getFullNameAttribute()), 'first_name' => e($user->first_name), 'last_name' => e($user->last_name), diff --git a/app/Presenters/UserPresenter.php b/app/Presenters/UserPresenter.php index d0f5c13fe..7c6d46573 100644 --- a/app/Presenters/UserPresenter.php +++ b/app/Presenters/UserPresenter.php @@ -432,6 +432,8 @@ class UserPresenter extends Presenter */ public function gravatar() { + + // User's specific avatar if ($this->avatar) { // Check if it's a google avatar or some external avatar @@ -443,6 +445,12 @@ class UserPresenter extends Presenter return Storage::disk('public')->url('avatars/'.e($this->avatar)); } + // If there is a default avatar + if (Setting::getSettings()->default_avatar!= '') { + return Storage::disk('public')->url('avatars/'.e(Setting::getSettings()->default_avatar)); + } + + // Fall back to Gravatar if the settings allow loading remote scripts if (Setting::getSettings()->load_remote == '1') { if ($this->model->gravatar != '') { @@ -456,8 +464,8 @@ class UserPresenter extends Presenter } } - // Set a fun, gender-neutral default icon - return config('app.url').'/img/default-sm.png'; + + return false; } /** diff --git a/database/migrations/2024_07_04_103729_add_default_avatar_to_settings.php b/database/migrations/2024_07_04_103729_add_default_avatar_to_settings.php new file mode 100644 index 000000000..423f45e9e --- /dev/null +++ b/database/migrations/2024_07_04_103729_add_default_avatar_to_settings.php @@ -0,0 +1,28 @@ +string('default_avatar')->after('favicon')->default('default.png')->nullable(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('settings', function (Blueprint $table) { + $table->dropColumn('default_avatar'); + }); + } +}; diff --git a/package-lock.json b/package-lock.json index f8eddcc97..addc766d9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -36,7 +36,7 @@ "signature_pad": "^4.2.0", "tableexport.jquery.plugin": "1.30.0", "tether": "^1.4.0", - "webpack": "^5.90.2" + "webpack": "^5.92.0" }, "devDependencies": { "all-contributors-cli": "^6.26.1", @@ -2497,6 +2497,14 @@ "acorn": "^8" } }, + "node_modules/acorn-import-attributes": { + "version": "1.9.5", + "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", + "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", + "peerDependencies": { + "acorn": "^8" + } + }, "node_modules/acorn-node": { "version": "1.8.2", "license": "Apache-2.0", @@ -5291,8 +5299,9 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.16.0", - "license": "MIT", + "version": "5.17.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.0.tgz", + "integrity": "sha512-dwDPwZL0dmye8Txp2gzFmA6sxALaSvdRDjPH0viLcKrtlOL3tw62nWWweVD1SdILDTJrbrL6tdWVN58Wo6U3eA==", "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" @@ -10394,7 +10403,8 @@ }, "node_modules/tapable": { "version": "2.2.1", - "license": "MIT", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", "engines": { "node": ">=6" } @@ -10857,8 +10867,9 @@ "license": "BSD-2-Clause" }, "node_modules/webpack": { - "version": "5.91.0", - "license": "MIT", + "version": "5.92.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.92.1.tgz", + "integrity": "sha512-JECQ7IwJb+7fgUFBlrJzbyu3GEuNBcdqr1LD7IbSzwkSmIevTm8PF+wej3Oxuz/JFBUZ6O1o43zsPkwm1C4TmA==", "dependencies": { "@types/eslint-scope": "^3.7.3", "@types/estree": "^1.0.5", @@ -10866,10 +10877,10 @@ "@webassemblyjs/wasm-edit": "^1.12.1", "@webassemblyjs/wasm-parser": "^1.12.1", "acorn": "^8.7.1", - "acorn-import-assertions": "^1.9.0", + "acorn-import-attributes": "^1.9.5", "browserslist": "^4.21.10", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.16.0", + "enhanced-resolve": "^5.17.0", "es-module-lexer": "^1.2.1", "eslint-scope": "5.1.1", "events": "^3.2.0", diff --git a/package.json b/package.json index 9f1ce36f2..83b3ada46 100644 --- a/package.json +++ b/package.json @@ -56,6 +56,6 @@ "signature_pad": "^4.2.0", "tableexport.jquery.plugin": "1.30.0", "tether": "^1.4.0", - "webpack": "^5.90.2" + "webpack": "^5.92.0" } } diff --git a/resources/lang/en-US/admin/settings/general.php b/resources/lang/en-US/admin/settings/general.php index 8074f5082..dca13b985 100644 --- a/resources/lang/en-US/admin/settings/general.php +++ b/resources/lang/en-US/admin/settings/general.php @@ -122,8 +122,8 @@ return [ 'ldap_test' => 'Test LDAP', 'ldap_test_sync' => 'Test LDAP Synchronization', 'license' => 'Software License', - 'load_remote' => 'Use Gravatar', - 'load_remote_help_text' => 'Uncheck this box if your install cannot load scripts from the outside internet. This will prevent Snipe-IT from trying load images from Gravatar.', + 'load_remote' => 'Load Remote Avatars', + 'load_remote_help_text' => 'Uncheck this box if your install cannot load scripts from the outside internet. This will prevent Snipe-IT from trying load avatars from Gravatar or other outside sources.', 'login' => 'Login Attempts', 'login_attempt' => 'Login Attempt', 'login_ip' => 'IP Address', @@ -375,5 +375,6 @@ return [ 'timezone' => 'Timezone', 'profile_edit' => 'Edit Profile', 'profile_edit_help' => 'Allow users to edit their own profiles.', + 'default_avatar' => 'Upload default avatar', ]; diff --git a/resources/views/layouts/default.blade.php b/resources/views/layouts/default.blade.php index 5b23db7b8..74e9d5be6 100644 --- a/resources/views/layouts/default.blade.php +++ b/resources/views/layouts/default.blade.php @@ -324,7 +324,7 @@ dir="{{ in_array(app()->getLocale(),['ar-SA','fa-IR', 'he-IL']) ? 'rtl' : 'ltr' @else - + @endif {{ Auth::user()->getFullNameAttribute() }} $(function () { - var locale = '{{ config('app.locale') }}'; + var locale = '{{ app()->getLocale() }}'; var blockedFields = "searchable,sortable,switchable,title,visible,formatter,class".split(","); var keyBlocked = function(key) { @@ -46,7 +46,6 @@ stickyHeader: true, stickyHeaderOffsetLeft: parseInt($('body').css('padding-left'), 10), stickyHeaderOffsetRight: parseInt($('body').css('padding-right'), 10), - locale: '{{ app()->getLocale() }}', undefinedText: '', iconsPrefix: 'fa', cookieStorage: '{{ config('session.bs_table_storage') }}', diff --git a/resources/views/partials/forms/edit/uploadLogo.blade.php b/resources/views/partials/forms/edit/uploadLogo.blade.php index 85034ff5f..b7c9cf49a 100644 --- a/resources/views/partials/forms/edit/uploadLogo.blade.php +++ b/resources/views/partials/forms/edit/uploadLogo.blade.php @@ -9,7 +9,7 @@ {{ trans('button.select_file') }} - @@ -28,13 +28,12 @@ - - @if (($setting->$logoVariable!='') && (Storage::disk('public')->exists(e($snipeSettings->$logoVariable)))) - - - - - + @if (($setting->$logoVariable!='') && (Storage::disk('public')->exists(($logoPath ?? ''). $snipeSettings->$logoVariable))) + + + + + @endif @@ -44,7 +43,7 @@ - @if (($setting->$logoVariable!='') && (Storage::disk('public')->exists(e($snipeSettings->$logoVariable)))) + @if (($setting->$logoVariable!='') && (Storage::disk('public')->exists(($logoPath ?? '').$snipeSettings->$logoVariable))) diff --git a/resources/views/settings/branding.blade.php b/resources/views/settings/branding.blade.php index 150f88712..59f6acad3 100644 --- a/resources/views/settings/branding.blade.php +++ b/resources/views/settings/branding.blade.php @@ -109,7 +109,37 @@ "maxSize" => 20000 ]) - + + @include('partials/forms/edit/uploadLogo', [ + "logoVariable" => "default_avatar", + "logoId" => "defaultAvatar", + "logoLabel" => trans('admin/settings/general.default_avatar'), + "logoClearVariable" => "clear_default_avatar", + "logoPath" => "avatars/", + "helpBlock" => trans('general.image_filetypes_help', ['size' => Helper::file_upload_max_size_readable()]), + ]) + + + + + {{ trans('admin/settings/general.load_remote') }} + + + + {{ Form::checkbox('load_remote', '1', old('load_remote', $setting->load_remote)) }} + {{ trans('general.yes') }} + {!! $errors->first('load_remote', ':message') !!} + + + + {{ trans('admin/settings/general.load_remote_help_text') }} + + + + + + + {{ trans('admin/settings/general.logo_print_assets') }} diff --git a/resources/views/settings/general.blade.php b/resources/views/settings/general.blade.php index 2943901b8..91d3b1c56 100644 --- a/resources/views/settings/general.blade.php +++ b/resources/views/settings/general.blade.php @@ -144,24 +144,6 @@ - - - - {{ trans('admin/settings/general.load_remote') }} - - - - {{ Form::checkbox('load_remote', '1', old('load_remote', $setting->load_remote)) }} - {{ trans('general.yes') }} - {!! $errors->first('load_remote', ':message') !!} - - - - {{ trans('admin/settings/general.load_remote_help_text') }} - - - - diff --git a/resources/views/users/confirm-bulk-delete.blade.php b/resources/views/users/confirm-bulk-delete.blade.php index 7992c27eb..b20c904d9 100644 --- a/resources/views/users/confirm-bulk-delete.blade.php +++ b/resources/views/users/confirm-bulk-delete.blade.php @@ -39,12 +39,28 @@ - {{ trans('general.name') }} - {{ trans('general.groups') }} - {{ trans('general.assets') }} - {{ trans('general.accessories') }} - {{ trans('general.licenses') }} - {{ trans('general.consumables') }} + {{ trans('general.name') }} + {{ trans('general.groups') }} + + + {{ trans('general.assets') }} + + + + {{ trans('general.accessories') }} + + + + {{ trans('general.licenses') }} + + + + {{ trans('general.consumables') }} + + + + {{ trans('general.files') }} + @@ -71,17 +87,20 @@ @endforeach - - {{ number_format($user->assets()->count()) }} + + {{ number_format($user->assets->count()) }} - - {{ number_format($user->accessories()->count()) }} + + {{ number_format($user->accessories->count()) }} - - {{ number_format($user->licenses()->count()) }} + + {{ number_format($user->licenses->count()) }} - - {{ number_format($user->consumables()->count()) }} + + {{ number_format($user->consumables->count()) }} + + + {{ number_format($user->uploads->count()) }} @endforeach @@ -89,13 +108,13 @@ - + {{ Form::select('status_id', $statuslabel_list , old('status_id'), array('class'=>'select2', 'style'=>'width:250px')) }} {{ trans('admin/users/general.update_user_assets_status') }} - + {{ trans('general.bulk_soft_delete') }} diff --git a/tests/Feature/Settings/BrandingSettingsTest.php b/tests/Feature/Settings/BrandingSettingsTest.php index a27a5d1ef..7f887c213 100644 --- a/tests/Feature/Settings/BrandingSettingsTest.php +++ b/tests/Feature/Settings/BrandingSettingsTest.php @@ -2,15 +2,242 @@ namespace Tests\Feature\Settings; -use App\Models\User; use Tests\TestCase; +use Illuminate\Http\UploadedFile; +use Illuminate\Support\Facades\Storage; +use App\Models\User; +use App\Models\Setting; + class BrandingSettingsTest extends TestCase { public function testSiteNameIsRequired() { - $this->actingAs(User::factory()->superuser()->create()) + $response = $this->actingAs(User::factory()->superuser()->create()) + ->from(route('settings.branding.index')) ->post(route('settings.branding.save', ['site_name' => ''])) - ->assertInvalid('site_name'); + ->assertSessionHasErrors(['site_name']) + ->assertInvalid(['site_name']) + ->assertStatus(302) + ->assertRedirect(route('settings.branding.index')); + + $this->followRedirects($response)->assertSee(trans('general.error')); } + + public function testSiteNameCanBeSaved() + { + $response = $this->actingAs(User::factory()->superuser()->create()) + ->post(route('settings.branding.save', ['site_name' => 'My Awesome Site'])) + ->assertStatus(302) + ->assertValid('site_name') + ->assertRedirect(route('settings.index')) + ->assertSessionHasNoErrors(); + + $this->followRedirects($response)->assertSee('Success'); + } + + + public function testLogoCanBeUploaded() + { + $this->markTestIncomplete('This test fails because of how we handle image uploads in the ImageUploadRequest.'); + + Storage::fake('public'); + + + $this->actingAs(User::factory()->superuser()->create()) + ->post( + route('settings.branding.save', + ['logo' => UploadedFile::fake()->image('logo.jpg')]) + )->assertValid('logo') + ->assertStatus(302) + ->assertRedirect(route('settings.index')) + ->assertSessionHasNoErrors(); + + + $setting = Setting::first(); + + $this->assertNotNull($setting->logo); + $this->assertDatabaseHas('settings', ['logo' => $setting->logo]); + Storage::disk('public')->assertExists($setting->logo); + } + + public function testLogoCanBeDeleted() + { + $this->markTestIncomplete('This test fails because of how we handle image uploads in the ImageUploadRequest.'); + Storage::fake('testdisk'); + + $this->actingAs(User::factory()->superuser()->create()) + ->post(route('settings.branding.save', + ['logo' => UploadedFile::fake()->image('logo.jpg')] + )); + + $setting = Setting::getSettings()->first(); + + $this->actingAs(User::factory()->superuser()->create()) + ->post(route('settings.branding.save',['clear_logo' => '1'])); + + Storage::disk('testdisk')->assertMissing('logo.jpg'); + $setting->refresh(); + $this->assertNull($setting->logo); + } + + public function testEmailLogoCanBeUploaded() + { + $this->markTestIncomplete('This test fails because of how we handle image uploads in the ImageUploadRequest.'); + Storage::fake('testdisk'); + + $this->actingAs(User::factory()->superuser()->create()) + ->post(route('settings.branding.save', + ['email_logo' => UploadedFile::fake()->image('email-logo.jpg')] + )) + ->assertValid('email_logo') + ->assertStatus(302) + ->assertRedirect(route('settings.index')) + ->assertSessionHasNoErrors(); + + $setting = Setting::getSettings()->first(); + \Log::error($setting->toArray()); + Storage::disk('testdisk')->assertExists($setting->email_logo); + } + + public function testEmailLogoCanBeDeleted() + { + $this->markTestIncomplete('This test fails because of how we handle image uploads in the ImageUploadRequest.'); + Storage::fake('testdisk'); + + $this->actingAs(User::factory()->superuser()->create()) + ->post(route('settings.branding.save', + ['email_logo' => UploadedFile::fake()->image('email-logo.jpg')] + )); + + $setting = Setting::getSettings()->first(); + + $this->actingAs(User::factory()->superuser()->create()) + ->post(route('settings.branding.save',['clear_email_logo' => '1'])); + + Storage::disk('testdisk')->assertMissing('email-logo.jpg'); + $setting->refresh(); + $this->assertNull($setting->email_logo); + } + + + public function testLabelLogoCanBeUploaded() + { + $this->markTestIncomplete('This test fails because of how we handle image uploads in the ImageUploadRequest.'); + + Storage::fake('testdisk'); + + $this->actingAs(User::factory()->superuser()->create()) + ->post(route('settings.branding.save', + ['label_logo' => UploadedFile::fake()->image('label-logo.jpg')] + )) + ->assertValid('label_logo') + ->assertStatus(302) + ->assertRedirect(route('settings.index')) + ->assertSessionHasNoErrors(); + + $setting = Setting::getSettings()->first(); + Storage::disk('testdisk')->assertExists($setting->label_logo); + } + + public function testLabelLogoCanBeDeleted() + { + $this->markTestIncomplete('This test fails because of how we handle image uploads in the ImageUploadRequest.'); + Storage::fake('testdisk'); + + $this->actingAs(User::factory()->superuser()->create()) + ->post(route('settings.branding.save', + ['label_logo' => UploadedFile::fake()->image('label-logo.jpg')] + )); + + $setting = Setting::getSettings()->first(); + + $this->actingAs(User::factory()->superuser()->create()) + ->post(route('settings.branding.save',['clear_label_logo' => '1'])); + + Storage::disk('testdisk')->assertMissing('label-logo.jpg'); + $setting->refresh(); + $this->assertNull($setting->label_logo); + } + + public function testDefaultAvatarCanBeUploaded() + { + $this->markTestIncomplete('This test fails because of how we handle image uploads in the ImageUploadRequest.'); + $setting = Setting::getSettings()->first(); + + Storage::fake('testdisk'); + + $this->actingAs(User::factory()->superuser()->create()) + ->post(route('settings.branding.save', + ['default_avatar' => UploadedFile::fake()->image('default-avatar.jpg')] + )) + ->assertValid('default_avatar') + ->assertStatus(302) + ->assertRedirect(route('settings.index')) + ->assertSessionHasNoErrors(); + + $setting->refresh(); + Storage::disk('testdisk')->assertExists($setting->default_avatar); + } + + public function testDefaultAvatarCanBeDeleted() + { + $this->markTestIncomplete('This test fails because of how we handle image uploads in the ImageUploadRequest.'); + Storage::fake('testdisk'); + + $this->actingAs(User::factory()->superuser()->create()) + ->post(route('settings.branding.save', + ['default_avatar' => UploadedFile::fake()->image('default-avatar.jpg')] + )); + + $setting = Setting::getSettings()->first(); + + $this->actingAs(User::factory()->superuser()->create()) + ->post(route('settings.branding.save',['clear_default_avatar' => '1'])); + + Storage::disk('testdisk')->assertMissing('default-avatar.jpg'); + $setting->refresh(); + $this->assertNull($setting->default_avatar); + } + + public function testFaviconCanBeUploaded() + { + $this->markTestIncomplete('This fails mimetype validation on the mock'); + Storage::fake('testdisk'); + + $this->actingAs(User::factory()->superuser()->create()) + ->post(route('settings.branding.save', + ['favicon' => UploadedFile::fake()->image('favicon.svg')] + )) + ->assertValid('favicon') + ->assertStatus(302) + ->assertRedirect(route('settings.index')) + ->assertSessionHasNoErrors(); + + $setting = Setting::getSettings()->first(); + Storage::disk('testdisk')->assertExists($setting->favicon); + } + + public function testFaviconCanBeDeleted() + { + $this->markTestIncomplete('This fails mimetype validation on the mock'); + Storage::fake('testdisk'); + + $this->actingAs(User::factory()->superuser()->create()) + ->post(route('settings.branding.save', + ['favicon' => UploadedFile::fake()->image('favicon.ico')->mimeType('image/x-icon')] + )); + + $setting = Setting::getSettings()->first(); + + $this->actingAs(User::factory()->superuser()->create()) + ->post(route('settings.branding.save',['clear_favicon' => '1'])); + + Storage::disk('testdisk')->assertMissing('favicon.ico'); + $setting->refresh(); + $this->assertNull($setting->favicon); + } + + + }
+ {{ trans('admin/settings/general.load_remote_help_text') }} +
- {{ trans('admin/settings/general.load_remote_help_text') }} -