Initial commit: Animexe Laravel platform

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-14 00:01:48 +03:00
co-authored by Claude Opus 4.8
commit a63515cfc6
366 changed files with 74773 additions and 0 deletions
@@ -0,0 +1,134 @@
<?php
namespace App\Http\Controllers\Frontend;
use App\Http\Controllers\Controller;
use App\Models\VoiceCall;
use App\Models\User;
use App\Services\AgoraTokenService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Str;
class VoiceCallController extends Controller
{
public function initiate(Request $request)
{
$request->validate(['callee_id' => 'required|integer|exists:users,id']);
$caller = Auth::user();
$callee = User::findOrFail($request->callee_id);
if ($caller->id === $callee->id) {
return response()->json(['error' => 'Kendinizi arayamazsınız.'], 422);
}
// End any previous active calls
VoiceCall::where('caller_id', $caller->id)
->whereIn('status', ['ringing', 'active'])
->update(['status' => 'ended', 'ended_at' => now()]);
$channelName = 'vc_' . Str::random(20);
$call = VoiceCall::create([
'caller_id' => $caller->id,
'callee_id' => $callee->id,
'channel_name' => $channelName,
'status' => 'ringing',
]);
$callerToken = AgoraTokenService::generateToken($channelName, $caller->id);
$calleeToken = AgoraTokenService::generateToken($channelName, $callee->id);
return response()->json([
'call_id' => $call->id,
'channel_name' => $channelName,
'token' => $callerToken,
'callee' => [
'id' => $callee->id,
'name' => $callee->name,
'avatar' => $callee->avatar ? \App\Support\MediaUrl::fromStoragePath($callee->avatar) : null,
],
'agora_app_id' => env('AGORA_APP_ID', ''),
]);
}
public function answer(VoiceCall $call)
{
$user = Auth::user();
abort_unless($call->callee_id === $user->id, 403);
abort_unless($call->status === 'ringing', 422, 'Call is no longer ringing.');
$call->update(['status' => 'active', 'answered_at' => now()]);
$token = AgoraTokenService::generateToken($call->channel_name, $user->id);
return response()->json([
'channel_name' => $call->channel_name,
'token' => $token,
'agora_app_id' => env('AGORA_APP_ID', ''),
'caller' => [
'id' => $call->caller->id,
'name' => $call->caller->name,
'avatar' => $call->caller->avatar ? \App\Support\MediaUrl::fromStoragePath($call->caller->avatar) : null,
],
]);
}
public function decline(VoiceCall $call)
{
$user = Auth::user();
abort_unless($call->callee_id === $user->id || $call->caller_id === $user->id, 403);
abort_unless($call->status === 'ringing', 422);
$call->update(['status' => 'declined', 'ended_at' => now()]);
return response()->json(['ok' => true]);
}
public function end(VoiceCall $call)
{
$user = Auth::user();
abort_unless($call->callee_id === $user->id || $call->caller_id === $user->id, 403);
$call->update(['status' => 'ended', 'ended_at' => now()]);
return response()->json(['ok' => true]);
}
public function poll(Request $request)
{
$user = Auth::user();
// Check for incoming ringing call
$incoming = VoiceCall::where('callee_id', $user->id)
->where('status', 'ringing')
->with('caller')
->latest()
->first();
if ($incoming) {
return response()->json([
'type' => 'incoming',
'call_id' => $incoming->id,
'caller' => [
'id' => $incoming->caller->id,
'name' => $incoming->caller->name,
'avatar' => $incoming->caller->avatar ? \App\Support\MediaUrl::fromStoragePath($incoming->caller->avatar) : null,
],
]);
}
// Check if an active call we're in has been ended by the other side
$call_id = $request->query('call_id');
if ($call_id) {
$call = VoiceCall::find($call_id);
if ($call && in_array($user->id, [$call->caller_id, $call->callee_id])) {
return response()->json([
'type' => 'status',
'status' => $call->status,
]);
}
}
return response()->json(['type' => 'none']);
}
}