backbone.dualStorage load from localStorage after refresh - javascript

I am trying to build an offline capable app with Backbone and dualStorage. I am having a problem where if I go offline and refresh the app 404's.
This is my current start up code. It checks if a cookie is present and if so tries to instantiate that session again. The problem is with the refresh fetch() errors out and I get a 404. How do I make dualStorage check the localStorage if online endpoint isn't available?
The localStorage is populated with the right data, and is made so by calling Session.save(); after successful login.
// Start App
Router = new AppRouter({});
var cookieSessionName = window.location.hostname.replace(/[^A-z0-9]/ig, '-') + '-cisession';
if($.cookie(cookieSessionName) !== null) {
Session.set({ id: $.cookie(cookieSessionName) });
Session.fetch({
success: function()
{
$('.user-name').html('Hi, '+Session.get('first_name'));
$('.logged-in').show();
$('.logged-out').hide();
property.collection.fetch();
owners.collection.fetch();
}
});
} else {
$('.logged-out').show();
$('.logged-in').hide();
}
Backbone.history.start({ pushState: true, root: '/' });

Related

FlowRouter.go(redirect) gets triggered, but does not actually redirect

FlowRouter.go(redirect); //gets triggered, but site does not actually redirect until refreshed.
I followed this guide to structure my routes:
var authorised = FlowRouter.group();
var publicRoutes = FlowRouter.group();
FlowRouter.triggers.enter([isUserSignedIn]);
authorised.route('/',{
name:'root',
action(){
BlazeLayout.render('App_body',{ main: 'App_home'});
}
});
publicRoutes.route('/welcome',{
name : 'welcome',
action(){
BlazeLayout.render('Unauthorised', { main: 'welcome' });
}
});
function isUserSignedIn(){
if (!Meteor.user() || Meteor.loggingIn()){
var route = FlowRouter.current();
if (route.path != "/welcome") {
// Set Session to redirect path after login
Session.set("redirectAfterLogin", route.path);
}
console.log("user is not signed in");
FlowRouter.go('welcome');
}
};
// Redirect After Login
Accounts.onLogin(function(){
console.log("Accounts.onLogin()");
var redirect = Session.get("redirectAfterLogin");
if (redirect){
console.log("redirect path exists")
if(redirect != "/welcome"){
console.log("redirect is not welcome path, redirect to ", redirect);
FlowRouter.go(Session.get("redirectAfterLogin"));
}
}
else{
// if redirect doesn't exist, go "/"
console.log("no redirection, go root");
FlowRouter.go('root');
}
})
// Not Found
FlowRouter.notFound = {
action() {
BlazeLayout.render('Unauthorised', { main: 'App_notFound' });
},
};
The code above does the following:
Case 1: Force Session.set("redirectAfterLogin", "/blah");
Logout of the app.
Enter in console Session.set("redirectAfterLogin", "/blah");
Login
Observe the following output in console:
Accounts.onLogin()
redirect path exists
redirect is not welcome path, redirect to /blah
But I am still on the "Unauthorised" Layout, with "welcome" template".
Press refresh, I get redirected to "Not Found" - this is the correct result.
Case 2: Session.get("redirectAfterLogin") is undefined
Logout of the app.
Enter in console Session.set("redirectAfterLogin");
Login
Observe the following output in console:
Accounts.onLogin()
no redirection, go root
But I am still on the "Unauthorised" Layout, with "welcome" template".
Press refresh, I get redirected to "/" - this is the correct result.
What exactly is hindering the logic here? Please help!
I had this problem when trying to redirect after logout in an event:
'click .js-logout'() {
Meteor.logout();
FlowRouter.go('signin');
},
My quick solution was to add timeout for calling router:
'click .js-logout'() {
Meteor.logout();
// we have to do redirect a bit later because logout is interfering the redirection
setTimeout(
() => {
FlowRouter.go('signin');
}, 100
);
},
You might want to increase the timeout.
This was the reason for my problem, the roles was not subscribed properly and thus I was stuck on the unauthorised layout. I hope this helps!
FlowRouter.wait()
// Tracker.autorun ->
// # if the roles subscription is ready, start routing
// # there are specific cases that this reruns, so we also check
// # that FlowRouter hasn't initalized already
// if Roles.subscription.ready() and !FlowRouter._initialized
// FlowRouter.initialize()
Tracker.autorun(function(){
if (Roles.subscription.ready() && !FlowRouter._initialized){
FlowRouter.initialize();
}
});

Meteor JS (Iron Router) - Restricting access to server routes

I have a download route in my MeteorJs app which i want to restrict access to. The route code is as follows
Router.route("/download-data", function() {
var data = Meteor.users.find({ "profile.user_type": "employee" }).fetch();
var fields = [...fields];
var title = "Employee - Users";
var file = Excel.export(title, fields, data);
var headers = {
"Content-type": "application/vnd.openxmlformats",
"Content-Disposition": "attachment; filename=" + title + ".xlsx"
};
this.response.writeHead(200, headers);
this.response.end(file, "binary");
},
{ where: "server" }
);
The route automatically downloads a file. This is currently working but I want to restrict access to the route. I only want admins to be able to download it.
I have created an onBeforeAction Hook as below
Router.onBeforeAction(
function() {
//using alanning:roles
if(Roles.userIsInRole(this.userId, "admin"){
console.log('message') //testing
}
},
{
only: ["downloadData"]
}
);
and renamed my route as below
//code above
this.response.writeHead(200, headers);
this.response.end(file, "binary");
},
{ where: "server", name: "downloadData" }
);
The onBeforeAcion hook does not take any effect
Also I noticed neither this.userId nor Meteor.userId works on the route
For the server side hook, I am pretty sure you need the onBeforeAction to have the { where: "server" } part as you do for your route.
Also, I don't think iron:router ever implemented server side user auth on their routing. You may want to check into a package around server routing with larger features such as mhagmajer:server-router that has access to authenticated routes.
https://github.com/mhagmajer/server-router

PayPal in-context checkout doesn't always trigger startFlow?

We've built an online store that integrates the PayPal in-context / express checkout. This is using the Classic NVP API.
It has been receiving the token every time and logging to the console that it is starting the payment flow. However, every now and then it will not redirect the modal to the checkout, but I can run paypal.checkout.startFlow('<token_from_console>'); in the console and it successfully redirects.
Here's the js for the checkout process:
window.paypalCheckoutReady = function () {
paypal.checkout.setup('<?=$paypal_merchantID?>', {
locale: 'en_AU',
<? if ($paypal_platform == 'sandbox') { ?>environment: 'sandbox',<? } ?>
button: ['submitButton'],
condition: function() {
return $('#orderForm').valid();
},
click: function() {
// INITIALISE CHECKOUT
paypal.checkout.initXO();
// SET EXPRESS CHECKOUT AND GET TOKEN
setCheckout = $.post("/checkout.php?mode=setExpressCheckout", $("#orderForm").serialize());
setCheckout.done(function(response){
console.log(response);
if (response.substr(0,2) == 'EC') {
paypal.checkout.startFlow(response);
console.log('starting paypal flow');
}
});
setCheckout.fail(function(reponse){
paypal.checkout.closeFlow();
});
}
});
};

How to redirect to external URL and collect client data in Meteor

My goal is to create a link which redirects to an external URL and track client data like OS, Browser etc.
To achieve this, I created two separate routes. One client route which redirects to a template that tracks client data and redirects to the server route.
Here are my routes:
Router.route('/:_id', {name: 'url', controller: 'UrlController'});
Router.route('/redirect/:_id', {name: 'urlRedirect', where: 'server'}).get(function () {
var url = Urls.findOne(this.params._id);
if (url) {
this.response.writeHead(302, {
'Location': url.url
});
this.response.end();
} else {
this.redirect('/');
}
});
UrlController = RouteController.extend({
action: function () {
this.render('redirect');
},
data: function () {
return Urls.findOne(this.params._id);
}
});
And here is the template:
Template.redirect.onRendered(function () {
var client = new ClientJS(); // Create A New Client Object
var userAgent = client.getUserAgent(); // Get User Agent String
console.log(userAgent);
Router.go('urlRedirect', {_id: this.data._id});
});
Now my question is, is it possible to collect client data from the server route (do I need the internal redirection from :_id to /redirect/:_id)?
If a user has been redirected and he clicks on the browser's 'back' button, he will see the empty redirect template. How can I fix this?
You can get header information from the nodejs request object in your route. For example, how to get the user-agent string:
Router.route('/asd', {where: 'server'}).get(function () {
var request = this.request;
var response = this.response;
var headers = request.headers;
var userAgent = headers["user-agent"];
console.log(userAgent);
response.end();
});

Backbone.js PushStates: Fallback for Internet Explorer not working

My site has just implemented pushstates in Backbone.js and the entire site breaks for IE. How should I create a fallback for IE?
What I am trying to achieve
Main URL: http://mydomain.com/explore
Another URL: 'http://mydomain.com/explore/1234
The main page of the site is http://mydomain.com/explore which triggers the router function explore.
When a user visits http://mydomain.com/explore/1234, Backbone's router will trigger the function viewListing, which is the same as function explore, but also includes details for item id 1234.
Backbone.js Router
// Router
var AppRouter = Backbone.Router.extend({
routes: {
'explore': 'explore',
'explore/:id': 'viewListing',
},
explore: function() {
this.listingList = new ListingCollection();
// More code here
},
viewListing: function(listing_id) {
this.featuredListingId = listing_id; // Sent along with fetch() in this.explore()
this.explore();
}
});
App = new AppRouter();
// Enable pushState for compatible browsers
var enablePushState = true;
// Disable for older browsers (IE8, IE9 etc)
var pushState = !!(enablePushState && window.history && window.history.pushState);
if(pushState) {
Backbone.history.start({
pushState: true,
root: '/'
})
} else {
Backbone.history.start({
pushState: false,
root: '/'
})
}
Problem: As you can see in the above code, I tried to disable pushstates with pushState: false if it is an incompatible browser.
However for IE to access what would normally work for a normal browser (http://mydomain.com/explore), IE will need to go to http://mydomain.com/explore/#explore which is making things confusing! Further more to access http://mydomain.com/explore/1234 IE needs to go to http://mydomain.com/explore/#explore/1234
How should this be fixed?
If you don't want http://mydomain.com/explore/#explore url, then you have to redirect to
http://mydomain.com/#explore so Backbone will start with it instead.
if(!pushState && window.location.pathname != "/") {
window.location.replace("/#" + window.location.pathname)
}
UPD: you'll probably have to remove the leading slash when setting path as a hash window.location.pathname.substr(1)
UPD2: if you want /explore/ to be the root for your backbone routes then you have to exclude it from routes and set as a root in History.start({root: "/explore/"})
routes: {
'': 'explore',
':id': 'viewListing',
}

Categories

Resources