Pagination in Gmail API (Previous Token) - laravel-5

I have implemented GMail API which gets Emails for me. Now I am trying to add pagination to it I have succeed in getting next records but now I also want to have Previous option(which required previous token).
I am unable to get into it below is what I tried so far.
public function paginate(Request $request){
$label = $request->input("label");
$nextToken = $request->input("next");
$prevToken = $request->input("prev");
$messages = LaravelGmail::message();
$msg = $messages->take(3)->in($label)->all($nextToken);
$nextToken_New = $messages->pageToken;
return view('gmail.load_mails', ['messages' => $msg, 'nextPageToken' => $nextToken_New,
'prevPageToken' => $nextToken]);
}
Now In the above function nextPageToken is passed in view as $nextToken_New
and for prevPageToken I am unable to set previous page token.(In code I have set last nextPageToken to prevPageToken which is not working)
Remember prevPageToken will be used to set on back key.

The Gmail api does not support prevous page token. Its not going to return the value to you.
Your first option would be to save these tokens on your server and then when ever you want to go back a page simply supply the token you want to the page token field
The second option and the one that i personally feel would be the most logical. Would be to cache the data returned by these requests on your server so that
you dont have to make extra http calls to the server.
you are not eating addictal quota making a call you have already made before.
APIs were not meant for you to use to implement pagination in your application. You should only be requesting data once its your job to then cache that data so that you wont need to make the same request twice.

Related

Angular: await for query string parameter but do something else if it doesn't appear

I have tried to formulate a question title the most generic way that applies to my problem.
I have an Angular application where I have to handle authentication over an external requirement: either use a query string parameter token that has to be exchanged with the server for a JWT, or try to search for a JWT refresh token in the local storage.
It is:
First test the query string: if there is a queryString parameter token, grab the token, delete any JWT in the local storage, exchange the token via API for two JWTs (id_token and refresh_token)
Else go for the refresh token: if there is a refresh_token in the local storage available, exchange it for a JWT id_token via API
Else, if none of the two are available, the user is unauthenticated and a prompt should be displayed
I used Observables almost the correct way
this.queryParamMap$.unsubscribe();
this.queryParamMap$ = this.activatedRoute.queryParamMap
.subscribe(
params => {
let token = params.get('token');
........
if (!!token) {
doLoginWithToken();
else if (isJwtRefreshAvailable())
doLoginWithRefreshToken();
There is one problem with this approach: the very first time the application starts up, the query param map is empty, even if I follow a direct browser link http://localhost:4200?token=AAAAAAAA. I have to wait for the next element which contains the token.
This has two undesirable effects:
At the first attempt, being the token undefined, the application immediately tries to log in with the refresh token
If I filter the queryParamMap observable for a token being present, if a token is never present the observable will never emit, thus not activating the subscription.
My problem can be summarized/generalized as follows.
I have an Observable that I know for sure emits undefined the very first time, but either in no time it could be ready with a proper value, or it won't emit new values after the initial undefined.
Else said, while the observable emits undefined and my code starts reacting to it (e.g. by testing for token), a new value can be ready for emission right away.
How can I solve this in Rxjs? Note that accessing the JWT token from the local storage is a synchronous operation, but it's easy to create Observable.of(localStorage.get(KEY)) which emits immediately if a refresh token is present.
For that, I can't realistically use race operator, because the refresh token is always ready and always wins the race.
How can I write asynchronous code that performs like the steps I described earlier?
As the ultimate result of the authentication, an Observable<UserProfileDto | undefined> emits the information about the user, which is used to display personalized information.
You have 2 problems here:
On init you got "undefined" value (its because probably, under the hood, there is some BehaviourSubject emitting its default value). To overcome this, you can add RxJS operator (skip(1)) to skip that first value, but:
Problem here is if you do not have query values at all, you will not reach your subscribe function. Its because queryParamMap will emit a value only, if there is a change (and in that case there is not):
You can do it without Angular, to just parse url from:
const urlParams = new URLSearchParams(window.location.search);
const params = Object.fromEntries(urlParams.entries());
Or using router in Angular:
this.router.events
// Wait for the navigation end event (since component is initialized before angular router navigation is done)
.pipe(filter(event => event instanceof NavigationEnd))
.subscribe((event: NavigationStart) => {
// Take query params snaphot
const map = this.route.snapshot.queryParams;
});

Pass the page number to a server side datatable

I am using datatable with Laravel to order a response that i receive from an API
I connect to the API with this code:
$ch = curl_init('https://api.turn14.com/v1/items?page=$page');
How you can see i just need to add the $page and it starts to take me all the products from their page, if i add page=1 it takes all the values of the API from the page 1, etc etc
The thing is that I am using datatable server side because i want to use all the functionalities that it offers me BUT I do not know how can i pass the number page with the datatable, I mean if I push the number 2 in the button how can i get that value?
I mean in the paginator says 1 .. 2 .. 3 etc, if i push 2 how can i know that i pushed in the button 2?
Thanks!
It would be good to know more about your code. That said, from what I can understand, when you pass the page number to the url - you receive the next page with data from the endpoint. If you are using the Laravel paginator and not something custom, the usual way it works is that it appends a query parameter to the current url:
Imagine you have a controller HomeController with a method index:
use Illuminate\Http\Request;
public function index(Request $request) {
dd($request->get('page')); // this will return your current page
// Make sure you check the page query parameter first before using it like this.
$ch = curl_init('https://api.turn14.com/v1/items?page='.$request->get('page'));
return view('home');
}
For more information you can read the Laravel docs:
https://laravel.com/docs/5.8/pagination#basic-usage
By default, the current page is detected by the value of the page query string argument on the HTTP request. This value is automatically detected by Laravel, and is also automatically inserted into links generated by the paginator.

Laravel: How to mark Session data as flashed

I am trying to pre-populate an input on a form for the creation of a model entity in Laravel 5.4. But the form is a shared blade template with the edit form for the same model, where I want to use form-model binding to provide the input.
The way I have achieved this so far is to flash a session variable to _old_input in the controller for the creation route:
session()->flash('_old_input.description', $event->description);
This achieves exactly what I want it to, with the exception of not being cleaned out at the end of the request. My next request still has the session data flashed.
My question is how does Laravel know that this is the recipient of a flash message as opposed to the input of a flashed message? And is there a way to tell it that I've already used the session flash and it should be cleaned up at the end of this request...
You need to use redirect to flash the session... otherwise, you will end up with the flash staying on for the next request...
You can return a view... like
return redirect('view')->with('_old_input.description', $event->description);
Or you can even redirect to a controller action ... like
session()->flash('_old_input.description', $event->description);
return redirect()->action('MyController#function');
which would work also... the key is to return a redirect response...
Hope this helps...
Serge is correct that flash is intended for use to put data into the session for the NEXT request and thus redirecting is the correct way to do this, I will also provide here the solution I used to hack my way past this...
Laravel stores its flash data in the _flash value in the session array, with keys which are to be used in the NEXT request under the new key, and keys which were used in THIS request in the old key; see extract below.
[_flash] => Array
(
[old] => Array
(
)
[new] => Array
(
[0] => _old_input
)
)
Using session()->push('_flash.old', '_old_input'); fools Laravel into thinking that this is data that was flashed into this request from the previous one, and clears up the data at the end of its cycle.
For full effect, you can use session()->forget('_flash.new.0'); to remove it from the new key, although beware that this is not necessarily the first flashed var (in my case it is).
My total code is therefore:
session()->flash('_old_input', ['description' => $event->description]);
session()->push('_flash.old', '_old_input');
session()->forget('_flash.new.0');
Again, Serge is correct but if anyone else comes here to find out how Laravel's flashing works and wants to circumvent it, here is a bit of information

Laravel 5 - Deal with controller validation and RESTful clients like Postman

I am using laravel's RESTful resource routes and controllers.
I testing my api with PostMan and/or RestClient(firefox)
Everything was fine before I added laravel's controller validation. Now it respond with very strange responses like: status code 0, or even executes the code with not valid data. Or even shows strange results taken from the database (which are not included to the controller at all).
That's creepy.
For example:
public function store(Request $request) {
$this->validate($request, [
'room_id' => 'required|integer',
'body' => 'required'
]);
exit; // Stop the process after the validation...
// ... Logic to STORE the MESSAGE in the database ...
return response(null, 204);
}
This store function must only validate the data and respond with an error if validation fails,
But when I execute it from PostMan, It returns response with list of all rooms which belongs to this user. This is creepy, I cannot realize why this is happening.
When I use the jQuery.ajax() method with the same request options, it works fine. It validates the data and stores the message in the database.
Question : Is there a way to deal with postman?
Question : Is PostMan dangerous? Since the server respond with database info (which is not included to the controller responses).
If you take a closer look at laravel's validation document it says that when data is submitted via HTML form,the validate method would redirect you to a previous page and the error would be flashed into the session, if the validation fails. Although, you will be able to access these error messages in your view using the $error variable. Therefore you will need to submit the data via ajax in-order to get the JSON error message.
When validatioin failed, Laravel needs to know you are sending ajax request or you explicitly want json respond, otherwise it redirects you to previous page.
You can check my answer here
https://stackoverflow.com/a/38478362/6246592

How do I prevent tampering with AJAX process page?

I am using Ajax for processing with JQUERY. The Data_string is sent to my process.php page, where it is saved.
Issue: right now anyone can directly type example.com/process.php to access my process page, or type example.com/process.php/var1=foo1&var2=foo2 to emulate a form submission. How do I prevent this from happening?
Also, in the Ajax code I specified POST. What is the difference here between POST and GET?
First of all submit your AJAX form via POST and on a server side make sure that request come within same domain and is called via AJAX.
I have couple of functions in my library for this task
function valid_referer()
{
if(isset($_SERVER['HTTP_REFERER']))
return parse_url($_SERVER['HTTP_REFERER'], PHP_URL_HOST) == $_SERVER['SERVER_NAME'];
else
return false;
}
function is_ajax()
{
$key = 'HTTP_X_REQUESTED_WITH';
return isset($_SERVER[$key]) && strtolower($_SERVER[$key]) == 'xmlhttprequest';
}
You might read this post regarding difference between post and get
While as Jason LeBrun says it is pretty much impossible to prevent people simulating a form submission, you can at least stop the casual attempts to. Along with implementing Nazariy's suggestions (which are both easy to get round if you really want to), you could also generate some unique value on the server side (i'll call it a token), which gets inserted into the same page as your Ajax. The Ajax would would then pass this token in with your other arguments to the process.php page whereupon you can check this token is valid.
UPDATE
see this question with regards to the token
anti-CSRF token and Javascript
You can not prevent people from manually emulating the submission of form data on your website. You can make it arbitrarily more difficult, but you won't be able to prevent it completely.

Resources