Laravel 419 Error using Ajax - ajax

Okay let me explain first. I am sending a PUT request using ajax like this:
//ajax function
$(document).on("click", ".question_no", function(){
current_color = rgb2hex($(this).css('background-color'));
q_index = $(this).attr('id').slice(5);
id_team_packet = $("#id_team_packet").val();
// startTimer();
if (current_color != '#ffc966') {
$(this).css('background-color', "#ffc966");
var status = "orange";
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
$.ajax({
url: '{{route('peserta.submit.ans.stat')}}',
method: 'put',
data: {q_index, id_team_packet},
success: function(data){
console.log(data)
}
})
}
})
NOTE I already have my CSRF token setup in my head, which I also include in my ajax setup as you can see below. It works great :). But once I protect that route with a Middleware, like this:
//middleware
public function handle($request, Closure $next)
{
if (Auth::user()) {
if (Auth::user()->role == 3) {
return $next($request);
}
if ($request->ajax()) {
return response()->json(['intended_url'=>'/'], 401);
}
return redirect('/');
}
if ($request->ajax()) {
return response()->json(['intended_url'=>'/'], 401);
}
return redirect('/');
}
//web.php
Route::middleware(['participant_only'])->group(function(){
Route::put('/peserta/submit-answer-status', 'PesertaController#submitAnsStat')->name('peserta.submit.ans.stat');
});
As you can see it only accepts logged in user with a role of '3'. If user tries to log in, it redirects to '/'. Now I also check if the request is using ajax, which I return a message with code 401. But unfortunately, when the middleware is applied and I ajax it, it returns this error:
message
exception Symfony\Component\HttpKernel\Exception\HttpException
file -\vendor\laravel\framework\src\Illuminate\Foundation\Exceptions\Handler.php
line 203
But if once I remove the middleware it works. I don't know where the problem is. Oh on another note, If I exclude that particular route from verifycsrftoken it returns the right response both with the middleware and without.
My question is, where is the problem and how do I fix it? Thank you :)

Related

Laravel: return data from server without redirect

What I'm trying to do is call function form server and validate data in javascript function but the return statement from server make redirect before response.complete("success")
button.onclick = async function handlePurchase() {
const payment = new PaymentRequest(methods, details, options);
try {
const response = await payment.show();
// Call server logic here and validate response if OK continue
// But server response redirect here so code not completed
$('#checkout-form').submit();
$.ajax({
url: '{{route("apple-pay")}}',
type: 'post',
data: $('#checkout-form').serialize(),
success: function(data){
console.log('data :>> ', data);
}
});
await response.complete("success");
// redirect to success page
} catch (err) {
console.error("Uh oh, something bad happened", err.message);
}
}
Server function:
public function pay(Request $request)
{
$merchant_id = env('CREDIMAX_MERCHANT_ID');
$password = env('CREDIMAX_INTEGRATION_PASSWORD');
$response = Http::withBasicAuth('merchant.'.$merchant_id, $password)->put
('https://example.com/api/rest/merchant/'.$merchant_id.'/order/1530/transaction/1', $data);
return $respone->json();
}
Seperate the request you are making to the third party app and the response you are sending back to you ajax call. This is how I mean:
public function pay(Request $request)
{
$merchant_id = env('CREDIMAX_MERCHANT_ID');
$password = env('CREDIMAX_INTEGRATION_PASSWORD');
$response = Http::withBasicAuth('merchant.'.$merchant_id, $password)->put
('https://example.com/api/rest/merchant/'.$merchant_id.'/order/1530/transaction/1', $data);
return response()->json([
'success' => $response->ok() ? 1 : 0,
...
]);
}
Check the last line in the controller it says "return $respone->json();" and should be "return $response->json();" -- missing the "s" in response.

Laravel Inertia (Vue) - Authenticate without Redirect

I'm making a normal Inertia post to a base Laravel login route:
submit() {
this.$inertia.post("/login", {
email: this.emailAddress,
password: this.password,
}, {
preserveState: true,
preserveScroll: true,
});
}
I'm able to catch validation errors as expected, but what I'm trying to avoid is the redirect after a successful user authentication, and instead proceed in the "logged in" state (update header to show user info, etc).
The Laravel AuthenticatesUsers trait contains this contains two key methods that gets called as part of the out-of-the-box login flow
public function login(Request $request)
{
$this->validateLogin($request);
// If the class is using the ThrottlesLogins trait, we can automatically throttle
// the login attempts for this application. We'll key this by the username and
// the IP address of the client making these requests into this application.
if (method_exists($this, 'hasTooManyLoginAttempts') &&
$this->hasTooManyLoginAttempts($request)) {
$this->fireLockoutEvent($request);
return $this->sendLockoutResponse($request);
}
if ($this->attemptLogin($request)) {
return $this->sendLoginResponse($request);
}
// If the login attempt was unsuccessful we will increment the number of attempts
// to login and redirect the user back to the login form. Of course, when this
// user surpasses their maximum number of attempts they will get locked out.
$this->incrementLoginAttempts($request);
return $this->sendFailedLoginResponse($request);
}
and
protected function sendLoginResponse(Request $request)
{
$request->session()->regenerate();
$this->clearLoginAttempts($request);
if ($response = $this->authenticated($request, $this->guard()->user())) {
return $response;
}
return $request->wantsJson()
? new Response('', 204)
: redirect()->intended($this->redirectPath());
}
I'm struggling to figure out if it's even possible to authenticate a user without redirecting this way.
You need to utilize the javascript frontend, not Inertia::post() . One way to do this is to use Axios:
submit() {
const data = {...this.form.data()};
axios.post('/auth/login', data, {
headers: {
'Content-Type': 'application/json',
},
})
.then(res => {
console.log('login success!', res);
});
Check your form and the way you submit - do you prevent the default behavior of the form submit? It seems like you are sending a POST but the native form behavior is also triggered.
You can also set a $redirectTo in your LoginController, also check RouteServiceProvider there is a public const HOME = '/' which triggered the redirect if nothing else is given.
This are my two cents...
A few days ago I was struggling with passing the result of the script to Vue without redirecting, using Inertia visits instead of Axios.
The solution I adopted was the following:
In vue:
this.$inertia.visit(`URL`, {
method: "post",
data: { //Email and password },
preserveState: false,
preserveScroll: false,
onError: (errors) => { // do what ever is needed if validation fails },
onSuccess: () => { // do what ever is needed if validation succeeds }
});
In Laravel:
// If validation fails:
return redirect()->back()->withErrors([
'login' => 'Validation fail details.'
]);
// If validation succeeds:
return redirect()->back()->with('login', 'Success message!');
This way the page does not redirect and the user can continue exactly wherever he is.
What i'm not sure is if it's possible to pass the user info over the success redirect message. Maybe returning a array like it's done in withErrors. If not possible it's always possible to make an additional request to the server to retrieve the desired information.
Hope it's usefull.

Axios - Redirect to controller with data

i'm trying to redirect to Controller with data and use that data in controller ( i'm using laravel)
/* html */
<a #click="Submit()" href="/buy" class="btn btn-block btn-lg btn-primary btn-checkout-pay">Buy</a>
/*js codes*/
Submit : function(){
axios.post('/buy',{
ProductId : this.id,
//ProductId : "1";//
ProductAmount : this.temporaryamount
//ProductAmount : "12000";//
})
.then(function (response) {
window.location = "/buy";
console.log(response);
})
.catch(function (error) {
console.log(error);
})
}
and the /buy is redirected to ShoppingController#create
/* web.php */
Route::get('/buy','ShoppingController#create');
Route::post('/buy','ShoppingController#create');
/* ShoppingController#create */
public function create(Request $request)
{
dd($request['ProductId']);
}
the problem is $request['ProductId']; is null
that means axois request is redirected without the data
P.S : i don't wan't to return the data i wanna just use the data in controller
Basically, you cannot used together those two create functions with different route method and at the same time you want to get the product id. Your post request will work on that situation but the get request will not. that's why dd($request['ProductId']) is null. You cannot use request as a parameter whenever you use a get request. $request as a parameter is for post request only.
for further explanation please read laravel docs source
so to solve your problem, you may remove this line
window.location = "/buy";
and show your post data in the controller by this
public function create(Request $request) {
dd($request->all())
}
if i understand correctly your problem is that you don't see the return of "dd".
It's normal your console.log is after the window! and no dd with axios! you have to return to see the answer!
Controller
public function create(Request $request)
{
return $request['ProductId'];
}
.vue
/*js codes*/
Submit : function(){
axios.post('/buy',{
ProductId : this.id,
//ProductId : "1";//
ProductAmount : this.temporaryamount
//ProductAmount : "12000";//
})
.then(function (response) {
console.log(response);
//Remove window.location, or if you dont remove you dont see console.log!
//window.location = "/buy";
})
.catch(function (error) {
console.log(error);
})
}
and on your route remove get.
/* web.php */
Route::post('/buy','ShoppingController#create');

Getting value from request in Laravel using ajax

I have this ajax method in PostsController
public function ajax(Request $request)
{
//dd($request);
$this->authorize('view', Post::class);
$posts = Post::orderBy("created_at","desc")->paginate(5);
$comments = Comment::all();
return response()->json(array("posts"=> $posts, "comments"=> $comments), 200);
}
which works great when you just getting data and sending it.
So i tried besides requesting data by ajax, to send some data alongside ajax request. How can i access that data inside controller?
Here is a method which resides inside certain blade:
function ajax(){
let var1 = "gg";
let var2 = "bruh";
let token = document.querySelector("meta[name='csrf-token']").getAttribute("content");
let url = '/posts';
$.ajax({
type: "POST",
url: url,
headers:
{
'X-CSRF-TOKEN': token
},
data: {
'var1': var1,
'var2': var2
},
success: function(data) {
console.log(data);
}
});
}
To simplify: How can i, dd() or dump(), given data(var1 & var2) by ajax function from blade in PostsController?
Here is route:
Route::post('/posts', "PostsController#ajax");
And here is some "gibberish" when i try to dd() it:
dd() is a laravel function and dump()for php. so you cannot use them from javaScript.
You cannot dd() or dump() from direct ajax request or JavaScript.
What you can do is, console log your data, or check from browser developer portion, network tab to see which data you are getting from the ajax response. You can find browser developer portion in,
for chrome:
Insepect > Network
for mozila:
Insepect Element > Network
If you are telling about get var1 and var2 on controller, you can just get them by $request->var1 and $request->var2.
Hasan05 was right. Just needed to know right direction. So to get data parameter of ajax request i modified ajax controller method:
public function ajax(Request $request)
{
$var1 = $request->input('var1');
$var2 = $request->input('var2');
$this->authorize('view', Post::class);
$posts = Post::orderBy("created_at","desc")->paginate(5);
$comments = Comment::all();
return response()->json(array("posts"=> $posts, "comments"=> $comments, "var1"=> $var1, "var2"=> $var2), 200);
}

Laravel 5.6 ajax request, can't read the value

I can't read the values send with ajax request, i don't know what im missing.
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
$("#send").click(function(e){
e.preventDefault();
var id = 5;
$.ajax({
type:'POST',
url:'/device/',
data:{id:id},
success:function(data){
console.log('Yes' + data);
}
});
});
in the controller device i just dump the input from the ajax call
$data = $request->all();
dd($data);
I can't see the value send via ajax in the console, i only see Yes but not the data.
What im missing ?
use the following line in your controller;
return $data; instead of dd($data);
Just Replace the + with , like below
console.log('Yes' , data);
try this in controller
public function store(Request $request) {
return Response::json($request->all(), 200);
}
dont forget to include
"use Response;
use Illuminate\Http\Request;"
Use This:
$("#send").click(function(e){
e.preventDefault();
var id = 5:
$.ajax({
type:'POST',
url:'{{url('/device')}}',
data:{
'ajax': 1,'id':id,'_token': {{csrf_token}}
},
success:function(data){
console.log('Yes'+data.id);
}
});
});
In the controller use:
public function name()
{
if(Input::get('ajax') == 1)
{
print_r('Ajax is working');die;
}
}
Also make sure, in the route you have post or any and not get for this route.
try this one.
in controller:
return $data;
And simply replace + with, like this:
console.log('Yes' , data);

Resources