RichText image upload on private disk
Hi there,
I am trying to find a way on how to display images in the RichText editor that are private (ie. only viewable by the user that created the note). Using the public disk works, but as soon as I use private disk it fails to fetch the image (404).
Section::make()->columns(1)
->schema([
RichEditor::make('notes')->label('Bilješke')
->fileAttachmentsDisk('private')
->fileAttachmentsDirectory('form-attachments')
->fileAttachmentsVisibility('private')
])]);
filesystems.php
'private' => [
'driver' => 'local',
'root' => storage_path('app/private'),
'url' => env('APP_URL').'/private',
'visibility' => 'private',
],
Solution:Jump to solution
I figured it out. Dumb mistake. I was using 127.0.0.1, but my .env was set to localhost... Different domains...
Anyway, it works now. All users that are team members, can see those attachmentes and download them through the link (if they decide to copy the link from the richtextbox editor).
If they get removed from the team, they get 404. If they are not logged in, they get redirected to login page....
7 Replies
Rich text, any editor, isn’t going to support private images because they have an expirable token associated with them on the url. So even if you save it with the token it will expire and the user won’t be able to see them once that happens.
Hmm, would it be possible with something like this?
1) when user is created, it gets assigned a new Laravel storage (ie app/private/user_uploads/UUIDv4 - uuid4 is already stored in the db as a slug for that user)
->visibility(public)
2) all user uploads go to that folder
3) I could use a controller and auth middleware on that route?
Just an idea, its already too late so I cant try it out tonight :/
Would that make any sense?
Kinda. You could possibly do it with a proxy url, so that when the image is requested in the html it has to pass through an authentication layer, but that will could risk exposing user information in the html. That’s why private files use tokens.
There’s just really not a good way to do it with URLs stored in html in the database.
It’s just the nature of html content too. Not a filament or laravel thing.
I'll give it a try tomorrow and see what can be done. If it fails, I'll just disable image upload on the element. It's just a notes entry for the resource, to make it easier for the user to write unstructured data. Images inside of the editor would be a nice touch but not really needed 😁
I’m sure there might be a way to achieve it but it’s not going to be a simple solution.
I'm kinda stuck
I have the following, it returns the tennant SLUG and file name (all team members should have access to the attachments). Now all I need to do is to somehow get the current user and it's current tennant slug and check if he belongs to that group (and if the user is logged in)
filesystem.php
'notes_attachments' => [
'driver' => 'local',
'root' => storage_path('app/notes_attachments'),
'url' => env('APP_URL').'/notes_attachments',
'visibility' => 'private',
'throw' => true,
],
web.php
Route::get('/notes_attachments/{team_slug}/{file_name}', 'App\Http\Controllers\AttachmentsMediaController@getAttachedMedia');
AttachmentsMediaController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Auth;
use Storage;
use Filament;
class AttachmentsMediaController extends Controller
{
public function getAttachedMedia($team_id, $file_name) {
$user = Auth::user();
return dump($user);
//if($user->team()->slug == $team_id) {
$file = Storage::disk('notes_attachments')->get($team_id . '/' . $file_name);
return (new \Illuminate\Http\Response($file))->header('Content-Type', 'application/png');
//}
}
}
If I understand correctly, Auth::user is still not defined on the routes (web.php), since Filament is doint it's own thing... Is there a way to somehow get the current user in the routes or on the controller? I tried using ->middleware('auth'), it just returns a null valueSolution
I figured it out. Dumb mistake. I was using 127.0.0.1, but my .env was set to localhost... Different domains...
Anyway, it works now. All users that are team members, can see those attachmentes and download them through the link (if they decide to copy the link from the richtextbox editor).
If they get removed from the team, they get 404. If they are not logged in, they get redirected to login page.
Controller
public function getAttachedMedia($team_id, $file_name) {
$team = Team::where('slug', $team_id)->first();
if(Auth::id() && Auth::user()->canAccessTenant($team)) {
$file = Storage::disk('notes_attachments')->get($team_id . '/' . $file_name);
return (new \Illuminate\Http\Response($file))->header('Content-Type', 'application/png');
}
else {
abort(404);
}
}
filesystem.php
'notes_attachments' => [
'driver' => 'local',
'root' => storage_path('app/notes_attachments'),
'url' => env('APP_URL').'/notes_attachments',
'visibility' => 'private',
'throw' => true,
],
Routes (I only have one panel anyways, for multiple panels, some more work would need to be done)
Route::get('/notes_attachments/{team_slug}/{file_name}', [AttachmentsMediaController::class, 'getAttachedMedia'])->middleware(['auth']);
Route::redirect('//login', '/app/login')->name('login');
Model
public function teams(): BelongsToMany
{
return $this->belongsToMany(Team::class)->withTimestamps()->wherePivot('status', 'A');
}
public function team() {
return Filament::getTenant();
}
public function canAccessTenant(Model $tenant): bool
{
return $this->teams->contains($tenant);
}