-1

I have checked everything in AWS S3, permissions, policy bucket name, all looks okay. I have updated the config in the jetstream config file

config\jetstream.php


'profile_photo_disk' => 's3',

I have updated the .env file variables with AWS S3 values, but the profile photo has not been uploaded on S3.

The same credentials are working on simple Laravel upload code, the image is successfully uploaded on s3, but by using Jetstream, it is not working, also there is no error reflected on the screen and in the log file as well.

Anyone could please help

Mahesh Yadav
  • 2,416
  • 20
  • 23

3 Answers3

4

There is a function written in the library trait, path and function is as below

Path: \vendor\laravel\jetstrem\src\HasProfilePhoto.php

Function:

/**
 * Update the user's profile photo.
 *
 * @param  \Illuminate\Http\UploadedFile  $photo
 * @return void
 */
public function updateProfilePhoto(UploadedFile $photo)
{
    tap($this->profile_photo_path, function ($previous) use ($photo) {
        $this->forceFill([
            'profile_photo_path' => $photo->storePublicly(
                'profile-photos', ['disk' => $this->profilePhotoDisk()]
            ),
        ])->save();

        if ($previous) {
            Storage::disk($this->profilePhotoDisk())->delete($previous);
        }
    });
}

As you can see for uploading the profile image on s3 the function used is storePublicly, but in my case, the s3 policy is not defined as publicly read, so I have overloaded the same function in

app\Actions\Fortify\UpdateUserProfileInformation.php

On top of the class add the Trait as use HasProfilePhoto;

/**
 * Update the user's profile photo.
 *
 * @param  \Illuminate\Http\UploadedFile  $photo
 * @return void
 * 
 * 
 */
public function updateProfilePhoto($user, UploadedFile $photo)
{
    tap($user->profile_photo_path, function ($previous) use ($photo, $user) {
        $user->forceFill([
            'profile_photo_path' => $photo->store(
                'profile-photos', ['disk' => config('jetstream.profile_photo_disk')]
            ),
        ])->save();

        if ($previous) {
            \Storage::disk(config('jetstream.profile_photo_disk'))->delete($previous);
        }
    });
}

This works for me, I hope if you face similar issue, then it would help you.

Mahesh Yadav
  • 2,416
  • 20
  • 23
1

The problem is related to the CORS policy on the S3 bucket.

I overwrote to use ->store(...) instead of ->storePublicly(...), which solved my issue.

Original:

public function updateProfilePhoto(UploadedFile $photo)
    {
        tap($this->profile_photo_path, function ($previous) use ($photo) {
            $this->forceFill([
                'profile_photo_path' => $photo->storePublicly(
                    'profile-photos', ['disk' => $this->profilePhotoDisk()]
                ),
            ])->save();

            if ($previous) {
                Storage::disk($this->profilePhotoDisk())->delete($previous);
            }
        });
    }

New:

 public function updateProfilePhoto(UploadedFile $photo)
    {
        tap($this->profile_photo_path, function ($previous) use ($photo) {
            $this->forceFill([
                'profile_photo_path' => $photo->store(
                    'profile-photos', ['disk' => $this->profilePhotoDisk()]
                ),
            ])->save();

            if ($previous) {
                Storage::disk($this->profilePhotoDisk())->delete($previous);
            }
        });
    }
0

you must modify the User.php model since it is from there that the trait 'use HasProfilePhoto;' is referenced.

public function updateProfilePhoto(UploadedFile $photo, $storagePath = 'profile-photos')
    {
        tap($this->profile_photo_path, function ($previous) use ($photo, $storagePath) {
            $this->forceFill([
                'profile_photo_path' => $photo->store($storagePath, $this->profilePhotoDisk()),
            ])->save();

            if ($previous) {
                Storage::disk($this->profilePhotoDisk())->delete($previous);
            }
        });
    }

    public function getTemporaryProfilePhotoUrl()
    {
        if ($this->profile_photo_path) {
            return Storage::disk($this->profilePhotoDisk())->temporaryUrl(
                $this->profile_photo_path,
                now()->addHours(1) // La URL expirará en una hora
            );
        } else {
            return $this->defaultProfilePhotoUrl();
        }
    }
{{ Auth::user()->getTemporaryProfilePhotoUrl() }}

You can also create a method in the user model to generate temporary urls of one hour and thus have greater security over the data of your clients.

It is recommended to keep the security of the bucket with completely private access and thus the logic of temporary urls.