|
|
|
|
@ -11,6 +11,8 @@ use App\Services\MailDeliveryService;
@@ -11,6 +11,8 @@ use App\Services\MailDeliveryService;
|
|
|
|
|
use App\Support\ApiActor; |
|
|
|
|
use Illuminate\Http\JsonResponse; |
|
|
|
|
use Illuminate\Http\Request; |
|
|
|
|
use Illuminate\Support\Facades\Storage; |
|
|
|
|
use Illuminate\Support\Str; |
|
|
|
|
use InvalidArgumentException; |
|
|
|
|
use RuntimeException; |
|
|
|
|
use Throwable; |
|
|
|
|
@ -44,7 +46,10 @@ class MeController extends Controller
@@ -44,7 +46,10 @@ class MeController extends Controller
|
|
|
|
|
$data['domain'] = $profile['domain'] ?? ''; |
|
|
|
|
$data['phone'] = $meta['phone'] ?? ''; |
|
|
|
|
$data['other_email'] = $meta['other_email'] ?? ''; |
|
|
|
|
$data['avatar'] = $meta['avatar'] ?? null; |
|
|
|
|
$avatarPath = $meta['avatar'] ?? null; |
|
|
|
|
$data['avatar'] = $avatarPath |
|
|
|
|
? Storage::disk('public')->url($avatarPath) |
|
|
|
|
: null; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return $this->ok($data); |
|
|
|
|
@ -126,24 +131,51 @@ class MeController extends Controller
@@ -126,24 +131,51 @@ class MeController extends Controller
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
$data = $request->validate([ |
|
|
|
|
'avatar' => ['nullable', 'string', 'max:262144'], |
|
|
|
|
'avatar' => ['nullable', 'string', 'max:524288'], |
|
|
|
|
]); |
|
|
|
|
|
|
|
|
|
try { |
|
|
|
|
$avatarValue = isset($data['avatar']) && $data['avatar'] !== '' |
|
|
|
|
? $data['avatar'] |
|
|
|
|
: null; |
|
|
|
|
$meta = $this->metadata->getUserMeta($actor->identifier); |
|
|
|
|
$oldPath = $meta['avatar'] ?? null; |
|
|
|
|
$avatarInput = isset($data['avatar']) && $data['avatar'] !== '' ? $data['avatar'] : null; |
|
|
|
|
|
|
|
|
|
if ($avatarInput === null) { |
|
|
|
|
// Hapus foto |
|
|
|
|
if ($oldPath) { |
|
|
|
|
Storage::disk('public')->delete($oldPath); |
|
|
|
|
} |
|
|
|
|
$this->metadata->saveAvatar($actor->identifier, null); |
|
|
|
|
return $this->ok(['message' => 'Foto profil dihapus.', 'avatar_url' => null]); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if ($avatarValue !== null && ! preg_match('/^data:image\/(jpeg|png|webp|gif);base64,/', $avatarValue)) { |
|
|
|
|
// Validasi format base64 data-URI |
|
|
|
|
if (! preg_match('/^data:image\/(jpeg|png|webp);base64,(.+)$/s', $avatarInput, $m)) { |
|
|
|
|
return $this->fail('Format avatar tidak valid. Harus base64 image (jpeg/png/webp).', 'invalid_format', 422); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
$this->metadata->saveAvatar($actor->identifier, $avatarValue); |
|
|
|
|
} catch (Throwable) { |
|
|
|
|
return $this->fail('Gagal menyimpan avatar.', 'server_error', 500); |
|
|
|
|
$imageData = base64_decode($m[2], strict: true); |
|
|
|
|
if ($imageData === false || strlen($imageData) > 300 * 1024) { |
|
|
|
|
return $this->fail('Ukuran gambar terlalu besar (maks 300KB).', 'too_large', 422); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
$ext = $m[1] === 'jpeg' ? 'jpg' : $m[1]; |
|
|
|
|
$filename = 'avatars/' . Str::slug($actor->identifier) . '-' . Str::random(8) . '.' . $ext; |
|
|
|
|
|
|
|
|
|
Storage::disk('public')->put($filename, $imageData); |
|
|
|
|
|
|
|
|
|
// Hapus file lama jika ada |
|
|
|
|
if ($oldPath && $oldPath !== $filename) { |
|
|
|
|
Storage::disk('public')->delete($oldPath); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
$this->metadata->saveAvatar($actor->identifier, $filename); |
|
|
|
|
|
|
|
|
|
$avatarUrl = Storage::disk('public')->url($filename); |
|
|
|
|
} catch (Throwable $e) { |
|
|
|
|
return $this->fail('Gagal menyimpan avatar: ' . $e->getMessage(), 'server_error', 500); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return $this->ok(['message' => 'Avatar berhasil diperbarui.', 'avatar' => $avatarValue]); |
|
|
|
|
return $this->ok(['message' => 'Foto profil berhasil diperbarui.', 'avatar_url' => $avatarUrl]); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public function testEmail(Request $request): JsonResponse |
|
|
|
|
|