Skip to content

Commit a8535a4

Browse files
committed
websocket - chat added
1 parent 026ea7b commit a8535a4

File tree

13 files changed

+288
-23
lines changed

13 files changed

+288
-23
lines changed

app/Events/MessageSent.php

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php
2+
3+
namespace App\Events;
4+
5+
use App\Models\User;
6+
use Illuminate\Broadcasting\Channel;
7+
use Illuminate\Broadcasting\InteractsWithSockets;
8+
use Illuminate\Broadcasting\PresenceChannel;
9+
use Illuminate\Broadcasting\PrivateChannel;
10+
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
11+
use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow;
12+
use Illuminate\Foundation\Events\Dispatchable;
13+
use Illuminate\Queue\SerializesModels;
14+
15+
class MessageSent implements ShouldBroadcastNow
16+
{
17+
use Dispatchable, InteractsWithSockets, SerializesModels;
18+
19+
/**
20+
* Create a new event instance.
21+
*/
22+
public $receiver;
23+
public $sender;
24+
public $message;
25+
26+
public function __construct($receiver, $sender, $message)
27+
{
28+
$this->receiver = [
29+
'id' => $receiver->id,
30+
'name' => $receiver->name,
31+
'role' => $receiver->role,
32+
];
33+
34+
$this->sender = [
35+
'id' => $sender->id,
36+
'name' => $sender->name,
37+
'role' => $sender->role,
38+
];
39+
40+
$this->message = $message;
41+
}
42+
43+
/**
44+
* Get the channels the event should broadcast on.
45+
*/
46+
public function broadcastOn(): Channel
47+
{
48+
return new PrivateChannel('chat.' . $this->receiver['id']);
49+
}
50+
}

app/Http/Controllers/API/Auth/_Auth.php

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,25 +22,29 @@ public function login(Request $request)
2222

2323
$user = User::where('email', $request->email)->first();
2424

25-
if (! $user || ! Hash::check($request->password, $user->password)) {
26-
// throw ValidationException::withMessages([
27-
// 'email' => ['The provided credentials are incorrect.'],
28-
// ]);
25+
if (!$user || !Hash::check($request->password, $user->password)) {
2926
return response()->json([
30-
'code'=> 201,
27+
'status' => 401,
3128
'type' => 'error',
3229
'title' => 'Feedback 👋',
3330
'message' => '❌ The provided credentials are incorrect'
3431
]);
3532
}
3633

3734
return [
38-
'user' => $user,
39-
'token' => $user->createToken('login-token')->plainTextToken
35+
'status' => 200,
36+
'type' => 'success',
37+
'title' => 'Feedback 👋',
38+
'message' => '✅ Everything is ok',
39+
'data' => [
40+
'user' => $user,
41+
'token' => $user->createToken('login-token')->plainTextToken
42+
43+
]
4044
];
4145
} catch (\Throwable $th) {
4246
return response()->json([
43-
'code'=> 500,
47+
'status' => 500,
4448
'type' => 'error',
4549
'title' => 'Feedback 👋',
4650
'message' => '❌ Internal server error'
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<?php
2+
3+
namespace App\Http\Controllers\API;
4+
5+
use App\Events\MessageSent;
6+
7+
use App\Http\Controllers\Controller;
8+
use App\Models\ChatMessage;
9+
use App\Models\User;
10+
11+
use Illuminate\Database\Eloquent\Collection;
12+
use Illuminate\Http\Request;
13+
use Illuminate\Http\Response;
14+
15+
class ChatMessageController extends Controller
16+
{
17+
/**
18+
* Store a newly created resource in storage.
19+
*/
20+
public function store(Request $request): Response
21+
{
22+
$validatedData = $request->validate([
23+
'user_id' => 'required|exists:users,id',
24+
'from' => 'required|exists:users,id',
25+
'message' => 'required|string',
26+
]);
27+
28+
$message = ChatMessage::create($validatedData);
29+
$receiver = User::find($request->user_id);
30+
$sender = User::find($request->from);
31+
32+
// broadcast(new MessageSent($receiver, $sender, $request->message));
33+
MessageSent::dispatch($receiver, $sender, $message);
34+
35+
return response([
36+
'status' => 200,
37+
'type' => 'success',
38+
'title' => 'Feedback 👋',
39+
'message' => '✅ message sent',
40+
'data' => [
41+
'sender' => $sender,
42+
'message' => $message,
43+
'receiver' => $receiver
44+
]
45+
]);
46+
}
47+
48+
/**
49+
* Get the messages for the user along with messages count.
50+
*/
51+
public function getUnreadMessages(Request $request): Collection
52+
{
53+
return ChatMessage::with('from')->where('user_id', $request->user_id)
54+
->get();
55+
}
56+
}

app/Models/ChatMessage.php

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
namespace App\Models;
4+
5+
use App\Models\Scopes\ChatMessageScope;
6+
use Illuminate\Database\Eloquent\Attributes\ScopedBy;
7+
use Illuminate\Database\Eloquent\Factories\HasFactory;
8+
use Illuminate\Database\Eloquent\Model;
9+
use Illuminate\Database\Eloquent\Relations\BelongsTo;
10+
11+
#[ScopedBy([ChatMessageScope::class])]
12+
class ChatMessage extends Model
13+
{
14+
use HasFactory;
15+
16+
/**
17+
* The attributes that are mass assignable.
18+
*
19+
* @var array<int, string>
20+
*/
21+
protected $fillable = [
22+
'user_id',
23+
'from',
24+
'message',
25+
];
26+
27+
public function user(): BelongsTo
28+
{
29+
return $this->belongsTo(User::class);
30+
}
31+
32+
public function from(): BelongsTo
33+
{
34+
return $this->belongsTo(User::class, 'from');
35+
}
36+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
namespace App\Models\Scopes;
4+
5+
use Illuminate\Database\Eloquent\Builder;
6+
use Illuminate\Database\Eloquent\Model;
7+
use Illuminate\Database\Eloquent\Scope;
8+
use Illuminate\Support\Facades\Auth;
9+
10+
class ChatMessageScope implements Scope
11+
{
12+
/**
13+
* Apply the scope to a given Eloquent query builder.
14+
*/
15+
public function apply(Builder $builder, Model $model): void
16+
{
17+
$builder->where('user_id', Auth::id());
18+
}
19+
}

bootstrap/app.php

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,16 @@
66

77
return Application::configure(basePath: dirname(__DIR__))
88
->withRouting(
9-
web: __DIR__.'/../routes/web.php',
10-
api: __DIR__.'/../routes/api.php',
11-
commands: __DIR__.'/../routes/console.php',
12-
channels: __DIR__.'/../routes/channels.php',
9+
web: __DIR__ . '/../routes/web.php',
10+
api: __DIR__ . '/../routes/api.php',
11+
commands: __DIR__ . '/../routes/console.php',
12+
// channels: __DIR__.'/../routes/channels.php',
1313
health: '/up',
1414
)
15+
->withBroadcasting(
16+
__DIR__ . '/../routes/channels.php',
17+
['prefix' => 'api', 'middleware' => ['api', 'auth:sanctum']],
18+
)
1519
->withMiddleware(function (Middleware $middleware) {
1620
//
1721
})

config/cors.php

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
3+
return [
4+
5+
/*
6+
|--------------------------------------------------------------------------
7+
| Cross-Origin Resource Sharing (CORS) Configuration
8+
|--------------------------------------------------------------------------
9+
|
10+
| Here you may configure your settings for cross-origin resource sharing
11+
| or "CORS". This determines what cross-origin operations may execute
12+
| in web browsers. You are free to adjust these settings as needed.
13+
|
14+
| To learn more: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
15+
|
16+
*/
17+
18+
'paths' => ['api/*', 'sanctum/csrf-cookie'],
19+
20+
'allowed_methods' => ['*'],
21+
22+
'allowed_origins' => ['*'],
23+
24+
'allowed_origins_patterns' => [],
25+
26+
'allowed_headers' => ['*'],
27+
28+
'exposed_headers' => [],
29+
30+
'max_age' => 0,
31+
32+
'supports_credentials' => true,
33+
34+
];

database/migrations/0001_01_01_000000_create_users_table.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ public function up(): void
1313
{
1414
Schema::create('users', function (Blueprint $table) {
1515
$table->id();
16+
$table->string('role');
1617
$table->string('name');
1718
$table->string('email')->unique();
1819
$table->timestamp('email_verified_at')->nullable();
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
use Illuminate\Database\Migrations\Migration;
4+
use Illuminate\Database\Schema\Blueprint;
5+
use Illuminate\Support\Facades\Schema;
6+
7+
return new class extends Migration
8+
{
9+
/**
10+
* Run the migrations.
11+
*/
12+
public function up(): void
13+
{
14+
Schema::create('chat_messages', function (Blueprint $table) {
15+
$table->id();
16+
$table->foreignId('user_id')->constrained();
17+
$table->integer('from');
18+
$table->text('message');
19+
$table->timestamps();
20+
});
21+
}
22+
23+
/**
24+
* Reverse the migrations.
25+
*/
26+
public function down(): void
27+
{
28+
Schema::dropIfExists('chat_messages');
29+
}
30+
};

database/seeders/DatabaseSeeder.php

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use App\Models\User;
66
// use Illuminate\Database\Console\Seeds\WithoutModelEvents;
7+
use Illuminate\Support\Str;
78
use Illuminate\Database\Seeder;
89
use Illuminate\Support\Facades\Hash;
910

@@ -14,12 +15,27 @@ class DatabaseSeeder extends Seeder
1415
*/
1516
public function run(): void
1617
{
18+
$roles = [
19+
'Software Engineer', 'DevOps', 'Database Analyst', 'Cyber Security Consultant', 'Project Manager',
20+
'System Architect', 'QA Engineer', 'Product Owner', 'UI/UX Designer', 'Scrum Master'
21+
];
22+
shuffle($roles);
23+
24+
foreach ($roles as $role) {
25+
User::create([
26+
'name' => fake()->name(),
27+
'role' => $role,
28+
'email' => fake()->unique()->safeEmail(),
29+
'email_verified_at' => now(),
30+
'password' => Hash::make('password'),
31+
'remember_token' => Str::random(10),
32+
]);
33+
}
1734
// User::factory(10)->create();
1835

19-
User::factory()->create([
20-
'name' => 'Test User',
21-
'email' => '[email protected]',
22-
'password' => Hash::make('password'),
23-
]);
36+
// User::factory()->create([
37+
// 'name' => 'Test User',
38+
// 'email' => '[email protected]',
39+
// ]);
2440
}
2541
}

0 commit comments

Comments
 (0)