Hi I am trying to build a laravel real time chat. I configured websockets and it seems to be connecting, but now I am trying to send a message and its working but to the other user the message is not displayed unless I refresh the page. I was following a tutorial in youtube did everything like in the tutorial and I dont know why I am receiving this errors. If you can have a look I would appreciate it.
Errors I am receiving
DevTools failed to load SourceMap: Could not load content for http://127.0.0.1:8000/js/utf8.js.map: HTTP error: status code 404, net::ERR_HTTP_RESPONSE_CODE_FAILURE
ChatsComponent.vue
<template>
<div class="row">
<div class="col-8">
<div class="card card-default">
<div class="card-header">Messages</div>
<div class="card-body p-0">
<ul class="list-unstyled" style="height:300px; overflow-y:scroll">
<li class="p-2" v-for="(message,index) in messages" :key="index">
<strong>{{ message.user.name }}</strong>
{{ message.message }}
</li>
</ul>
</div>
<input
#keyup.enter="sendMessage"
v-model="newMessage"
type="text"
name="message"
placeholder="Enter your message..."
class="form-control">
</div>
<span class="text-muted">User is typing...</span>
</div>
<div class="col-4">
<div class="card card-default">
<div class="card-header">Active Users</div>
<div class="card-body">
<ul>
<li class="py-2">Harish</li>
</ul>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
props:['user'],
data(){
return {
messages:[],
newMessage:'',
}
},
created(){
this.fetchMessages();
Echo.join('chat')
.listen('MessageSent', (event) => {
this.messages.push(event.message);
});
},
methods:{
fetchMessages(){
axios.get('messages').then(response =>{
this.messages = response.data
})
},
sendMessage(){
this.messages.push({
user:this.user,
message:this.newMessage
});
axios.post('messages', {message: this.newMessage});
this.newMessage='';
}
}
}
</script>
Message Model
class Message extends Model
{
/**
* The attributes that should be cast to native types.
*
* #var array
*/
protected $fillable = ['message'];
public function user()
{
return $this->belongsTo(User::class);
}
}
And I added this to User model
public function messages()
{
return $this->hasMany(Message::class);
}
ChatsController
use Illuminate\Http\Request;
use App\Message;
use App\Events\MessageSent;
class ChatsController extends Controller
{
public function _construct(){
$this->middleware('auth');
}
public function index()
{
return view('chats');
}
public function fetchMessages()
{
return Message::with('user')->get();
}
public function sendMessages(Request $request)
{
$message = auth()->user()->messages()->create([
'message' => $request->message
]);
broadcast(new MessageSent($message->load('user')))->toOthers();
return ['status' =>'success'];
}
}
MessageEvent event
App\Message; use App\User;
class MessageSent implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $message;
/**
* Create a new event instance.
*
* #return void
*/
public function __construct(Message $message)
{
$this->message = $message;
}
/**
* Get the channels the event should broadcast on.
*
* #return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new PresenceChannel('chat');
}
}
Routes
Route::get('/chats','ChatsController#index')->middleware('auth');
Route::get('/messages','ChatsController#fetchMessages');
Route::post('/messages','ChatsController#sendMessages');
Broadcast::channel('chat', function ($user) {
return $user;
});
Chat view
#extends('layouts.app')
#section('content')
<div class="container">
<chats :user="{{ auth()->user()}}"></chats>
</div>
#endsection
Related
I'm trying to call a variable from a table, but I'm getting an error "Undefined variable $user". I'm trying to make the program display the Username from the user from the table.
I'm using 2 tables, tribes which represents something like a group, and a user which represents.. well.. user.
So I'm trying to connect the two by displaying the creator of a certain "tribe".
User controller:
<?php
namespace App\Http\Controllers;
Use App\Models\User;
use Illuminate\Http\Request;
class tribesController extends Controller
{
public function index($user)
{
$user = User::findOrFail($user);
return view('home',[
'user'=>$user,
]);
}
}
Homepage:
#extends('layouts.app')
#section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">{{ __('Dashboard') }}</div>
<div class="card-body">
#if (session('status'))
<div class="alert alert-success" role="alert">
{{ session('status') }}
</div>
#endif
{{ $user->username }}
</div>
</div>
</div>
</div>
</div>
#endsection
Router:
<?php
use Illuminate\Support\Facades\Route;
/*
Route::get('/', function () {
return view('welcome');
});
Route::get('/home', function () {
return view('home');
});
Route::get('/playlist', function () {
return view('playlist');
});
Route::get('/tribe', function () {
return view('tribe');
});
Route::get('/edit', function () {
return view('edit');
});
Auth::routes();
Route::get('/tribe/{user}', [App\Http\Controllers\TribesController::class, 'index'])->name('tribe.index');
Database file:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateTribesTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('tribes', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('user_id');
$table->string('title');
$table->string('genre');
$table->string('filepath')->nullable();
$table->timestamps();
$table->index('user_id');
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('tribes');
}
}
model:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class tribe extends Model
{
public function user(){
return $this->belongsTo(User::class);
}
use HasFactory;
}
You are treating the url parameter as a object, it can't be an object until you get it. Pass in a user id and then query the ORM for a user matching that id then you can use it as an object!
I cannot get my events working on laravel 7.x, pusher, laravel-echo. I have set up everything correctly but still getting 401 error. I have also set up broadcast_driver as pusher in .env file. If anyone can help, I will appreciate.
CommentEvent.php
<?php
namespace App\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class CommentEvent implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $comment;
/**
* Create a new event instance.
*
* #return void
*/
public function __construct($comment)
{
$this->comment =$comment;
}
/**
* Get the channels the event should broadcast on.
*
* #return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new Channel('comment-channel');
}
public function broadcastAs()
{
return 'newComment';
}
}
CommentController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Events\CommentEvent;
use App\Comment;
class CommentController extends Controller
{
public function index(){
return view('comments');
}
public function fetchComments(){
$comments =Comment::all();
return response()->json($comments);
}
public function store(Request $request){
$comment =Comment::create($request->all());
event(new CommentEvent($comment));
return response()->json('ok');
}
}
/routes/channels.php
<?php
use Illuminate\Support\Facades\Broadcast;
/*
|--------------------------------------------------------------------------
| Broadcast Channels
|--------------------------------------------------------------------------
|
| Here you may register all of the event broadcasting channels that your
| application supports. The given channel authorization callbacks are
| used to check if an authenticated user can listen to the channel.
|
*/
// Broadcast::channel('App.User.{id}', function ($user, $id) {
// return (int) $user->id === (int) $id;
// });
Broadcast::channel('comment-channel', function () {
return true;
});
bootstrap.js
window._ = require('lodash');
try {
window.Popper = require('popper.js').default;
window.$ = window.jQuery = require('jquery');
require('bootstrap');
} catch (e) {}
window.axios = require('axios');
window.moment = require('moment');
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
window.axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
window.axios.defaults.headers.common.crossDomain = true;
// window.axios.defaults.baseURL = '/api';
let token = document.head.querySelector('meta[name="csrf-token"]');
if (token) {
window.axios.defaults.headers.common['X-CSRF-TOKEN'] = token.content;
} else {
console.error('CSRF token not found: https://adonisjs.com/docs/4.1/csrf');
}
import Echo from 'laravel-echo';
window.Pusher = require('pusher-js');
window.Echo = new Echo({
broadcaster: 'pusher',
key: process.env.MIX_PUSHER_APP_KEY,
cluster: process.env.MIX_PUSHER_APP_CLUSTER,
forceTLS: true
});
store.js
import Vue from 'vue';
import Vuex from 'vuex';
import axios from 'axios';
Vue.use(Vuex);
export const store =new Vuex.Store({
state:{
//stores all the comments in this array//
comments:[]
},
getters:{
//returns the comments array//
comments:state=>{
return state.comments
}
},
mutations:{
//populates the comments array in the state with the comments from the database//
getComments:(state,comments)=>{
state.comments =comments
},
addComment:(state,comment)=>{
state.comments = state.push(comment)
}
},
actions:{
/* gets all the comments from comments endpoint api*/
getComments:({commit})=>{
axios.get(`http://127.0.0.1:8000/api/comments`)
.then(res=>{
//commits getcomments mutation and passes a parameter of comments from the response//
commit('getComments',res.data)
})
.catch(err=>{
console.log(err)
})
},
addComment:({commit},comment)=>{
return new Promise((resolve,reject)=>{
axios.post(`http://127.0.0.1:8000/api/comments`,{
author:comment.author,
content:comment.content
})
.then(res=>{
resolve(res)
}).catch(err=>{
reject(err)
})
})
}
}
})
MainApp.vue
<template>
<div class="container">
<div class="row">
<div class="col">
<div class="card">
<div class="card-body">
<form #keyup.enter="postComment">
<div class="form-group">
<input type="text" class="form-control" placeholder="Author's Name" v-model="comment.author">
</div>
<div class="form-group">
<textarea name="comment" id="" rows="6" class="form-control" v-model="comment.content" >
</textarea>
</div>
<div class="form-group">
<input type="submit" value="Submit" class="btn btn-success" #click.prevent="postComment">
</div>
</form>
</div>
</div>
</div>
<div class="col">
<div class="card">
<div class="card-body">
<div class="media" v-for="comment in comments" :key="comment.id">
<img class="mr-3" src="https://api.adorable.io/avatars/48/#adorable.io.png" alt="Generic placeholder image">
<div class="media-body">
<h5>{{comment.author}}</h5>
{{comment.content}}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import {store} from '../store';
import {mapGetters} from 'vuex';
import {mapActions} from 'vuex';
export default {
store:store,
data:function(){
return{
comment:{
author:'',
content:''
}
}
},
mounted() {
//calls the action getcomments from store.js//
this.$store.dispatch('getComments');
Echo.channel('comment-channel')
.listen('.newComment', (e)=>{
console.log(e)
})
},
computed:{
//gets the comments array from store.js//
...mapGetters([
'comments'
])
},
methods:{
postComment:function(){
this.$store.dispatch('addComment',this.comment)
.then(res=>{
if(res==='ok'){
console.log('success')
}
}).catch(err=>{
console.log(err)
})
}
}
}
</script>
Make sure to pass $user into the channel route callback. replace this code with your channel route. then you are good to go :)
Broadcast::channel('comment-channel', function ($user) {
return true;
});
I am creating a chat in Laravel Websocket i followed a youtube tutorial and the message goes to the other user they can talk with each other but i need to reload the page to get the message that was sent,its not real time.At the console before i send a message it says this error: Failed to load resource: the server responded with a status of 404 (Not Found) and than after sending says this POST http://127.0.0.1:8000/broadcasting/auth 404 (Not Found) .I have run "php artisan websocket:serve" command in terminal.Thanks in advance
ChatsController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Message;
use App\Events\MessageSent;
class ChatsController extends Controller
{
public function __construct()
{
$this->middleware('auth');//only authenticated users can acces to chat
}
public function index()
{
return view('chats');
}
public function fetchMessages()
{
return Message::with('user')->get();
}
public function sendMessage(Request $request)
{
$message = auth()->user()->messages()->create([
'message' => $request->message
]);
broadcast(new MessageSent($message->load('user')))->toOthers();
return ['status' => 'success'];
}
}
User.php
public function messages()
{
return $this->hasMany(Message::class);
}
Message.php
public function user()
{
return $this->belongsTo(User::class);
}
web.php
<?php
use App\User;
use App\Department;
use App\Events\WebsocketDemoEvent;
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
Route::get('/', function () {
broadcast(new WebsocketDemoEvent('some data'));
return view('welcome');
});
Route::get('/page', function () {
return view('admin.page');
});
Auth::routes();
Route::get('/home', 'HomeController#index')->name('home');
Route::group(['middleware' => ['auth','admin']], function () {
Route::get('/role-register','Admin\DashboardController#registered');
Route::delete('/role-delete/{id}', 'Admin\DashboardController#registerdelete');//delete user
Route::post('/save-user', 'Admin\DashboardController#store');
Route::get('/department', 'Admin\DepartmentController#index');
Route::post('/save-department', 'Admin\DepartmentController#store');
Route::get('/department-edit/{id}', 'Admin\DepartmentController#edit');//edit department
Route::put('/department-update/{id}', 'Admin\DepartmentController#update');
Route::delete('/department-delete/{id}', 'Admin\DepartmentController#delete');//delete department
});
Auth::routes();
Route::get('/home', 'HomeController#index')->name('home');
Route::get('/chats', 'ChatsController#index');//chats
Route::get('/messages', 'ChatsController#fetchMessages');//messages
Route::post('/messages', 'ChatsController#sendMessage');//messages
Route::get('/dashboard', 'Admin\DashboardController#dbcheck');//DATABASE
Route::get('/user-edit/{id}', 'HomeController#registeredit');
Route::get('/role-edit/{id}', 'Admin\DashboardController#registeredit');//edit user
Route::put('/role-register-update/{id}', 'Admin\DashboardController#registerupdate');
Auth::routes();
Route::get('/home', 'HomeController#index')->name('home');
Route::get('store_image', 'StoreImageController#index');
Route::post('store_image/insert_image', 'StoreImageController#insert_image');
Route::get('store_image/fetch_image/{id}', 'StoreImageController#fetch_image');
Route::get('/page',array('as'=>'jquery.treeview','uses'=>'Admin\DepartmentController#treeView'));
Route::get('/pageusers', 'Admin\DepartmentController#usersdep');
ChatsComponent.vue
<template>
<div class="row">
<div class="col-8">
<div class="card card-default">
<div class="card-header">Messages</div>
<div class="card-body p-0">
<ul class="list-unstyled" style="height:300px; overflow-y:scroll">
<li class="p-2" v-for="(message, index) in messages" :key="index">
<strong>{{ message.user.name }}</strong>
{{ message.message }}
</li>
</ul>
</div>
<input
#keyup.enter="sendMessage"
v-model="newMessage"
type="text"
name="message"
placeholder="Enter your message"
class="form-control">
</div>
<span class="text-muted">user is typing...</span>
</div>
<div class="col-4">
<div class="card card-default">
<div class="card-header">Active Users</div>
<div class="card-body">
<ul>
<li class="py-2">{{ user.name }}</li>
</ul>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
props:['user'],
data() {
return {
messages: [],
newMessage:''
}
},
created() {
this.fetchMessages();
Echo.join('chat')
.listen('MessageSent',(event) => {
this.messages.push(event.message);
})
},
methods: {
fetchMessages() {
axios.get('messages').then(response => {
this.messages = response.data;
})
},
sendMessage(){
this.messages.push({
user: this.user,
message: this.newMessage
});
axios.post('messages', {message: this.newMessage});
this.newMessage = '';
}
}
}
</script>
MessageSent.php
<?php
namespace App\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Queue\SerializesModels;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use App\Message;
class MessageSent implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $message;
/**
* Create a new event instance.
*
* #return void
*/
public function __construct(Message $message)
{
$this->message = $message;
}
/**
* Get the channels the event should broadcast on.
*
* #return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new PresenceChannel('chat');
}
}
Sorry to post this as an answer, but you need 50 reputation to place a comment.
Did you uncomment the App\Providers\BroadcastServiceProvider::class, line in your config/app.php?
I am building one to one chat with laravel and pusher.I am trying to send event only to the person one is talking to but not able to do so.Event is send to all ,don't know what is the issue.
<ul class="list" id="friend">
#foreach(Auth::user()->friends() as $f)
<li data-friend="{{$f->id}}" class="clearfix" style="cursor: pointer">
<img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/195612/chat_avatar_01.jpg" alt="avatar" />
<div class="about">
<div class="name">{{$f->firstname}}</div>
<div class="status">
<i class="fa fa-circle online"></i> online
</div>
</div>
</li>
#endforeach
</ul>
textarea:
<div class="chat-message clearfix">
<textarea name="message-to-send" id="message-to-send" placeholder ="Type your message" rows="3"></textarea>
<i class="fa fa-file-o"></i>
<i class="fa fa-file-image-o"></i>
<button id="send" data-userid="{{Auth::user()->id}}">Send</button>
</div>
script:
<script>
b={!!json_encode(Auth::user()->id)!!};
pusher=new Pusher('******',{
cluster:'ap1'
});
channel=pusher.subscribe('user'+b);
$(document).ready(function(){
$('#friend li').click(function(){
var f=$(this).attr('data-friend');
$('#send').click(function(){
var userid=$(this).attr('data-userid');
var message=$('#message-to-send').val();
$.ajax({
method:'GET',
url:'/chat2/'+message+'/'+f,
success:function(response){
console.log('dshfgjhgdhjs');
}
})
});
});
});
channel.bind('App\\Events\\chat2', function(e){
console.log(e);
} );
</script>
route:
Route::get('/chat2/{message}/{friend}',function($message,$friend){
event(new chat2(Auth::user(),$message,$friend));
});
event:
class chat2 implements ShouldBroadcast
{
use InteractsWithSockets, SerializesModels;
public $user;
public $message;
public $friend;
/**
* Create a new event instance.
*
* #return void
*/
public function __construct(User $user,$message,$friend)
{
$this->user=$user;
$this->message=$message;
$this->friend=$friend;//
}
/**
* Get the channels the event should broadcast on.
*
* #return Channel|array
*/
public function broadcastOn()
{
return new Channel('user'.$this->friend);
}
}
You need to look at private broadcast channels. Laravel supports authenticated private channels for broadcast events.
https://laravel.com/docs/5.4/broadcasting#authorizing-channels
Once you have the user listening on a private channel, you can send events only to that channel.
I would like to provide the functionality to change his/her password on his/her own on my web application but I found the error addressed on the title so can anyone help me to solve this?
url:
http://nuatthai.loc/auth/password
routing:
Route::post('auth/password', ['as' => 'auth.postPassword', 'uses' => 'PasswordController#postPassword']);
Route::get('auth/password', ['as' => 'auth.prePassword', 'uses' => 'PasswordController#prePassword']);
Controller:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Validator;
use Mail;
use App\Role;
use App\User;
use App\Http\Controllers\Controller;
class PasswordController extends Controller
{
use ResourceController;
public function __construct()
{
$this->middleware('role:' . Role::ADMIN + Role::OWNER + Role::MANAGER + Role::ACCOUNTANT);
}
protected function validator(array $data)
{
return Validator::make($data, [
'password' => 'required|confirmed|min:8',
]);
}
private function updateData(Request $request)
{
$user = User::find($this::getMyId());
$user->password = $request->input('password');
$user->remember_token = str_random(60);
$user->save();
return $user;
}
public function prePassword()
{
return view('auth.change');
}
public function postPassword($request)
{
$validator = $this->validator($request->all());
if ($validator->fails()) {
\Session::flash('flash_error', $validator->messages());
$this->throwValidationException(
$request, $validator
);
}
$this::updateData($request);
}
}
view:
{{-- resources/views/auth/change.blade.php --}}
#extends('common.layout')
#section('header') #parent #endsection
#section('navbar') #include('common.navbar') #endsection
#section('sidebar') #include('common.sidebar') #endsection
#section('content')
<div class="panel panel-default">
<div class="panel-heading">Login</div>
<div class="panel-body">
#if (count($errors) > 0)
<div class="alert alert-danger">
<strong>Whoops!</strong> There were some problems with your input.<br><br>
<ul>
#foreach ($errors->all() as $error)
<li>{{ $error }}</li>
#endforeach
</ul>
</div>
#endif
{!! Form::open(array('action' => ['PasswordController#postPassword'], 'class' => 'form-horizontal')) !!}
<div class="form-group">
<label class="col-md-4 control-label input-lg">Password</label>
<div class="col-md-6">
<input type="password" class="form-control input-lg" name="password">
</div>
</div>
<div class="form-group">
<label class="col-md-4 control-label input-lg">Confirm Password</label>
<div class="col-md-6">
<input type="password" class="form-control input-lg" name="password_confirmation">
</div>
</div>
<div class="form-group">
<div class="col-md-6 col-md-offset-4">
<button type="submit" class="btn btn-primary btn-lg" style="margin-right: 15px;">
Reset Password
</button>
</div>
</div>
</form>
</div><!-- .panel-body -->
</div><!-- .panel --> #endsection
{{-- resources/views/auth/change.blade.php --}}
middleware:
<?php
namespace App\Http\Middleware;
use Closure;
use App\Role;
use App\UserRole;
class RoleMiddleware
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next, $mode)
{
if(!\Auth::check()) {
// session expired.
return redirect()->guest('auth/login');
}
else {
$admin = $mode & Role::ADMIN;
$owner = $mode & Role::OWNER;
$manager = $mode & Role::MANAGER;
$accountant = $mode & Role::ACCOUNTANT;
$type = \Auth::user()->role->type;
if(($admin) && ($type == Role::ADMIN)) {
return $next($request);
}
if(($owner) && ($type == Role::OWNER)) {
return $next($request);
}
if(($manager) && ($type == Role::MANAGER)) {
return $next($request);
}
if(($accountant) && ($type == Role::ACCOUNTANT)) {
return $next($request);
}
return response('Access Denied.', 403);
}
}
}
Role:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use App\Http\Controllers\ResourceController;
class Role extends Model
{
use ResourceController;
const TABLE = 'common_roles';
const ROLE_ID = 'role_id';
const ROLE_TYPE = 'type';
const TABLE_ROLE_ID = self::TABLE . '.' . self::ROLE_ID;
const TABLE_ROLE_TYPE = self::TABLE . '.' . self::ROLE_TYPE;
protected $table = self::TABLE;
protected $primaryKey = self::ROLE_ID;
const ADMIN = 0b1000; // 8
const OWNER = 0b100; // 4
const MANAGER = 0b10; // 2
const ACCOUNTANT = 0b1; // 1
public function users()
{
return $this->hasMany('App\User');
}
}
I really appreciate of any suggestions and advices in advance.