You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
pixelfed/app/Http/Controllers/AvatarController.php

154 lines
5.2 KiB
PHTML

<?php
namespace App\Http\Controllers;
use App\Jobs\AvatarPipeline\AvatarOptimize;
use App\Models\Avatar;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
class AvatarController extends Controller
{
public function __construct()
{
return $this->middleware('auth');
}
public function store(Request $request): RedirectResponse
{
$this->validate($request, [
9 months ago
'avatar' => 'required|mimetypes:image/jpeg,image/jpg,image/png|max:'.config('pixelfed.max_avatar_size'),
]);
try {
$user = $request->user();
$profile = $user->profile;
$file = $request->file('avatar');
$path = $this->getPath($user, $file);
$dir = $path['root'];
$name = $path['name'];
$public = $path['storage'];
$loc = $request->file('avatar')->storePubliclyAs($public, $name);
$avatar = Avatar::firstOrNew(['profile_id' => $profile->id]);
$currentAvatar = $avatar->recentlyCreated ? null : storage_path('app/'.$profile->avatar->media_path);
$avatar->media_path = "$public/$name";
$avatar->change_count = ++$avatar->change_count;
$avatar->last_processed_at = null;
$avatar->save();
Cache::forget("avatar:{$profile->id}");
Cache::forget('user:account:id:'.$user->id);
AvatarOptimize::dispatch($user->profile, $currentAvatar);
} catch (\Exception $e) {
Log::error('AvatarController@store failed: '.$e->getMessage(), [
'user_id' => $request->user()?->id,
'exception' => $e,
]);
return redirect()->back()->withErrors([
'avatar' => 'There was an error updating your avatar. Please try again.',
]);
}
return redirect()->back()->with('status', 'Avatar updated successfully. It may take a few minutes to update across the site.');
}
public function getPath($user, $file)
{
$basePath = storage_path('app/public/avatars');
$this->checkDir($basePath);
$id = $user->profile->id;
$path = $this->buildPath($id);
$dir = storage_path('app/'.$path);
$this->checkDir($dir);
$name = Str::random(20).'_avatar.'.$file->guessExtension();
$res = ['root' => 'storage/app/'.$path, 'name' => $name, 'storage' => $path];
return $res;
}
public function checkDir($path): void
{
9 months ago
if (! is_dir($path)) {
mkdir($path);
}
}
public function buildPath($id)
{
$padded = str_pad($id, 19, 0, STR_PAD_LEFT);
$parts = str_split($padded, 3);
foreach ($parts as $k => $part) {
6 days ago
if ($k === 0) {
$prefix = storage_path('app/public/avatars/'.$parts[0]);
$this->checkDir($prefix);
}
6 days ago
if ($k === 1) {
$prefix = storage_path('app/public/avatars/'.$parts[0].'/'.$parts[1]);
$this->checkDir($prefix);
}
6 days ago
if ($k === 2) {
$prefix = storage_path('app/public/avatars/'.$parts[0].'/'.$parts[1].'/'.$parts[2]);
$this->checkDir($prefix);
}
6 days ago
if ($k === 3) {
$avatarpath = 'public/avatars/'.$parts[0].'/'.$parts[1].'/'.$parts[2].'/'.$parts[3];
$prefix = storage_path('app/'.$avatarpath);
$this->checkDir($prefix);
}
6 days ago
if ($k === 4) {
$avatarpath = 'public/avatars/'.$parts[0].'/'.$parts[1].'/'.$parts[2].'/'.$parts[3].'/'.$parts[4];
$prefix = storage_path('app/'.$avatarpath);
$this->checkDir($prefix);
}
6 days ago
if ($k === 5) {
$avatarpath = 'public/avatars/'.$parts[0].'/'.$parts[1].'/'.$parts[2].'/'.$parts[3].'/'.$parts[4].'/'.$parts[5];
$prefix = storage_path('app/'.$avatarpath);
$this->checkDir($prefix);
}
6 days ago
if ($k === 6) {
$avatarpath = 'public/avatars/'.$parts[0].'/'.$parts[1].'/'.$parts[2].'/'.$parts[3].'/'.$parts[4].'/'.$parts[5].'/'.$parts[6];
$prefix = storage_path('app/'.$avatarpath);
$this->checkDir($prefix);
}
}
return $avatarpath;
}
public function deleteAvatar(Request $request): JsonResponse
{
$user = $request->user();
$profile = $user->profile;
$avatar = $profile->avatar;
9 months ago
if ($avatar->media_path == 'public/avatars/default.png' ||
$avatar->media_path == 'public/avatars/default.jpg'
) {
return response()->json(200);
}
$oldPath = $avatar->media_path;
$oldFullPath = storage_path('app/'.$oldPath);
if (is_file($oldFullPath)) {
9 months ago
@unlink(storage_path('app/'.$avatar->media_path));
}
$avatar->media_path = 'public/avatars/default.jpg';
$avatar->change_count = $avatar->change_count + 1;
$avatar->save();
9 months ago
Cache::forget('avatar:'.$avatar->profile_id);
return response()->json(200);
}
}