How to avoid counter multiplication when user reenter the component? - php

I'm using angular-user-idle npm package to track browser inactive status and display a session out popup on preset timeout . The library works well when you do not redirect from that particular component on timeout. When you redirect to home page or similar one and reenter the same earlier component and if timeout happens this time, popup appear multiple time now.
Now in order to explain you this, I have displayed counter number during 1st load of component and 2nd load of the component in the screenshots below. If you carefully look at second image number of each counter is appearing twice. What is the reason for it same is resulting in popup appearing multiple times? How can I avoid it?
ngOnInit() {
//Start watching for user inactivity.
this.restart();
this.userIdle.startWatching();
// Start watching when user idle is starting.
this.userIdle.onTimerStart().subscribe(count => console.log(count));
// Start watch when time is up.
this.userIdle.onTimeout().subscribe(() => {
this.openGenericDialog('GenericAlert', "Your session is expired!");
this.dialogRef.afterClosed().subscribe(
result => {
this.dialogResult = result;
this.stopWatching()
this.stop();
this.createUpdateLoggedInRecord('Simulation',
this.varUser.UserKeyID, false);
this.router.navigateByUrl('/authentication');
});
}
);
}
stop() {
this.userIdle.stopTimer();
}
stopWatching() {
this.userIdle.stopWatching();
}
restart() {
this.userIdle.resetTimer();
}

I think you might have a memory leak because you don't keep track of your subscriptions.
this.userIdle.onTimeout().subscribe(() => {
...
^^ This.
Should be this (vv)
this.userIdle.onTimeout()
.pipe(take(1))
.subscribe(() => {
...

Related

Close support chat after connection timeout with Laravel Echo

I'm building a support chat application. It's built on Laravel Echo through Pusher.js.
There are two sides - support/admin and client. When a client starts a chat, support can accept it and they can chat together. It's working like it should be, but there is one thing. When the client goes offline (close browser, leave site, lost internet connection...) it should wait for about a few seconds (to make sure it was not a mistake) and then close the chat. So when he comes back in about an hour, there would not be any active chat.
I'm checking both sides' online status with presence channel with simple code:
this.presence = Echo.join('chat');
this.presence
.listen('.pusher:subscription_error', (result) => {
if(this.debug) {
console.log(result);
}
})
.listen('.pusher:member_added', (result) => {
if(!!result.info.is_admin) {
this.presence_users.push(result.info);
}
})
.listen('.pusher:member_removed', (result) => {
let found = _.find(this.presence_users, ['id', result.id]);
let index = this.presence_users.indexOf(found);
this.presence_users.splice(index, 1);
})
.here((result) => {
this.presence_users = _.filter(result, ['is_admin', true]);
});
On the support side it's a little different, but still the same logic (also don't worry - user's id is not id from database, but unique md5 identifier).
Presence channel is working good. But I can't find anywhere on the internet, how to set up connection_timeout URL? I just think it could be URL, where Pusher.js will post some data when the user goes offline, or connection is lost - my custom id field, for example. As I noted in the start, it should have some "cooldown", when user goes offline by mistake. This would help to close the chat when the user is not available to respond.
Do you have any experience with a similar problem? If so, how did you solve it? Or - is it even possible to solve it with Pusher.js?
Well, 7 days are gone and no answer here, so I think it's not possible the way I describe. But there can be a "hacky" way:
Create a CRON job which runs every 10 minutes
Script will get all chats from database with flag active or pending
When chat has no recent messages (nothing from last 5-10 minutes), then check if users are online
Get users from presence channel
$response = $pusher->get('/channels/chat/users');
if($response['status'] == 200) {
$users = json_decode($response['body'], true)['users'];
}
If there is at least one of them online, skip, otherwise wait for a short time (5 seconds, just to be sure), check online status again and when they are still offline, close the chat.
Haven't tested it, since it is not required yet. Maybe someone will find this helpful.

JQuery wheel spin onload

I have little problem with JQuery.
Am making spinning wheel application. That application start when I click on button.
I want to change that, because my client will determine when wheel to begin.
Most of my configuration is stored in a database but I try with single number 1 = start, 0 stop.
My app have this for button click and start:
this.cache.wheelSpinBtn = $('.wheel');
// test
this.cache.wheelSpin = 1; // 1 auto start 0 False
Application start when i press button with class .wheel
this.cache.wheelSpinBtn.on('click', function (e) {
e.preventDefault();
if (!$(this).hasClass('disabled')) _this.spin();
});
But I want to remove the button from the other visitors, and this command is issued in the administration. As I said in my configuration is based
I try without database :
if(this.cache.wheelSpin === 1) {
this.spin(); // if is 1 start spinning
}
With database that looks:
if(this.cache.wheelSpin === <?php echo $obj->getStatus()?> ) {
this.spin(); // if is 1 start spinning
}
In both cases that is not work when i refresh page.
I just want when i refresh page wheel start spins. If is value 1 and my core know when need to stop.
My applucation code is little compicated and my code is in and its inposible to use .ready() on only one this.cache.wheelSpin...
Check video.
http://www.youtube.com/watch?v=H-yi6Sv71rs&feature=youtu.be

How to prevent users to open same page more than once at a time

On my website people earn points by seeing a page. They get 1 point for each second they keep the page open (the page keeps rotating Advertisements).
Some people have started exploiting this by opening that page multiple times all together and hence are earning more points! for example if the user open the page 10 times then he is earning 10 points for each second. I don't want them to earn more than 1 point per second.
How can I prevent the users from opening that page more than once at the same time?
Thanks in advance.
note : My website is php based.
I have on easy but not reliable way in mind:
Set a Sessionvar like
$_SESSION['user_already_on_page'] = true;
Now you can check for this variable and return an error page or something like that.
if($_SESSION['user_already_on_page'])
{
//maybe the user has left unexpected. to workaround this we have to check
//for the last db entry. Examplecode:
$query = mysql_query($_db,'SELECT LastUpdated FROM Pointstable WHERE U_Id = $uid');
$row = mysql_fetch_array($query);
if((time()-$row['LastUpdated']) < 5)
{
die("You are already on this page!");
}
//$_SESSION['user_already_on_page'] is set but the last update is older than 5 sec
//it seems, that he unexpectedly lost connection or something like that.
}
To unset this variable you could fire an AJAX-Script on pageclose that unsets this variable.
So your unsetonpage.ajax.php could look like this:
<?php $_SESSION['user_already_on_page'] = false;?>
And your JS-Part (using jquery):
$(window).bind('beforeunload', function(eventObject) {
$.ajax({url:'./ajax/unsetonpage.ajax.php',type:'GET'});
});
This should work.
Add the time when the page is opened to the database. Whenever the page is opened check if the difference b/w that time and current time is less than xx seconds then redirect the user. If the difference is more than xx seconds then update that time.
//--- You make session in startup called (my_form)
if (!empty($_SESSION['my_form']))
{
if ($_SESSION['my_form']== basename($_SERVER['PHP_SELF']))
{
header("Location:index.php");
exit();
} else {
$_SESSION['my_form']= basename($_SERVER['PHP_SELF']);
}
} else {
$_SESSION['my_form']= basename($_SERVER['PHP_SELF']);
}

preventing duplicates infinite scrolling ajax loader

it might just be too late at night for me to see a clear solution here, but I figured I'd get some thoughts from anybody with an opinion...
the site i'm working on has a long list of user posts. i've got all the scroll event handlers working to ajax in the next batch of 100 posts when you reach or approach the bottom.
my question is... How do i prevent the following scenario?
UserX visits the site and loads posts 1-100
10 more users visit the site and add 10 more posts
UserX scrolls to bottom and loads posts 101-200, which used to to be posts 91-190
UserX ends up with duplicates of posts 91-100 on the page
i'll include a stripped down version of my code below in case it helps anybody else along
$.ajax({
type:'POST',
url:"/userposts.php",
data:{ limit: postCount },
success:function(data) {
$("postsContainer").append(data);
if ( $("postsContainer").find("div[id='lastPostReached']") ) {
// unbind infinite scrolling event handlers
}
},
dataType:'html'
});
in my PHP script I have essentially the following:
if ( ! isset($_POST["limit"]) ) {
$sql .= " LIMIT 101"; // initial request
} else {
$sql .= " LIMIT {$_POST["limit"]},101
}
$posts = mysql_query($sql);
while( $post = mysql_fetch_assoc($posts) ) {
/* output formatted posts */
}
// inform callback handler to disable infinite scrolling
if ( mysql_num_rows($posts) < 101 ) {
echo '<div id="lastPostReached"></div>';
}
This gives me infinite scrolling nice and easy, but how can I prevent the hypothetical duplicates that would show up when new records have been added to the table between ajax requests?
You define a timestamp from php that indicates the servertime at the time the page loads (eg var _loadTime = <?php echo time(); ?>) and then pass this value as part of the Ajax data config object along with limit.
Then on the server side you can exclude any posts that were created after this time and hense preserve your list.
You can also go a step further and use this time along with a basic ajax long polling technique to notify the user of new posts since the page loaded/last loading of new posts - similar to Facebook and Twitters feeds.
Update your ajax request, so that in addition to the limit parameter you pass through the current range of post ids (I'm assuming the posts have some kind of unique id). Update your php to take those parameters into account when retrieving the next set of posts.
That is, instead of saying "give me another 100" the request is "give me 100 starting at id x".
(Sorry, I don't have time now to write an example code for this.)
Just use a unique identifier ID for the posts and count backwards.
First visit user requests posts 603-503
Ten users get on the page and add comments so the highest comment is now 613
User scolls down and requests 503-403
Problem solved? :)

Curing the "Back Button Blues"

Ever stumbled on a tutorial that you feel is of great value but not quite explained properly? That's my dilemma. I know THIS TUTORIAL has some value but I just can't get it.
Where do you call each function?
Which function should be called
first and which next, and which
third?
Will all functions be called in all files in an application?
Does anyone know of a better way cure the "Back Button Blues"?
I'm wondering if this will stir some good conversation that includes the author of the article. The part I'm particularly interested in is controlling the back button in order to prevent form duplicate entries into a database when the back button is pressed. Basically, you want to control the back button by calling the following three functions during the execution of the scripts in your application. In what order exactly to call the functions (see questions above) is not clear from the tutorial.
All forwards movement is performed by
using my scriptNext function. This is
called within the current script in
order to activate the new script.
function scriptNext($script_id)
// proceed forwards to a new script
{
if (empty($script_id)) {
trigger_error("script id is not defined", E_USER_ERROR);
} // if
// get list of screens used in this session
$page_stack = $_SESSION['page_stack'];
if (in_array($script_id, $page_stack)) {
// remove this item and any following items from the stack array
do {
$last = array_pop($page_stack);
} while ($last != $script_id);
} // if
// add next script to end of array and update session data
$page_stack[] = $script_id;
$_SESSION['page_stack'] = $page_stack;
// now pass control to the designated script
$location = 'http://' .$_SERVER['HTTP_HOST'] .$script_id;
header('Location: ' .$location);
exit;
} // scriptNext
When any script has finished its
processing it terminates by calling my
scriptPrevious function. This will
drop the current script from the end
of the stack array and reactivate the
previous script in the array.
function scriptPrevious()
// go back to the previous script (as defined in PAGE_STACK)
{
// get id of current script
$script_id = $_SERVER['PHP_SELF'];
// get list of screens used in this session
$page_stack = $_SESSION['page_stack'];
if (in_array($script_id, $page_stack)) {
// remove this item and any following items from the stack array
do {
$last = array_pop($page_stack);
} while ($last != $script_id);
// update session data
$_SESSION['page_stack'] = $page_stack;
} // if
if (count($page_stack) > 0) {
$previous = array_pop($page_stack);
// reactivate previous script
$location = 'http://' .$_SERVER['HTTP_HOST'] .$previous;
} else {
// no previous scripts, so terminate session
session_unset();
session_destroy();
// revert to default start page
$location = 'http://' .$_SERVER['HTTP_HOST'] .'/index.php';
} // if
header('Location: ' .$location);
exit;
} // scriptPrevious
Whenever a script is activated, which
can be either through the scriptNext
or scriptPrevious functions, or
because of the BACK button in the
browser, it will call the following
function to verify that it is the
current script according to the
contents of the program stack and take
appropriate action if it is not.
function initSession()
// initialise session data
{
// get program stack
if (isset($_SESSION['page_stack'])) {
// use existing stack
$page_stack = $_SESSION['page_stack'];
} else {
// create new stack which starts with current script
$page_stack[] = $_SERVER['PHP_SELF'];
$_SESSION['page_stack'] = $page_stack;
} // if
// check that this script is at the end of the current stack
$actual = $_SERVER['PHP_SELF'];
$expected = $page_stack[count($page_stack)-1];
if ($expected != $actual) {
if (in_array($actual, $page_stack)) {// script is within current stack, so remove anything which follows
while ($page_stack[count($page_stack)-1] != $actual ) {
$null = array_pop($page_stack);
} // while
$_SESSION['page_stack'] = $page_stack;
} // if
// set script id to last entry in program stack
$actual = $page_stack[count($page_stack)-1];
$location = 'http://' .$_SERVER['HTTP_HOST'] .$actual;
header('Location: ' .$location);
exit;
} // if
... // continue processing
} // initSession
The action taken depends on whether
the current script exists within the
program stack or not. There are three
possibilities:
The current script is not in the $page_stack array, in which case it is
not allowed to continue. Instead it is
replaced by the script which is at the
end of the array.
The current script is in the
$page_stack array, but it is not the
last entry. In this case all
following entries in the array are
removed.
The current script is the last entry
in the $page_stack array. This is
the expected situation. Drinks all
round!
That is a good discussion but more to the point you should be looking into Post Redirect Get (PRG) also known as "Get after Post."
http://www.theserverside.com/patterns/thread.tss?thread_id=20936
If you do not understand my article then you should take a close look at figure 1 which depicts a typical scenario where a user passes through a series of screens – logon, menu, list, search, add and update. When I describe a movement of FORWARDS I mean that the current screen is suspended while a new screen is activated. This happens when the user presses a link in the current screen. When I describe a movement as BACKWARDS I mean that the user terminates the current screen (by pressing the QUIT or SUBMIT button) and returns to the previous screen, which resumes processing from where it left off. This may include incorporating any changes made in the screen which has just been terminated.
This is where maintaining a page stack which is independent of the browser history is crucial – the page stack is maintained by the application and is used to verify all requests. These may be valid as far as the browser is concerned, but may be identified by the application as invalid and dealt with accordingly.
The page stack is maintained by two functions:
scriptNext() is used to process a
FORWARDS movement, which adds a new
entry at the end of the stack and
activates the new entry.
scriptPrevious() is used to process
a BACKWARDS movement, which removes
the last entry from the stack and
re-activates the previous entry.
Now take the situation in the example where the user has navigated to page 4 of the LIST screen, gone into the ADD screen, then returned to page 5 of the LIST screen. The last action in the ADD screen was to press the SUBMIT button which used the POST method to send details to the server which were added to the database, after which it terminated automatically and returned to the LIST screen.
If you therefore press the BACK button while in page 5 of the LIST screen the browser history will generate a request for the last action on the ADD screen, which was a POST. This is a valid request as far as the browser is concerned, but is not as far as the application is concerned. How can the application decide that the request is invalid? By checking with its page stack. When the ADD screen was terminated its entry was deleted from the page stack, therefore any request for a screen which is not in the page stack can always be treated as invalid. In this case the invalid request can be redirected to the last entry in the stack.
The answers to your questions should therefore be obvious:
Q: Where do you call each function?
A: You call the scriptNext()
function when the user chooses to
navigate forwards to a new screen,
and call the scriptPrevious()
function when the user terminates
the current screen.
Q: Which function should be called
first and which next, and which
third?
A: Each function is called in
response to an action chosen by the
user, so only one function is used
at a time.
Q: Will all functions be called in
all files in an application?
A: All functions should be available
in all files in an application, but
only called when chosen by the user.
It you wish to see these ideas in action then you can download my sample application.
The part I'm particularly interested in is controlling the back button in order to prevent form duplicate entries into a database when the back button is pressed.
Your premise is wrong. There is no such thing as "Back Button Blues", if you design your application as a web application. If you design your application without any server side state, you will never run into this problem in the first case. This minimalistic approach to web applications works remarkably well, and is usually known as REST.
# troelskn
If you design your application without any server side state ....
It is not possible to design an effective application which does not have state, otherwise all you have is a collection of individual pages which do not communicate with each other. As maintaining state on the client is fraught with issues there is no effective alternative but to maintain state on the server.
#Marston.
I solved the problem with post/redirect/get but I believe the tutorial has some merit and perhaps Tony Marston can elaborate on it. And how it could be used to solve not necessarily my particular problem but perhaps something similar. Or how is it better than post/redirect/get if the functions can in fact be used in solving my particular problem. I think this will be a good addition to the community here.
if ($_POST) {
process_input($_POST);
header("Location: $_SERVER[HTTP_REFERER]");
exit;
}

Categories