Pusher authentication not working as expected - laravel

I have made a project with Laravel and react. There is a react component defined for video chat. Video is working but I am having issues with presence_auth(), basically getting the error with response 500 ()
Call to undefined method Pusher\Pusher::presence_auth()
Following is my web routes file:
<?php
/*
|--------------------------------------------------------------------------
| 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 () {
return view('welcome');
});
Auth::routes();
Route::get('/home', 'HomeController#index')->name('home');
Route::post('/pusher/auth', 'HomeController#authenticate');
The HomeController where I am getting this error:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use \Pusher\Pusher;
class HomeController extends Controller
{
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('auth');
}
/**
* Show the application dashboard.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
return view('home');
}
public function authenticate(Request $request){
$socketId = $request->socket_id;
$channelName = $request->channel_name;
$pusher = new Pusher('7525d88e2baa6d08b175', 'c25081ca96b9033e941c', '523589', [
'cluster' => 'ap1',
'encrypted' => true
]);
$presence_data = ['name' => auth()->user()->name];
$key = $pusher->presence_auth($channelName, $socketId, auth()->id(), $presence_data);
return response($key);
}
}
And finally my App.js file with the components:
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import MediaHandler from '../MediaHandler';
import Pusher from 'pusher-js';
import Peer from 'simple-peer';
const APP_KEY = '7525d88e2baa6d08b175';
export default class App extends Component {
constructor(){
super();
this.state = {
hasMedia: false,
otherUserId: null
};
this.user = window.user;
this.user.stream = null;
this.peers = {};
this.mediaHandler = new MediaHandler();
this.setupPusher();
this.callTo = this.callTo.bind(this);
this.setupPusher = this.setupPusher.bind(this);
this.startPeer = this.startPeer.bind(this);
}
componentWillMount(){
this.mediaHandler.getPermissions()
.then((stream) => {
this.setState({hasMedia: true});
this.user.stream = stream;
try{
this.myVideo.srcObject = stream;
} catch(e) {
this.myVideo.src = URL.createObjectURL(stream);
}
this.myVideo.play();
})
}
setupPusher(){
this.pusher = new Pusher(APP_KEY, {
authEndpoint: '/pusher/auth',
cluster: 'ap1',
auth: {
params: this.user.id,
headers: {
'X-CSRF-Token': window.csrfToken
}
}
});
this.channel = this.pusher.subscribe('presence-video-channel');
this.channel.bind(`client-signal-${this.user.id}`, (signal) => {
let peer = this.peers[signal.userId];
if(peer == undefined){
this.setState({otherUserId: signal.userId});
peer = this.startPeer(signal.userId, false);
}
peer.signal(signal.data);
});
}
startPeer(userId, initiator = true){
const peer = new Peer({
initiator,
stream: this.user.stream,
trickle: false
});
peer.on('signal', (data) => {
this.channel.trigger(`client-signal-${userId}`, {
type: 'signal',
userId: this.user.id,
data: data
});
});
peer.on('stream', (stream) => {
try{
this.userVideo.srcObject = stream;
} catch(e) {
this.userVideo.src = URL.createObjectURL(stream);
}
this.userVideo.play();
});
peer.on('close', () => {
let peer = this.peers[userId];
if(peer != undefined){
peer.destroy();
}
this.peers[userId] = undefined;
});
return peer;
}
callTo(userId){
this.peers[userId] = this.startPeer(userId);
}
render() {
return (
<div className="App">
{[1,2,3,4].map((userId) => {
return this.user.id != userId ? <button key={userId} onClick={() => this.callTo(userId)}>Call {userId}</button> : null
})}
<div className="video-container">
<video className="my-video" ref={(ref) => {this.myVideo = ref;}}></video>
<video className="user-video" ref={(ref) => {this.userVideo = ref;}}></video>
</div>
</div>
);
}
}
if (document.getElementById('app')) {
ReactDOM.render(<App />, document.getElementById('app'));
}
Everything else is working fine interms of stream but for some reason, presence_auth() function is not being identified.

So I had the same issue and i was able to solve it. my pusher php client was pusher/pusher-php-server "~3.0". The presence_auth() method is not available in this version of the library. I had to use the latest library which is version 5 and it worked seemlessly without any further modification. I just update the to the latest version.

Related

DELETE 405 (Method Not Allowed) - Laravel with Axios

Basically i am trying to delete a row using axios, but i keep getting DELETE 405 (Method Not Allowed)
This is my api route for delete:
Route::delete('/vehicles/{id}', [VehiclesController::class, 'destroy']);
In the controller:
public function destroy($id)
{
$vehicleDelete = Vehicle::findOrFail($id);
$vehicleDelete->delete();
return response()->json([
"status" => true
], 200);
}
The button in the front-end:
<button class = 'btn btn-danger' onclick = "deleteBtn(${item.id})">Delete</button>
I tried using console.log to see if the i get the correct id and it does get the correct.
And here is the axios function:
const deleteBtn = (id) => {
axios.delete("api/vehicles/" + id)
.then(response => {
console.log(id);
})
}
After trying out almost everything here is the solution that i randomly came with:
API Route:
Route::delete('/vehicles/{id}', [VehiclesController::class, 'destroy']);
Destroy method in the controller:
public function destroy($id)
{
$vehicle = Vehicle::find($id);
if(!$vehicle) {
return response()->json(["error" => "Vehicle does not exist!!"]);
}
if($vehicle->delete()) {
return response()->json(["success" => "Vehicle deleted!!"]);
}
return response()->json(["error" => "Something bad happened!!"]);
}
front-end button:
<button class = 'btn btn-danger' onclick = "deleteBtn(${item.id})">Delete</button>
And finally, the javascript function:
const deleteBtn = (id) => {
axios.delete(API.url + (API.routes.deleteVehicles.replace("{id}", id)))
.then(response => {
vehicleTable.innerHTML = "";
drawVehicles();
})
}
For reference here is the API object:
const API = {
url: 'http://127.0.0.1:8000/api',
routes: {
getVehicles: '/vehicles',
deleteVehicles: '/vehicles/{id}',
createVehicles: '/vehicles'
}
}

How to solve SyntaxError: Unexpected token < in JSON at position 0 in Paypal checkout in Laravel

I am doing Paypal integration in Laravel. I have used composer require srmklive/paypal to install the srmklive/paypal package in this project.
When I press the PayPal button, I get this error:
Here is my code:
code from blade file:
paypal.Buttons({
createOrder: function(data, actions) {
return fetch('api/paypal/order/create/', {
method: 'post',
body:JSON.stringify({
"value":100
})
}).then(function(res) {
return res.json();
}).then(function(orderData) {
return orderData.id;
});
},
onApprove: function(data, actions) {
return fetch('/api/paypal/order/capture/', {
method: 'post',
body: JSON.stringify({
orderID: data.orderID
})
}).then(function(res) {
return res.json();
}).then(function(orderData) {
var errorDetail = Array.isArray(orderData.details) && orderData.details[0];
if (errorDetail && errorDetail.issue === 'INSTRUMENT_DECLINED') {
return actions.restart();
}
if (errorDetail) {
var msg = 'Sorry, your transaction could not be processed.';
return alert(msg); // Show a failure message (try to avoid alerts in production environments)
}
});
}
}).render('#paypal-button-container');
code from paymentController:
class PaymentController extends Controller
{
public function create(Request $request){
$data = json_decode($request->getContent(), true);
$provider = \PayPal::setProvider();
$provider->setApiCredentials(config('paypal'));
$token = $provider->getAccessToken();
$provider->setAccessToken($token);
$price = Plan::getSubscriptionPrice($data['value']);
$description = Plan::getSubscriptionDescription($data['value']);
$order = $provider->createOrder([
"intent" => "CAPTURE",
"purchase_units" => [
[
"amount" => [
"currency_code" => "USD",
"value" => $price
],
"description" => $description
]
]
]);
return response()->json($order);
}
public function capture(Request $request) {
$data = json_decode($request->getContent(), true);
$orderId = $data['orderID'];
$provider = \PayPal::setProvider();
$provider->setApiCredentials(config('paypal'));
$token = $provider->getAccessToken();
$provider->setAccessToken($token);
$result = $provider->capturePaymentOrder($orderId);
return response()->json($result);
}
}
How can I solve this error?
The route api/paypal/order/create/ is returning/outputting text that is not JSON, such as an HTML error page or something else that begins with an HTML tag.
The route must only output JSON, and must contain a valid id from the PayPal API.

How to create HTTP requests with axios from within V8Js

When running Axios in V8Js all requests fail as XMLHttpRequest is not available.
How can we make axios request work server side?
It's possible to bind PHP functions or classes to JavaScript with V8Js.
For example in PHP you can:
$v8 = new \V8Js();
$v8->sayHello = function($name) {
print('Hello ' . $name);
};
$js = 'PHP.sayHello('Bob')';
$v8->executeString($js);
When executed this will produce the string 'Hello Bob'.
So, know this we can create the XMLHttpRequest in PHP and then bind it to JS in the same way.
First we need to create the XMLHttpRequest class to actually make the requests. For this I'm using Guzzle.
<?php
namespace App\Http\Helpers;
use GuzzleHttp\Client;
class XMLHttpRequest
{
protected $url;
protected $method;
public $status;
public $statusText;
public $readyState;
public $responseData;
public $responseHeaders;
public $onreadystatechange;
public function open($method, $url)
{
$this->method = $method;
$this->url = $url;
}
public function send($data = '')
{
$headers = [];
// Here I am using a Laravel function to fetch the session id but this could be replaced
if($sessionId = request()->session()->getId()) {
// Set whatever auth values are needed for your application
$headers['Cookie'] = 'session=' . $sessionId;
}
$options = [
'http_errors' => false,
'headers' => $headers,
'body' => $data
];
$client = new Client();
$response = $client->request($this->method, $this->url, $options);
$this->responseHeaders = $response->getHeaders();
$this->responseData = (string) $response->getBody();
$this->status = $response->getStatusCode();
$this->readyState = 4;
$this->statusText = $response->getReasonPhrase();
if (is_callable($this->onreadystatechange)) {
call_user_func($this->onreadystatechange);
}
}
}
Then after creating a V8Js instance we can attach the new library:
$v8 = new \V8Js();
$v8->XMLHttpRequest = function () {
return new XMLHttpRequest;
};
Now we need to tell Axios to use our library. We can do this by first creating an adapter:
const XMLHttpRequest = PHP.XMLHttpRequest;
const adapter = (config) => {
return new Promise(function(resolve, reject) {
const xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = () => {
const response = {
data: xhttp.responseData,
status: xhttp.status,
statusText: xhttp.statusText,
headers: xhttp.responseHeaders,
config: config,
request: {}
};
settle(resolve, reject, response);
};
xhttp.open(config.method, config.baseURL + config.url);
xhttp.send();
})
}
And then adding an interceptor to set the adapter and the baseURL:
axios.interceptors.request.use(config => {
config.baseURL = 'https://YOUR-URL.com'
config.adapter = adapter
return config
})
After this using a normal axios.post will work server side.

Social Login with Angular 5 and Lumen 5.6

I am trying to implement social login with angular 5 as my front-end and lumen 5.6 as my backend.
I am using JWT Authentication system with Lumen.
So, I am confused here how I should implement social login system in this situation.
Through my research I have come to these libraries which can do that work, but I am not sure how the process is handled from the front-end (angular) to back-end (lumen).
For Angular 5 -
angularx-social-login OR Satellizer
For Lumen -
laravel/socialite
But as I have not found any documentation on Satellizer working with Angular 5, so I choosed to use other one.
I have read this article, but still the process from front-end to back-end is not clear to me.
https://medium.com/#barryvdh/oauth-in-javascript-apps-with-angular-and-lumen-using-satellizer-and-laravel-socialite-bb05661c0d5c
Any explanatory help ?
So the way I used social login with Angular 5 is with a package called
"angular5-social-login": "^1.0.9",
So add that to your package.json file.
Import it in app.module.ts
import { SocialLoginModule, AuthServiceConfig, GoogleLoginProvider, FacebookLoginProvider } from 'angular5-social-login';
Set up a function in app.module.ts
export function getAuthServiceConfigs() {
const config = new AuthServiceConfig(
[
{
id: FacebookLoginProvider.PROVIDER_ID,
provider: new FacebookLoginProvider('') // Left as i dont use it
},
{
id: GoogleLoginProvider.PROVIDER_ID,
provider: new GoogleLoginProvider('YOUR-API-TOKEN.apps.googleusercontent.com')
},
]
);
return config;
}
Add it to your Imports in app.module.ts
imports: [
HttpClientModule,
AppRoutingModule,
...
SocialLoginModule, // One we need to add
],
Then at the add it to your providers in app.module.ts
providers: [
YourServices,
...
ApiAuthService,
{
provide: AuthServiceConfig,
useFactory: getAuthServiceConfigs
},
LoggedInGuard,
],
As you can see i have a LoggedInGuard and a ApiAuthService these are these with the auth and checking your logged in.
So That's the package installed and set up...
Now inside of api-auth.service.ts add this function
socialSignIn(userData) {
const formData = new FormData();
formData.append('email', userData.email);
formData.append('name', userData.name);
formData.append('provider', userData.provider);
formData.append('id', userData.id);
formData.append('idToken', userData.idToken);
formData.append('token', userData.token);
formData.append('image', userData.image);
return this._http.post(
environment.apiUrl + '/auth/social-signin/',
formData,
{
headers: new Headers({
'Authorization': 'Bearer ' + userData.idToken
})
}
);
}
Now in your sign in component add this to the HTML
<div (click)="socialSignIn('google')" class="c2a_btn large google">
Log in with google
</div>
In your sign in component .ts file add this function
import { AuthService, FacebookLoginProvider, GoogleLoginProvider, LinkedinLoginProvider } from 'angular5-social-login';
import { ApiAuthService } from '../../../../services/api-auth.service';
import { TokenService } from '../../../../services/token.service';
public socialSignIn(socialPlatform: string) {
this.loading = true;
let socialPlatformProvider;
if (socialPlatform === 'facebook') {
socialPlatformProvider = FacebookLoginProvider.PROVIDER_ID;
} else if (socialPlatform === 'google') {
socialPlatformProvider = GoogleLoginProvider.PROVIDER_ID;
} else if (socialPlatform === 'linkedin') {
socialPlatformProvider = LinkedinLoginProvider.PROVIDER_ID;
}
this.socialAuthService.signIn(socialPlatformProvider).then(
(userData) => {
this._apiAuthService.socialSignIn(userData)
.map( data => {
return data.json();
})
.subscribe(
token => {
this._tokenService.setAccessToken(token.access_token);
},
error => {
this.invalidLogin = true;
this.loading = false;
},
() => {
this.loading = false;
this.closeSignIn.emit('out');
// this._router.navigate(['/profile']);
}
);
}
);
}
This is just the front end now for the back end. I'm using Laravel 5.6
But I made a function like this
public function socialSignIn(Request $request, Response $response) {
$date = date('Y-m-d h:i:s');
$provider = $request->input('provider');
if ($provider == 'google') {
$id_token = $request->header('Authorization');
$id_token = str_replace("Bearer ","",$id_token);
$CLIENT_ID = Config::get('google.client_id');
$email = $request->input('email');
$names = $request->input('name');
$name = explode(' ', $names);
$client = new \Google_Client();
$client->setDeveloperKey($CLIENT_ID);
$payload = $client->verifyIdToken($id_token);
if ($payload) {
if (User::where('email', '=', $email)->exists()) {
$user = User::Where('email', '=', $email)->first();
if(!Auth::loginUsingId($user->id)){
return response()->json([
'failed'
], 403);
}
$updateLastLoginDate = User::where('id', Auth::user()->id)-first();
$updateLastLoginDate->last_login_date = $date;
$updateLastLoginDate->save();
$activeAccount = Auth::user();
$activeAccount->active = '1';
$activeAccount->save();
} else {
$recordUser = New User;
$recordUser->email = $request->input('email');
$recordUser->last_login_date = $date;
$recordUser->save();
$recordLinkedSocialAcounts = new LSA;
$recordLinkedSocialAcounts->user_id = $recordUser->id;
$recordLinkedSocialAcounts->provider_name = $provider;
$recordLinkedSocialAcounts->provider_id = $request->input('id');
$recordLinkedSocialAcounts->save();
$recordUserInformation = new UPI;
$recordUserInformation->user_id = $recordUser->id;
$recordUserInformation->first_name = $name[0];
$recordUserInformation->last_name = $name[1];
$recordUserInformation->last_login_date = $date;
$recordUserInformation->image = $request->input('image');
$recordUserInformation->save();
if(!Auth::loginUsingId($recordUser->id)){
return response()->json([
'failed'
], 403);
}
}
return response()->json([
'access_token' => Auth::user()->createToken('access_token')->accessToken,
'role_id' => Auth::user()->role_id
], 200);
} else {
return response()->json([
'failed'
], 403);
}
}
}
I will most probably make a video on this soon. Any questions just ask

Phalcon: HMVC view not working

I got a problem rendering nested view, here is what I'm trying to do
I changed your 'request' of HMVC (HMVC-GitHub or/and HMVC-Pattern) function into an Elements module
namespace Modules\Main\Libraries;
/**
* Elements
*
* Helps to build UI elements for the application
*/
class Elements extends \Phalcon\Mvc\User\Component
{
public function loadModule($path = '', $data = array()) {
$di = clone $this->getDI();
$dispatcher = $di->get('dispatcher');
$paths = explode('/', $path);
$data = is_array($data) ? $data : array($data);
// get controller name
if (isset($paths[0])) {
$controller = $paths[0];
}
// get action name
if (isset($paths[1])) {
$action = $paths[1];
}
// get params
if (isset($paths[2])) {
array_splice($paths, 0, 2);
$params = array_merge($paths, $data);
} else {
$params = $data;
}
if (!empty($controller)) {
$dispatcher->setControllerName($controller);
} else {
$dispatcher->setControllerName('index');
}
if (!empty($action)) {
$dispatcher->setActionName($action);
} else {
$dispatcher->setActionName('index');
}
if (!empty($params)) {
if(is_array($params)) {
$dispatcher->setParams($params);
} else {
$dispatcher->setParams((array) $params);
}
} else {
$dispatcher->setParams(array());
}
$dispatcher->dispatch();
$response = $dispatcher->getReturnedValue();
if ($response instanceof ResponseInterface) {
return $response->getContent();
}
return $response;
}
}
and I have 2 controllers:
namespace Modules\Main\Controllers;
class IndexController extends ControllerBase
{
public function indexAction()
{
$secondContent = $this->elements->loadModule('test/hello/json');
$this->view->setVar('secondContent', $secondContent);
}
}
and
namespace Modules\Main\Controllers;
use \Phalcon\Http\Response;
class TestController extends ControllerBase
{
public function indexAction()
{
}
public function helloAction($format='html', $param = 'empty')
{
$this->view->setVar('content', 'Hello this is test value "'.$param.'"');
$content = $this->view->getContent();
return (string)$content;
// return 'Hello this is test value "'.$param.'"';
}
}
my DI
$di['elements'] = function() {
return new \Modules\Main\Libraries\Elements();
};
Views files
IndexController::Index
<h1>Congratulations!</h1>
<p>You're now flying with Phalcon. Great things are about to happen!</p>
<p>Second content: {{ secondContent}}</p>
<p>HMVC: {{ elements.loadModule('test/hello/json', 'test') }}</p>
and HelloController::test
This is :: {{ content }}
expecting to get
Congratulations!
You're now flying with Phalcon. Great things are about to happen!
Second content: This is :: Hello this is test value "empty"
HMVC: This is :: Hello this is test value "test"
but it only rendering the HelloController (First call from IndexController::indexAction):
This is :: Hello this is test value "empty"
if I change IndexController::indexAction to
public function indexAction()
{
$secondContent = '';
$this->view->setVar('secondContent', $secondContent);
}
and TestController::helloAction to
public function helloAction($format='html', $param = 'empty')
{
$this->view->setVar('content', 'Hello this is test value "'.$param.'"');
$content = $this->view->getContent();
//return (string) $content;
return 'Hello this is test value "'.$param.'"';
}
the result that i get is (Second content is empty):
Congratulations!
You're now flying with Phalcon. Great things are about to happen!
Second content:
HMVC: Hello this is test value "test"
Any solution to solve this ?
Thanks,
Helman
Phalcon have built-it modules feature, you dont have to built your own module loader, you just need create module bootstrap that extend ModuleDefinitionInterface.
Just take a look this sample from phalcon multi module
https://github.com/phalcon/mvc/tree/master/multiple
this example below is taken from link above, This contain module bootstrap code.
<?php
namespace Multiple\Frontend;
class Module
{
public function registerAutoloaders()
{
$loader = new \Phalcon\Loader();
$loader->registerNamespaces(array(
'Multiple\Frontend\Controllers' => '../apps/frontend/controllers/',
'Multiple\Frontend\Models' => '../apps/frontend/models/',
));
$loader->register();
}
/**
* Register the services here to make them general or register in the ModuleDefinition to make them module-specific
*/
public function registerServices($di)
{
//Registering a dispatcher
$di->set('dispatcher', function () {
$dispatcher = new \Phalcon\Mvc\Dispatcher();
//Attach a event listener to the dispatcher
$eventManager = new \Phalcon\Events\Manager();
$eventManager->attach('dispatch', new \Acl('frontend'));
$dispatcher->setEventsManager($eventManager);
$dispatcher->setDefaultNamespace("Multiple\Frontend\Controllers\\");
return $dispatcher;
});
//Registering the view component
$di->set('view', function () {
$view = new \Phalcon\Mvc\View();
$view->setViewsDir('../apps/frontend/views/');
return $view;
});
$di->set('db', function () {
return new \Phalcon\Db\Adapter\Pdo\Mysql(array(
"host" => "localhost",
"username" => "root",
"password" => "secret",
"dbname" => "invo"
));
});
}
}
you can load module using this code below
$app = new \Phalcon\Mvc\Application();
$app->registerModules(array(
'frontend' => array(
'className' => 'Multiple\Frontend\Module',
'path' => '../apps/frontend/Module.php'
),
'backend' => array(
'className' => 'Multiple\Backend\Module',
'path' => '../apps/backend/Module.php'
)
));

Resources