I've got a Classic ASP application that relies on session; if the user leaves a screen idle and then runs a form post or other operation, I'd like to know whether the session has expired.
Currently I'm checking session in each page to see if it's timed out, but is there a better, dynamic, JavaScripty approach that will do what banks do and time out sessions with a notification and redirect to login?
During your page's onload event, start a timer, and then redirect the page after N seconds.
For the timer, use the window.setTimeout function.
For the redirect, set the value of window.location.
Reusable Example:
<head>
<script type="text/javascript">
<!--
function redirect(url) {
window.location = url;
}
function beginSessionTimer() {
// 30000ms = 30s
window.setTimeout(redirect, 30000,
"http://www.yoursite.com/login.asp?session=clear");
}
//-->
</script>
</head>
<body onload='beginSessionTimer();'>
</body>
Quick-n-dirty Example w/ an inline function:
<body onload='window.setTimeout(function(){
window.location="http://www.yoursite.com/login.asp?session=clear";},
30000);'>
Note that if your page performs any AJAX calls, that keeps the session alive, so you'll want to reset the timer using the clearTimeout method (combined w/ a new call to setTimeout). For details on clearTimeout, click here for excellent documentation from Mozilla.)
Related
I have reCAPTCHA v3 set up on my page:
<script src="https://www.google.com/recaptcha/api.js?render=MY_KEY"></script>
If internet connectivity becomes unavailable or unreliable, reCAPTCHA will insert this HTML at the bottom of my page:
<div>
<div>
Could not connect to the reCAPTCHA service. Please check your internet connection and reload to get a reCAPTCHA challenge.
</div>
</div>
I would much rather handle this error in my JavaScript so I can display it to the user in a better way. However, the documentation for v3 doesn't indicate how to do this.
Any thoughts on how to catch this error?
You can put an onerror handler in the script tag itself:
<script src="https://www.google.com/recaptcha/api.js?render=MY_KEY" onerror="error_handler()">
But I think what you want is more along the lines of what reCAPTCHA v2 offers:
widgetId = grecaptcha.render('example1', {
'sitekey' : 'your_site_key',
'theme' : 'light',
'error-callback' : error_handler()
});
I doubt that works but there is another way. You just need to monitor the DOM for changes since you know that when there is an error Google will add a div to your page. You can do that with MutationObserver.
var m = new MutationObserver(function (mutationRecords) {
this.disconnect();
error_handler();
});
m.observe(document.body, {childList: true});
{childList: true} tells the MutationObserver to detect nodes added to the DOM and passes them to the callback function as the parameter mutationRecords (which contains array of MutationRecord objects). From there it's up to you what to do next.
This should at least be enough to get you started!
We have our own system which we need to integrate with MS Dynamics 365.For Example : In Accounts section we need to add an extra tab that loads IFrame or something that retrieves some extra information from our system.
The following are the things that I reached :
Inserting IFrame within a new Dashboard: (but it will not fetch specific account information, it will only pass the currently logged in user along with the organization name)
Unified Service Desk (USD): (we may add customization but this is a desktop app and we need it to be on web)
Microsoft flow: this would only work in the background when you create or edit an account (not sure if it has another functionality)
Extensions: Not sure how to use it to achieve the same functionality, I believe the solution may be here but I just need from where to start.
Has anybody done a similar thing before?
Thank you
You can definitely do it,
Here is how I just tried on one of my Trail Instance.
I added new Tab as you need, I called it "HTML Page"
On this Tab I added Webresource, you can add Iframe as well and call your external WebPage.
For my simple use case I created a simple HTML page as webresource in CRM and configured it to Webresource tab as below
Sample code for HTML. Dont worry about long html file. Mostly it is bla bla. What is of our importance is <body onload="myFunction()"> and then in
<script>
function myFunction() {
debugger;
alert("Account Id when from fromcontext is ");
alert(parent.Xrm.getformContext().data.entity.getId());
}
</script>
complete HTML code below
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>
<title>My first styled page</title>
</head>
<body onload="myFunction()">
<!-- Site navigation menu -->
<ul class="navbar">
<li>Home page
<li>Musings
<li>My town
<li>Links
</ul>
<!-- Main content -->
<h1>My first styled page</h1>
<p>Welcome to my styled page!
<p>It lacks images, but at least it has style.
And it has links, even if they don't go
anywhere…
<p>There should be more here, but I don't know
what yet.
<!-- Sign and date the page, it's only polite! -->
<address>Made 5 April 2004<br>
by myself.</address>
<script>
function myFunction() {
debugger;
alert("Account Id when from fromcontext is ", parent.Xrm.getformContext().data.entity.getId());
}
</script>
</body>
</html>
Also on Form Load of account I added additional Javascript. This javascript will create global variable which could be called from your webresource.
Article Link for additional Javascript
Sample code used for Javascript below
formContext=null;
function onload(executionContext){
debugger;
var formContext = executionContext.getFormContext();
Xrm.getformContext = function (){
return formContext;
};
Xrm.getParentAttribute = function (attrName) {
debugger;
return formContext.getAttribute(attrName);
};
Xrm.getParentControl = function (attrName) {
debugger;
return formContext.getControl(attrName);
};
}
Final Result will be something like below
Summary:
Create Wberesource/Iframe
Create Additiona Js on Load
Use global variable in your webresource.
I would like to make an ajax call from javascript code (to check if the user session is still active). I would like my code to be independent of any portlet, and hence would like to build the url in javascript, without having to rely on a portlet id.
Is this possible within the MVCPortlet framework ? If not, are there alternatives ?
Edit below this line.
I am aware of liferay's mechanisms for session management, and I actually have set an automatic extension of the session. But two of my users have lost thier long input because the session expired despite this mechanism (I believe they interrupted their work, and their computer went to sleep...).
I would like to avoid such a situation by checking if a session is still active before I submit an input from certain forms. The way I do it is prepend the submit with an ajax call which I detail below.
My true question is : how do I remove the reliance on portletId in that code so that I don't need to change every portlet in which I want to implement this mechanism.
I do it today with the following javascript function:
Liferay.provide(window, "bb_checkSession",
function (sessionId, portletId, successCallback, failureCallback) {
var A = AUI();
var resourceUrl = Liferay.PortletURL.createResourceURL();
resourceUrl.setResourceId("CHECK_SESSION");
resourceUrl.setPortletId(portletId);
A.io.request(resourceUrl.toString(), {
method: 'GET',
cache: false,
on: {
success: function () {
var responseData = A.JSON.parse(this.get('responseData'));
if (responseData == null || sessionId != responseData.sessionId) {
if (failureCallback) failureCallback();
} else {
if (successCallback) successCallback();
}
},
failure: function () {
if (failureCallback) failureCallback();
}
}
});
},
['aui-io', 'liferay-portlet-url']
);
and in my portlet, I handle the call as follows
public void checkSession(ResourceRequest resourceRequest, ResourceResponse resourceResponse) throws IOException {
PortletSession session = resourceRequest.getPortletSession();
JSONObject jsonObject = JSONFactoryUtil.createJSONObject();
resourceResponse.setContentType("text/javascript");
jsonObject.put("sessionId", session.getId());
resourceResponse.getWriter().write(jsonObject.toString());
}
This can be easily achieved through Jquery. If in your web.xml you have defined session-timeout as 15 mins, then at 14th minute a lightbox will appear which will ask User if he wishes to continue the session or logout.
If User wishes to continue session, then /c/portal/extend_session is called(Ajax) else /c/portal/logout is called.
Below code works independent of any type of portlet. You need to place this code in your JSP/Facelets page.
<script src="/static-files/scripts/jquery-1.6.2.js" type="text/javascript" charset="utf-8"></script>
<script src="/static-files/scripts/jquery-ui.min.js" type="text/javascript" charset="utf-8"></script>
<script src="/static-files/scripts/jquery.idletimer.js" type="text/javascript" charset="utf-8"></script>
<script src="/static-files/scripts/jquery.idletimeout.js" type="text/javascript" charset="utf-8"></script>
<link href="/static-files/css/jquery-ui-rev.css" type="text/css" rel="stylesheet"/>
<script type="text/javascript" charset="utf-8">
var $j=jQuery.noConflict();
$j(document).ready(function()
{
$j("#dialog").attr("style","visibility:visible");
var titletext=$j(this).attr('title');
$j("#dialog").bind("contextmenu",function(event)
{ return false; })
// setup the dialog
$j("#dialog").dialog({
autoOpen: false,
modal: true,
width: 400,
height: 200,
closeOnEscape: false,
draggable: false,
resizable: false,
buttons: {
'Yes, Continue': function()
{
$j.ajax({
url: '/c/portal/extend_session',
cache: false,
success: function() {
$j('div#dialog').dialog('close');
}
});
$j(document).attr('title',titletext);
},
'No, Log out': function(){
$j.idleTimeout.options.onTimeout.call($j.post('/c/portal/logout',function()
{}))
}
}
});
// cache a reference to the countdown element so we don't have to query the DOM for it on each ping.
var $jcountdown = $j("#dialog-countdown");
// start the idle timer plugint
$j.idleTimeout('#dialog', 'div.ui-dialog-buttonpane button:first', {
idleAfter: 840, // 14 mins
onTimeout: function(){
window.location.replace("/c/portal/logout");
},
onIdle: function(){
$j(document).attr('title', 'Warning! Due to inactivity, your session is about to expire.');
$j(this).dialog("open");
},
onCountdown: function(counter){
$jcountdown.html(counter); // update the counter
}
});
});
</script>
<!-- dialog window markup -->
<div id="dialog" title="Your session is about to expire!" style="visibility:hidden">
<p>
<span class="ui-icon ui-icon-alert" style="float:left; margin:0 7px 50px 0;"></span>
You will be logged out in <span id="dialog-countdown" style="font-weight:bold;whitespace:nowrap"></span> seconds.
</p>
<p>Do you wish to continue your session?</p>
</div>
Vikas V gave you some code that you can use - there are two aspects of your question that don't really match my perception...
Liferay already has such a mechanism - e.g. log in to your portal and let it sit for 30 minutes (or configure the timeout to be earlier) and you'll see that you get a warning message, followed by a "you have been logged out" message if you don't click "extend session". in 6.1 this is even working through multiple open tabs (I believe it's using js-cookies to contain a timestamp, so that all tabs timeout at the same time)
if you make a request to the server in order to check if the session is still active, you risk extending the session - e.g. just checking for the session being alive might extend it eternally
Thus, my recommendation is to either hook into Liferay's mechanism (edit your question or comment here if you need hints where to find it, I'd have to look it up) or to use your own fully client side implementation. If you opt for your own implementation (e.g. like Vikas V suggested) , keep in mind that you might have multiple tabs open and you wouldn't want to be logged out by a stale tab that you forgot about in the background.
I have a requirement to display a message confirming a successful database update in an ASP.NET MVC application. Currently the application only shows messages (using a ValidationSummary helper) when an error occurs. On a successful operation, the application currently redirects to a suitable point in the navigation.
Goals are:
Display the confirmation message in an appropriate way
Minimise user actions required to proceed after reading message
Avoid an extra post / round-trip to display the message
Minimise development effort and risk inserting a message at multiple points in the application
My preference would be some sort of tool-tip type message display near the submit button and then a mechanism for removing the message and proceeding with the existing redirection after success.
That seems to suggest an Ajax call rather than the existing HTTP POST to submit the form. How would I go about this?
I Would use TempData["key"]
This is like ViewData["key"] however the data persists for the next HttpRequest and is disposed automatically by asp.net after this
So you can do this.
Controller Action
[HttpPost]
public ActionResult SomePostAction(SomeViewModel vm)
{
if(ModelState.IsValid) // Is User Input Valid?
{
try
{
CommitData();
TempData["UserMessage"] = new MessageVM() { CssClassName = "alert-sucess", Title = "Success!", Message = "Operation Done." };
return RedirectToAction("Success");
}
catch(Exception e)
{
TempData["UserMessage"] = new MessageVM() { CssClassName = "alert-error", Title = "Error!", Message = "Operation Failed." };
return RedirectToAction("Error");
}
}
return View(vm); // Return View Model with model state errors
}
_Layout.cshtml
<!DOCTYPE html>
<html>
<head>
</head>
<body>
#if(TempData["UserMessage"] != null)
{
var message = (MessageVM)TempData["UserMessage"];
<div class="alert #message.CssClassName">
<strong>#message.Title</strong>
#message.Message
</div>
}
#RenderBody()
</body>
</html>
More Info: http://www.devcurry.com/2012/05/what-is-aspnet-mvc-tempdata.html
On a successful operation ,you just store the success message description into ViewBag
like as
ViewBag.successMessage="Success"
then in view check the ViewBag value is null or not? through javascript ,if not null show the message in Div
if('#ViewBag.successMessage'!="")
{
$('#divSuccessMessage').show();
}
else
{
$('#divSuccessMessage').hide();
}
default in page load hide the div
the following links might help you (posting links as it would require better explanation):
http://msdn.microsoft.com/en-us/magazine/ff797575.aspx
http://ofps.oreilly.com/titles/9781449320317/ch_AJAX.html
As others mentioned, TempData is one of the most straight forward options to use. Its main drawback in regular ASP.NET in my opinion is that it uses the session storage in to store its contents. This means that you'll have extra work getting it to function on a web farm, or that you need to turn on sessions in the first place.
TempData is a string based dictionary you can put anything in it, and by default get it out only once on any later request. Before calling RedirectToAction() you set your message and on the next request you check for messages and display them. By retrieving the messages they are automatically deleted at the end of the request.
As an alternative you could use cookies for transporting the message between the two requests. Essentially you could either roll your own solution, or implement a custom ITempDataProvider which transports the contents of TempData via cookies. Given that the messages are short, the performance impact is minimal. Note that you need to properly secure cookies.
I was facing the same problem you did and created a solution for it called FlashMessage. It's available on NuGet. Usage is simple: you simply queue a message before you call RedirectToAction() as follows:
FlashMessage.Confirmation("Your message");
return RedirectToAction("AdminUsers", "Admin");
In your view you include the following statement to render any previously queued messages:
#Html.RenderFlashMessages()
If i feed a page to a user, e.g.:
<!DOCTYPE HTML>
<HTML>
<HEAD>
<SCRIPT type="text/javascript">
function cbCountry_Click()
{
var select = document.getElementById("cbCountry");
select.options[select.options.length] = new Option("Canada", "CA");
select.options[select.options.length] = new Option("United States", "US");
}
</SCRIPT>
</HEAD>
<BODY>
<SELECT id="cbCountry"></SELECT>
<P><BUTTON onclick="cbCountry_Click()">Get Countries</BUTTON>
<P>Visit a link
</BODY>
</HTML>
This page has the capability to modify itself. In this case it's standalone javascript, but imagine it's AJAX code.
If the user then clicks a link to go forward, then clicks to return back to this page; they will be presented with the page as it is cached; rather than how they left it:
Has anyone solved the AJAX problem?
i notice that Google periodically sends the state of your page to the server. If you return to the page they force a timer refresh, which refreshes the state of the page from the server.
i've also noticed that some people simply force the page to not be cached:
Cache-Control: nocache
preventing the page from being cached. Downside of that is that it prevents the page from being cached.
You could use a cookie to store the state on the client side and restore the state of the page from the cookie whenever your page is loaded.