diff --git a/app/Http/Controllers/ImageController.php b/app/Http/Controllers/ImageController.php index 44ad80b..6db93c4 100644 --- a/app/Http/Controllers/ImageController.php +++ b/app/Http/Controllers/ImageController.php @@ -23,10 +23,6 @@ class ImageController extends Controller */ public function display($post_id, $options = 'o:full', $image, ImageService $image_service) { - if (Auth::guest()) { - throw new UnauthorizedHttpException('Vous devez être connecté pour voir cette image.'); - } - $post = Post::find($post_id); if (Auth::user()->getAuthIdentifier() !== (int)$post->user_id) { diff --git a/app/Http/Controllers/UserController.php b/app/Http/Controllers/UserController.php new file mode 100644 index 0000000..7047acf --- /dev/null +++ b/app/Http/Controllers/UserController.php @@ -0,0 +1,44 @@ + Auth::user()]); + } + + public function update(UpdateUser $request) + { + /** @var User $user */ + $user_id = Auth::user()->getAuthIdentifier(); + $user = User::find($user_id); + $validated = $request->validated(); + if (isset($validated['avatar'])) { + try { + $user->clearMediaCollection('avatars'); + $user->addMediaFromRequest('avatar')->toMediaCollection('avatars'); + } catch (DiskDoesNotExist $e) { + } catch (FileDoesNotExist $e) { + } catch (FileIsTooBig $e) { + } + unset($validated['avatar']); + } + + if (!array_key_exists('encrypt_messages', $validated)) { + $validated['encrypt_messages'] = 0; + } + + $user->update($validated); + + return redirect(route('user.index'))->withSuccess('Data saved!'); + } +} diff --git a/app/Http/Requests/UpdateUser.php b/app/Http/Requests/UpdateUser.php new file mode 100644 index 0000000..8081f3f --- /dev/null +++ b/app/Http/Requests/UpdateUser.php @@ -0,0 +1,35 @@ + 'required|min:4|max:255', + 'email' => 'required|email:rfc|unique:users,email,'.Auth::user()->getAuthIdentifier(), + 'encrypt_messages' => 'boolean', + 'notification_hour' => 'in:0,1,2,3,4', + 'avatar' => 'file|dimensions:max_width=200,max_height=200,ratio=1' + ]; + } +} diff --git a/app/User.php b/app/User.php index 60bc353..5425326 100644 --- a/app/User.php +++ b/app/User.php @@ -5,10 +5,15 @@ namespace App; use Illuminate\Contracts\Auth\MustVerifyEmail; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; +use Illuminate\Support\Facades\Log; +use Spatie\Image\Exceptions\InvalidManipulation; +use Spatie\MediaLibrary\HasMedia\HasMedia; +use Spatie\MediaLibrary\HasMedia\HasMediaTrait; +use Spatie\MediaLibrary\Models\Media; -class User extends Authenticatable +class User extends Authenticatable implements HasMedia { - use Notifiable; + use Notifiable, HasMediaTrait; /** * The attributes that are mass assignable. @@ -16,7 +21,7 @@ class User extends Authenticatable * @var array */ protected $fillable = [ - 'name', 'email', 'password', + 'name', 'email', 'password', 'notification_hour', 'encrypt_messages', ]; /** @@ -28,15 +33,13 @@ class User extends Authenticatable 'password', 'remember_token', ]; - /** - * The attributes that should be cast to native types. - * - * @var array - */ - protected $casts = [ - 'email_verified_at' => 'datetime', + protected $dates = [ + 'created_at', 'updated_at', 'email_verified_at', ]; + /** + * @return string + */ public function getFolder() { $arrayHash = str_split(strtolower(md5($this->id))); @@ -50,4 +53,32 @@ class User extends Authenticatable { return (bool) $this->encrypt_messages; } + + /** + * @param Media|null $media + */ + public function registerMediaConversions(Media $media = null) + { + try { + $this->addMediaConversion('thumb') + ->width(100) + ->height(100) + ->optimize(); + $this->addMediaConversion('icon') + ->width(32) + ->height(32) + ->optimize(); + } catch (InvalidManipulation $e) { + Log::alert(sprintf('Error while manipulating Avatar for %s (%s)', $this->email, $e->getMessage())); + } + } + + /** + * @param string $alias + * @return string + */ + public function getAvatar($alias = 'thumb'): string + { + return $this->getFirstMediaUrl('avatars', $alias); + } } diff --git a/composer.json b/composer.json index 4de1904..0f5af1b 100644 --- a/composer.json +++ b/composer.json @@ -13,7 +13,8 @@ "intervention/image": "^2.5", "laravel/framework": "^6.0", "laravel/tinker": "^1.0", - "lavary/laravel-menu": "^1.7" + "lavary/laravel-menu": "^1.7", + "spatie/laravel-medialibrary": "^7.0.0" }, "require-dev": { "facade/ignition": "^1.4", diff --git a/composer.lock b/composer.lock index a25d7a0..f5496db 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "a8999b4d9f518e7a9608ff59c6ba40e9", + "content-hash": "e3145fece6314548c650ce97ed16de32", "packages": [ { "name": "dnoegel/php-xdg-base-dir", @@ -953,6 +953,128 @@ ], "time": "2019-08-24T11:17:19+00:00" }, + { + "name": "league/glide", + "version": "1.5.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/glide.git", + "reference": "a5477e9e822ed57b39861a17092b92553634932d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/glide/zipball/a5477e9e822ed57b39861a17092b92553634932d", + "reference": "a5477e9e822ed57b39861a17092b92553634932d", + "shasum": "" + }, + "require": { + "intervention/image": "^2.4", + "league/flysystem": "^1.0", + "php": "^5.5 | ^7.0", + "psr/http-message": "^1.0" + }, + "require-dev": { + "mockery/mockery": "~0.9", + "phpunit/php-token-stream": "^1.4", + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Glide\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jonathan Reinink", + "email": "jonathan@reinink.ca", + "homepage": "http://reinink.ca" + } + ], + "description": "Wonderfully easy on-demand image manipulation library with an HTTP based API.", + "homepage": "http://glide.thephpleague.com", + "keywords": [ + "ImageMagick", + "editing", + "gd", + "image", + "imagick", + "league", + "manipulation", + "processing" + ], + "time": "2019-04-03T23:46:42+00:00" + }, + { + "name": "maennchen/zipstream-php", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/maennchen/ZipStream-PHP.git", + "reference": "6373eefe0b3274d7b702d81f2c99aa977ff97dc2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/maennchen/ZipStream-PHP/zipball/6373eefe0b3274d7b702d81f2c99aa977ff97dc2", + "reference": "6373eefe0b3274d7b702d81f2c99aa977ff97dc2", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "myclabs/php-enum": "^1.5", + "php": ">= 7.1", + "psr/http-message": "^1.0" + }, + "require-dev": { + "ext-zip": "*", + "guzzlehttp/guzzle": ">= 6.3", + "mikey179/vfsstream": "^1.6", + "phpunit/phpunit": ">= 7.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "ZipStream\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paul Duncan", + "email": "pabs@pablotron.org" + }, + { + "name": "Jesse Donat", + "email": "donatj@gmail.com" + }, + { + "name": "Jonatan Männchen", + "email": "jonatan@maennchen.ch" + }, + { + "name": "András Kolesár", + "email": "kolesar@kolesar.hu" + } + ], + "description": "ZipStream is a library for dynamically streaming dynamic zip files from PHP without writing to the disk at all on the server.", + "keywords": [ + "stream", + "zip" + ], + "time": "2019-07-17T11:01:58+00:00" + }, { "name": "monolog/monolog", "version": "2.0.0", @@ -1034,6 +1156,52 @@ ], "time": "2019-08-30T09:56:44+00:00" }, + { + "name": "myclabs/php-enum", + "version": "1.7.6", + "source": { + "type": "git", + "url": "https://github.com/myclabs/php-enum.git", + "reference": "5f36467c7a87e20fbdc51e524fd8f9d1de80187c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/php-enum/zipball/5f36467c7a87e20fbdc51e524fd8f9d1de80187c", + "reference": "5f36467c7a87e20fbdc51e524fd8f9d1de80187c", + "shasum": "" + }, + "require": { + "ext-json": "*", + "php": ">=7.1" + }, + "require-dev": { + "phpunit/phpunit": "^7", + "squizlabs/php_codesniffer": "1.*", + "vimeo/psalm": "^3.8" + }, + "type": "library", + "autoload": { + "psr-4": { + "MyCLabs\\Enum\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP Enum contributors", + "homepage": "https://github.com/myclabs/php-enum/graphs/contributors" + } + ], + "description": "PHP Enum implementation", + "homepage": "http://github.com/myclabs/php-enum", + "keywords": [ + "enum" + ], + "time": "2020-02-14T08:15:52+00:00" + }, { "name": "nesbot/carbon", "version": "2.24.0", @@ -1698,6 +1866,290 @@ ], "time": "2018-07-19T23:38:55+00:00" }, + { + "name": "spatie/image", + "version": "1.7.6", + "source": { + "type": "git", + "url": "https://github.com/spatie/image.git", + "reference": "74535b5fd67ace75840c00c408666660843e755e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spatie/image/zipball/74535b5fd67ace75840c00c408666660843e755e", + "reference": "74535b5fd67ace75840c00c408666660843e755e", + "shasum": "" + }, + "require": { + "ext-exif": "*", + "ext-mbstring": "*", + "league/glide": "^1.4", + "php": "^7.0", + "spatie/image-optimizer": "^1.0", + "spatie/temporary-directory": "^1.0.0", + "symfony/process": "^3.0|^4.0|^5.0" + }, + "require-dev": { + "larapack/dd": "^1.1", + "phpunit/phpunit": "^6.0|^7.0", + "symfony/var-dumper": "^3.2|^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Spatie\\Image\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Freek Van der Herten", + "email": "freek@spatie.be", + "homepage": "https://spatie.be", + "role": "Developer" + } + ], + "description": "Manipulate images with an expressive API", + "homepage": "https://github.com/spatie/image", + "keywords": [ + "image", + "spatie" + ], + "time": "2020-01-26T18:56:44+00:00" + }, + { + "name": "spatie/image-optimizer", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/spatie/image-optimizer.git", + "reference": "9c1d470e34b28b715d25edb539dd6c899461527c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spatie/image-optimizer/zipball/9c1d470e34b28b715d25edb539dd6c899461527c", + "reference": "9c1d470e34b28b715d25edb539dd6c899461527c", + "shasum": "" + }, + "require": { + "ext-fileinfo": "*", + "php": "^7.2", + "psr/log": "^1.0", + "symfony/process": "^4.2|^5.0" + }, + "require-dev": { + "phpunit/phpunit": "^8.0", + "symfony/var-dumper": "^4.2|^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Spatie\\ImageOptimizer\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Freek Van der Herten", + "email": "freek@spatie.be", + "homepage": "https://spatie.be", + "role": "Developer" + } + ], + "description": "Easily optimize images using PHP", + "homepage": "https://github.com/spatie/image-optimizer", + "keywords": [ + "image-optimizer", + "spatie" + ], + "time": "2019-11-25T12:29:24+00:00" + }, + { + "name": "spatie/laravel-medialibrary", + "version": "7.18.0", + "source": { + "type": "git", + "url": "https://github.com/spatie/laravel-medialibrary.git", + "reference": "6461708267ca8863b351eb70f6d5eb324a3eec0b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spatie/laravel-medialibrary/zipball/6461708267ca8863b351eb70f6d5eb324a3eec0b", + "reference": "6461708267ca8863b351eb70f6d5eb324a3eec0b", + "shasum": "" + }, + "require": { + "ext-fileinfo": "*", + "illuminate/bus": "~5.5.0|~5.6.0|~5.7.0|~5.8.0|^6.0", + "illuminate/console": "~5.5.0|~5.6.0|~5.7.0|~5.8.0|^6.0", + "illuminate/database": "~5.5.0|~5.6.0|~5.7.0|~5.8.0|^6.0", + "illuminate/pipeline": "~5.5.0|~5.6.0|~5.7.0|~5.8.0|^6.0", + "illuminate/support": "~5.5.0|~5.6.0|~5.7.0|~5.8.0|^6.0", + "league/flysystem": "^1.0.8", + "maennchen/zipstream-php": "^1.0", + "php": "^7.2", + "spatie/image": "^1.4.0", + "spatie/pdf-to-image": "^1.2", + "spatie/temporary-directory": "^1.1" + }, + "conflict": { + "php-ffmpeg/php-ffmpeg": "<0.6.1" + }, + "require-dev": { + "doctrine/dbal": "^2.5.2", + "ext-pdo_sqlite": "*", + "guzzlehttp/guzzle": "^6.3", + "league/flysystem-aws-s3-v3": "^1.0.13", + "mockery/mockery": "^1.0.0", + "orchestra/testbench": "~3.8.0|^4.0", + "phpunit/phpunit": "^8.0", + "spatie/phpunit-snapshot-assertions": "^2.0" + }, + "suggest": { + "league/flysystem-aws-s3-v3": "Required to use AWS S3 file storage", + "php-ffmpeg/php-ffmpeg": "Required for generating video thumbnails" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Spatie\\MediaLibrary\\MediaLibraryServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Spatie\\MediaLibrary\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Freek Van der Herten", + "email": "freek@spatie.be", + "homepage": "https://murze.be", + "role": "Developer" + } + ], + "description": "Associate files with Eloquent models", + "homepage": "https://github.com/spatie/laravel-medialibrary", + "keywords": [ + "cms", + "conversion", + "downloads", + "images", + "laravel", + "laravel-medialibrary", + "media", + "spatie" + ], + "time": "2020-01-05T12:27:11+00:00" + }, + { + "name": "spatie/pdf-to-image", + "version": "1.8.2", + "source": { + "type": "git", + "url": "https://github.com/spatie/pdf-to-image.git", + "reference": "22a580e03550c95ce810ad430e3c44d2f7a1c75a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spatie/pdf-to-image/zipball/22a580e03550c95ce810ad430e3c44d2f7a1c75a", + "reference": "22a580e03550c95ce810ad430e3c44d2f7a1c75a", + "shasum": "" + }, + "require": { + "ext-imagick": "*", + "php": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "Spatie\\PdfToImage\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Freek Van der Herten", + "email": "freek@spatie.be", + "homepage": "https://spatie.be", + "role": "Developer" + } + ], + "description": "Convert a pdf to an image", + "homepage": "https://github.com/spatie/pdf-to-image", + "keywords": [ + "convert", + "image", + "pdf", + "pdf-to-image", + "spatie" + ], + "time": "2019-07-31T06:46:19+00:00" + }, + { + "name": "spatie/temporary-directory", + "version": "1.2.2", + "source": { + "type": "git", + "url": "https://github.com/spatie/temporary-directory.git", + "reference": "fcb127e615700751dac2aefee0ea2808ff3f5bb1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spatie/temporary-directory/zipball/fcb127e615700751dac2aefee0ea2808ff3f5bb1", + "reference": "fcb127e615700751dac2aefee0ea2808ff3f5bb1", + "shasum": "" + }, + "require": { + "php": "^7.2" + }, + "require-dev": { + "phpunit/phpunit": "^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Spatie\\TemporaryDirectory\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Alex Vanderbist", + "email": "alex@spatie.be", + "homepage": "https://spatie.be", + "role": "Developer" + } + ], + "description": "Easily create, use and destroy temporary directories", + "homepage": "https://github.com/spatie/temporary-directory", + "keywords": [ + "spatie", + "temporary-directory" + ], + "time": "2019-12-15T18:52:09+00:00" + }, { "name": "swiftmailer/swiftmailer", "version": "v6.2.1", diff --git a/config/medialibrary.php b/config/medialibrary.php new file mode 100644 index 0000000..9b00744 --- /dev/null +++ b/config/medialibrary.php @@ -0,0 +1,156 @@ + env('MEDIA_DISK', 'public'), + + /* + * The maximum file size of an item in bytes. + * Adding a larger file will result in an exception. + */ + 'max_file_size' => 1024 * 1024 * 10, + + /* + * This queue will be used to generate derived and responsive images. + * Leave empty to use the default queue. + */ + 'queue_name' => '', + + /* + * The fully qualified class name of the media model. + */ + 'media_model' => Spatie\MediaLibrary\Models\Media::class, + + 's3' => [ + /* + * The domain that should be prepended when generating urls. + */ + 'domain' => 'https://'.env('AWS_BUCKET').'.s3.amazonaws.com', + ], + + 'remote' => [ + /* + * Any extra headers that should be included when uploading media to + * a remote disk. Even though supported headers may vary between + * different drivers, a sensible default has been provided. + * + * Supported by S3: CacheControl, Expires, StorageClass, + * ServerSideEncryption, Metadata, ACL, ContentEncoding + */ + 'extra_headers' => [ + 'CacheControl' => 'max-age=604800', + ], + ], + + 'responsive_images' => [ + + /* + * This class is responsible for calculating the target widths of the responsive + * images. By default we optimize for filesize and create variations that each are 20% + * smaller than the previous one. More info in the documentation. + * + * https://docs.spatie.be/laravel-medialibrary/v7/advanced-usage/generating-responsive-images + */ + 'width_calculator' => Spatie\MediaLibrary\ResponsiveImages\WidthCalculator\FileSizeOptimizedWidthCalculator::class, + + /* + * By default rendering media to a responsive image will add some javascript and a tiny placeholder. + * This ensures that the browser can already determine the correct layout. + */ + 'use_tiny_placeholders' => true, + + /* + * This class will generate the tiny placeholder used for progressive image loading. By default + * the medialibrary will use a tiny blurred jpg image. + */ + 'tiny_placeholder_generator' => Spatie\MediaLibrary\ResponsiveImages\TinyPlaceholderGenerator\Blurred::class, + ], + + /* + * When urls to files get generated, this class will be called. Leave empty + * if your files are stored locally above the site root or on s3. + */ + 'url_generator' => null, + + /* + * Whether to activate versioning when urls to files get generated. + * When activated, this attaches a ?v=xx query string to the URL. + */ + 'version_urls' => false, + + /* + * The class that contains the strategy for determining a media file's path. + */ + 'path_generator' => null, + + /* + * Medialibrary will try to optimize all converted images by removing + * metadata and applying a little bit of compression. These are + * the optimizers that will be used by default. + */ + 'image_optimizers' => [ + Spatie\ImageOptimizer\Optimizers\Jpegoptim::class => [ + '--strip-all', // this strips out all text information such as comments and EXIF data + '--all-progressive', // this will make sure the resulting image is a progressive one + ], + Spatie\ImageOptimizer\Optimizers\Pngquant::class => [ + '--force', // required parameter for this package + ], + Spatie\ImageOptimizer\Optimizers\Optipng::class => [ + '-i0', // this will result in a non-interlaced, progressive scanned image + '-o2', // this set the optimization level to two (multiple IDAT compression trials) + '-quiet', // required parameter for this package + ], + Spatie\ImageOptimizer\Optimizers\Svgo::class => [ + '--disable=cleanupIDs', // disabling because it is known to cause troubles + ], + Spatie\ImageOptimizer\Optimizers\Gifsicle::class => [ + '-b', // required parameter for this package + '-O3', // this produces the slowest but best results + ], + ], + + /* + * These generators will be used to create an image of media files. + */ + 'image_generators' => [ + Spatie\MediaLibrary\ImageGenerators\FileTypes\Image::class, + Spatie\MediaLibrary\ImageGenerators\FileTypes\Webp::class, + Spatie\MediaLibrary\ImageGenerators\FileTypes\Pdf::class, + Spatie\MediaLibrary\ImageGenerators\FileTypes\Svg::class, + Spatie\MediaLibrary\ImageGenerators\FileTypes\Video::class, + ], + + /* + * The engine that should perform the image conversions. + * Should be either `gd` or `imagick`. + */ + 'image_driver' => 'gd', + + /* + * FFMPEG & FFProbe binaries paths, only used if you try to generate video + * thumbnails and have installed the php-ffmpeg/php-ffmpeg composer + * dependency. + */ + 'ffmpeg_path' => env('FFMPEG_PATH', '/usr/bin/ffmpeg'), + 'ffprobe_path' => env('FFPROBE_PATH', '/usr/bin/ffprobe'), + + /* + * The path where to store temporary files while performing image conversions. + * If set to null, storage_path('medialibrary/temp') will be used. + */ + 'temporary_directory_path' => null, + + /* + * Here you can override the class names of the jobs used by this package. Make sure + * your custom jobs extend the ones provided by the package. + */ + 'jobs' => [ + 'perform_conversions' => Spatie\MediaLibrary\Jobs\PerformConversions::class, + 'generate_responsive_images' => Spatie\MediaLibrary\Jobs\GenerateResponsiveImages::class, + ], +]; diff --git a/database/migrations/2020_03_17_170058_create_media_table.php b/database/migrations/2020_03_17_170058_create_media_table.php new file mode 100644 index 0000000..139ec80 --- /dev/null +++ b/database/migrations/2020_03_17_170058_create_media_table.php @@ -0,0 +1,38 @@ +bigIncrements('id'); + $table->morphs('model'); + $table->string('collection_name'); + $table->string('name'); + $table->string('file_name'); + $table->string('mime_type')->nullable(); + $table->string('disk'); + $table->unsignedBigInteger('size'); + $table->json('manipulations'); + $table->json('custom_properties'); + $table->json('responsive_images'); + $table->unsignedInteger('order_column')->nullable(); + $table->nullableTimestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down() + { + Schema::dropIfExists('media'); + } +} diff --git a/resources/views/layouts/connected.blade.php b/resources/views/layouts/connected.blade.php index ee9b641..8d4a513 100644 --- a/resources/views/layouts/connected.blade.php +++ b/resources/views/layouts/connected.blade.php @@ -55,15 +55,24 @@