Channel
This commit is contained in:
37
app/Events/Conversation/MessageSent.php
Normal file
37
app/Events/Conversation/MessageSent.php
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Events\Conversation;
|
||||||
|
|
||||||
|
use Illuminate\Broadcasting\Channel;
|
||||||
|
use Illuminate\Broadcasting\InteractsWithSockets;
|
||||||
|
use Illuminate\Broadcasting\PrivateChannel;
|
||||||
|
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
|
||||||
|
use Illuminate\Foundation\Events\Dispatchable;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
|
||||||
|
class MessageSent implements ShouldBroadcast
|
||||||
|
{
|
||||||
|
use Dispatchable, InteractsWithSockets, SerializesModels;
|
||||||
|
|
||||||
|
public $message;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new event instance.
|
||||||
|
*/
|
||||||
|
public function __construct($message)
|
||||||
|
{
|
||||||
|
$this->message = $message->load('user');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the channels the event should broadcast on.
|
||||||
|
*
|
||||||
|
* @return array<int, Channel>
|
||||||
|
*/
|
||||||
|
public function broadcastOn(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
new PrivateChannel('chat.'.$this->message->conversation_id),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,7 +20,7 @@ class CollectionController extends Controller
|
|||||||
{
|
{
|
||||||
return response()->rest(
|
return response()->rest(
|
||||||
CollectionResource::collection(
|
CollectionResource::collection(
|
||||||
Collection::with('media')->where('is_visible', true)->ordered()->get()
|
Collection::query()->with('media')->where('is_visible', true)->inRandomOrder()->get()
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -34,7 +34,7 @@ class CollectionController extends Controller
|
|||||||
|
|
||||||
return response()->rest_paginate(
|
return response()->rest_paginate(
|
||||||
CollectionResource::collection(
|
CollectionResource::collection(
|
||||||
Collection::with('media')->where('is_visible', true)->ordered()->simplePaginate($perPage)
|
Collection::query()->with('media')->where('is_visible', true)->inRandomOrder()->simplePaginate($perPage)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ namespace App\Http\Controllers\Api\V1\Filters;
|
|||||||
|
|
||||||
use App\Http\Controllers\Api\V1\Filters\Requests\FilterIndexRequest;
|
use App\Http\Controllers\Api\V1\Filters\Requests\FilterIndexRequest;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\Ecommerce\Channel\Channel;
|
||||||
use App\Models\Ecommerce\Product\Brand\Brand;
|
use App\Models\Ecommerce\Product\Brand\Brand;
|
||||||
use App\Models\Ecommerce\Product\Category\Category;
|
use App\Models\Ecommerce\Product\Category\Category;
|
||||||
use App\Models\Ecommerce\Product\Collection\Collection;
|
use App\Models\Ecommerce\Product\Collection\Collection;
|
||||||
@@ -51,6 +52,10 @@ class FilterController extends Controller
|
|||||||
return $this->filterByCategoryResource(Brand::find($this->request->brand_id));
|
return $this->filterByCategoryResource(Brand::find($this->request->brand_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($this->shouldFilterByChannel()) {
|
||||||
|
return $this->filterByCategoryResource(Channel::find($this->request->channel_id));
|
||||||
|
}
|
||||||
|
|
||||||
return Category::query()->where('is_visible', true)->ordered()->get(['id', 'parent_id', 'name']);
|
return Category::query()->where('is_visible', true)->ordered()->get(['id', 'parent_id', 'name']);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,4 +132,12 @@ class FilterController extends Controller
|
|||||||
{
|
{
|
||||||
return $this->request->filled('brand_id');
|
return $this->request->filled('brand_id');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if request should be filtered by channel
|
||||||
|
*/
|
||||||
|
private function shouldFilterByChannel(): bool
|
||||||
|
{
|
||||||
|
return $this->request->filled('channel_id');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ class FilterIndexRequest extends FormRequest
|
|||||||
'collection_id' => ['bail', 'nullable', 'int', 'exists:collections,id'],
|
'collection_id' => ['bail', 'nullable', 'int', 'exists:collections,id'],
|
||||||
'category_id' => ['bail', 'nullable', 'int', 'exists:categories,id'],
|
'category_id' => ['bail', 'nullable', 'int', 'exists:categories,id'],
|
||||||
'brand_id' => ['bail', 'nullable', 'int', 'exists:brands,id'],
|
'brand_id' => ['bail', 'nullable', 'int', 'exists:brands,id'],
|
||||||
|
'channel_id' => ['bail', 'nullable', 'int', 'exists:channels,id'],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
65
app/Http/Controllers/ChatController.php
Normal file
65
app/Http/Controllers/ChatController.php
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Events\Conversation\MessageSent;
|
||||||
|
use App\Models\Chat\Conversation;
|
||||||
|
use App\Models\Chat\Message;
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class ChatController extends Controller
|
||||||
|
{
|
||||||
|
public function contacts()
|
||||||
|
{
|
||||||
|
return User::select(['id', 'first_name', 'last_name'])
|
||||||
|
->get()
|
||||||
|
->map(function ($user) {
|
||||||
|
return [
|
||||||
|
'id' => $user->id,
|
||||||
|
'name' => $user->first_name.' '.$user->last_name,
|
||||||
|
];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function start(Request $request)
|
||||||
|
{
|
||||||
|
$user1 = auth()->id();
|
||||||
|
$user2 = $request->user_id;
|
||||||
|
|
||||||
|
$conversation = Conversation::whereHas('users', fn ($q) => $q->where('user_id', $user1))
|
||||||
|
->whereHas('users', fn ($q) => $q->where('user_id', $user2))
|
||||||
|
->first();
|
||||||
|
|
||||||
|
if (! $conversation) {
|
||||||
|
$conversation = Conversation::create();
|
||||||
|
$conversation->users()->attach([$user1, $user2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $conversation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function messages($id)
|
||||||
|
{
|
||||||
|
return Message::with('user')
|
||||||
|
->where('conversation_id', $id)
|
||||||
|
->latest()
|
||||||
|
->take(50)
|
||||||
|
->get()
|
||||||
|
->reverse()
|
||||||
|
->values();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function send(Request $request)
|
||||||
|
{
|
||||||
|
$message = Message::create([
|
||||||
|
'conversation_id' => $request->conversation_id,
|
||||||
|
'user_id' => auth()->id(),
|
||||||
|
'body' => $request->body,
|
||||||
|
]);
|
||||||
|
|
||||||
|
broadcast(new MessageSent($message))->toOthers();
|
||||||
|
|
||||||
|
return $message->load('user');
|
||||||
|
}
|
||||||
|
}
|
||||||
22
app/Models/Chat/Conversation.php
Normal file
22
app/Models/Chat/Conversation.php
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models\Chat;
|
||||||
|
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class Conversation extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
public function users()
|
||||||
|
{
|
||||||
|
return $this->belongsToMany(User::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function messages()
|
||||||
|
{
|
||||||
|
return $this->hasMany(Message::class);
|
||||||
|
}
|
||||||
|
}
|
||||||
17
app/Models/Chat/Message.php
Normal file
17
app/Models/Chat/Message.php
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models\Chat;
|
||||||
|
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class Message extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
public function user()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(User::class);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('conversations', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('conversations');
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('conversation_user', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->foreignId('conversation_id')->constrained()->cascadeOnDelete();
|
||||||
|
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
|
||||||
|
$table->timestamps();
|
||||||
|
|
||||||
|
$table->unique(['conversation_id', 'user_id']);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('conversation_user');
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('messages', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->foreignId('conversation_id')->constrained()->cascadeOnDelete();
|
||||||
|
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
|
||||||
|
$table->text('body');
|
||||||
|
$table->timestamp('seen_at')->nullable();
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('messages');
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -101,6 +101,13 @@ Route::get('filters', [FilterController::class, 'index']);
|
|||||||
// Global orders...
|
// Global orders...
|
||||||
Route::post('global-order', [GlobalOrderController::class, 'store']);
|
Route::post('global-order', [GlobalOrderController::class, 'store']);
|
||||||
|
|
||||||
|
Route::middleware('auth:sanctum')->group(function () {
|
||||||
|
Route::get('/chat/contacts', [ChatController::class, 'contacts']);
|
||||||
|
Route::get('/chat/messages/{conversation}', [ChatController::class, 'messages']);
|
||||||
|
Route::post('/chat/start', [ChatController::class, 'start']);
|
||||||
|
Route::post('/chat/send', [ChatController::class, 'send']);
|
||||||
|
});
|
||||||
|
|
||||||
Route::middleware(['auth:sanctum', 'banned'])->group(function () {
|
Route::middleware(['auth:sanctum', 'banned'])->group(function () {
|
||||||
// Profile...
|
// Profile...
|
||||||
Route::get('profile', [ProfileController::class, 'index']);
|
Route::get('profile', [ProfileController::class, 'index']);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
use Illuminate\Support\Facades\Broadcast;
|
use Illuminate\Support\Facades\Broadcast;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
@@ -12,3 +13,10 @@ use Illuminate\Support\Facades\Broadcast;
|
|||||||
| used to check if an authenticated user can listen to the channel.
|
| used to check if an authenticated user can listen to the channel.
|
||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
Broadcast::channel('chat.{conversationId}', function ($user, $conversationId) {
|
||||||
|
return DB::table('conversation_user')
|
||||||
|
->where('conversation_id', $conversationId)
|
||||||
|
->where('user_id', $user->id)
|
||||||
|
->exists();
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user