I'm not sure what I am doing wrong here. I'm following this example here: https://gist.github.com/mikermcneil/5737561.
I want to chain two controller actions to one 'get' route. I need to return some json data and also a view. When attempting to send the data with the view I get an socket.io error message that says I can't send information through views.
'get /users': [
{
controller: 'UserController',
action: 'users'
},
{
controller: 'UserController',
action: 'getuser'
}
],
Right now to make it work I have to have two 'get' routes. One that returns my view ejs file and another that the socket can connect too.
var socket = io.connect('http://localhost:1337');
socket.get('/user', {}, function(users) {
var grid = new Slick.Grid("#userGrid", users.users, columns, options);
});
This works but then I have a random /user route out there that anyone can access that just returns json. I'd like to not have random routes that can be accessed through the browser if possible. So can I chain controller actions to one route? Or is there a way to return a res.view and json data in one action?
users: function(req, res, next) {
//User.find().populateAll().exec(function(err, users){
res.view('user/users');
next();
// res.json({
// success: true,
// users: users
// });
//});
},
//get user data and send it as json to for sockets
getuser: function (req, res) {
User.find().populateAll().exec(function(err, users) {
res.json({users: users});
});
},
I tried using next() and without. Thanks for any help!
Related
EDIT
I noticed that the subscribe event must come first before and publish get called. But it will be silly to ask user to open TabOut page every time when app start.
I do not need to always reloading the TabOut page, so I need this event sort of method to do the job. Or else could've just call the reload on ionViewDidEnter().
I have 2 Tabs and 1 modal. /TabIn, /TabOut, and /ModalIn.
The Tabs page serve as data listing which display the data from database on ionViewDidLoad().
The ModalIn page serve as data entry for the user to key in and submit data. This page resides in the TabIn page and will get called when user clicked on each of the list of data.
After successfully submit the form in the ModalIn page I want to call refresh again on the TabOut page (no matter it has been loaded before or not). I tried using events publish it is not working. Below are my code.
ModalIn .ts
let headers: any = new HttpHeaders({ 'Content-Type': 'application/x-www-form-urlencoded' }),
options: any = { "username": val, formValue },
url: any = "some_url_here";
this.http.post(url, options, headers)
.subscribe((data: any) => {
if (data.status == 'success') {
this.events.publish('shouldReloadData');
} else {
}
},
(error: any) => {
console.log(error);
});
TabOut .ts
constructor(public events: Events) {
events.subscribe('shouldReloadData', () => {
// Reload the page here
console.log("should reloadddd"); // <- This is not working
});
}
Call subscribe with this keyword inside TabOut.ts.
constructor(public events: Events) {
this.events.subscribe('shouldReloadData', () => {
});
}
I use Firebase with VueJS (and VueRouter).
I have a problem with redirecting. I want to redirect between two pages. The first page is used for authentication and the second one for content that should only be visible to logged-in users.
My state holds the firebase user key (which will be populated through a mutation, that calls firebase):
state: {
user: { key: null }
}
The authentication page these lines:
beforeCreate() {
if (this.$store.state.user.key !== null) {
this.$router.replace('/')
}
}
And the secret page these:
beforeCreate() {
if (this.$store.state.user.key === null) {
this.$router.replace('/new')
}
}
But: the redirect from the authentication page to the secret page doesn't take place.
My Vue-dev-tools show that the user-key is set.
What could be the solution to this problem?
EDIT:
This is the mutation that calls Firebase and sets the user-key:
updateSession(state) {
auth.onAuthStateChanged((user) => {
if (user) {
state.user.key = user.uid
}
})
}
Here is the action:
UPDATE_SESSION({ commit }) {
commit('updateSession')
}
I call the action in my root component (App.vue):
beforeCreate() {
this.$store.dispatch('UPDATE_SESSION')
}
EDIT 2:
Now my routes array:
routes: [
{ path: '/', component: Secret },
{ path: '/new', component: Authentication }
]
Take a look at the Per-Route Guards section of the docs: https://router.vuejs.org/en/advanced/navigation-guards.html
You might want to try something like the below. By putting the beforeEnter guard on the route, you are telling Vue to do that first. The next argument tells VueRouter what to do next, and can redirect if needed or continue on to the original route.
beforeEnter(to, from, next) {
if (this.$store.state.user.key === null) {
next('/new')
}
}
EDIT
You may also want to try using push instead of replace
As per the conversation we had in the comments looks like you require this:
store.dispatch can handle Promise returned by the triggered action handler and it also returns Promise. See docs.
So you can setup the login action to retirn a promise like this:
a_logInUser: ({state, commit}, userInput) => {
return new Promise((resolve, reject) => {
firebase.auth().signInWithEmailAndPassword(userInput.email, userInput.paswword);
resolve();
});
}
Then in your authentication page where you tale the login input details and click the login button , set this up as the click handler of your login button
loginUser(){
this.$store.dispatch('a_logInUser', {email: this.email, password: this.password})
.then((result) => {
this.$router.replace('/');
}, (err) => {
// stay on this pageS
//handle login error
});
}
}
I am trying to implement user authentication in my sails app.. But I am encountering a problem in different controllers that their action are being called twice.. I have checked from my browser and the request is only being sent once.. Here is an example..
// api/controllers/AuthController.js
...
logout: function (req, res) {
console.log("Loggin out");
req.logOut();
res.json({message: 'Logged out succesfully'});
},
...
Following is my config/routes.js file. (using get for many action just for sake of ease for testing api..)
module.exports.routes = {
// By default, your root route (aka home page) points to a view
// located at `views/home/index.ejs`
//
// (This would also work if you had a file at: `/views/home.ejs`)
'/': {
view: 'home/index'
},
// testing the api
'get /users/check' : 'UserController.test',
'get /login' : 'AuthController.process',
'get /logout' : 'AuthController.logout',
'get /signup': 'UserController.add',
'get /verify/username/:username?' : 'UserController.checkUsername',
'get /verify/email/:email?' : 'UserController.checkEmail',
// add friend
'get /:user?/addfriend': 'FriendController.addFriend',
// accept request
'get /:user?/friendrequest/:request?/accept': 'FriendController.acceptRequest',
};
I have applied the isAuthenticated policy on this action.. which is like
module.exports = function(req, res, next) {
if(req.isAuthenticated()) {
console.log("Valid User");
return next();
}
else {
console.log("User not logged in");
return res.json({error: "Please login"});
}
};
No whenever I call <myhost>/logout I get the following json back..
{
"error": "Please login"
}
and here is the output on the server..
Valid User
Loggin out
User not logged in
This means that my controller's action is being called twice.. and this is not the problem with only this controller. The UserController.add action has the same problem. I seem to be doing every thing fine but I don't know where this problem is coming from. Can any one suggest how can I debug it . Or what could be the root of the problem. As far as I have check..
Browser is not sending the request twice.
The Controller's action is being called twice and so are the middleware assosiated with it.
Oh i have the same Problem a few weeks ago.
Sails also call the middleware on static files (like your styles.css). Console.log the req-object than you see what your browser requested.
There a two Ways to handle this Problem:
1.) Try to set skipAssets: true in your route (see: http://beta.sailsjs.org/#/documentation/concepts/Routes/RouteTargetSyntax.html)
2.) In your policy add an if-condition to skip assets (like ".js", ".css" and so on).
In one controller I want to render a certain view with a certain layout to send an email with the resulting string, but I obviously do not need to show the result to the user. Is there a way to use the EJS engine that I'm using to render views to achieve this? Here's my a bit simplified controller action:
setEmail: function(req, res) {
var update = {
activationToken: _getToken(),
email: req.param('email')
};
Profile.update(res.locals.profile.id, update).then(function(profile) {
res.redirect(profileUrl);
mailer.sendActivationEmail(
update.email,
res.i18n('Подтвердите свой адрес электронной почты'),
emailString); // <=== Here is where I need the string rendered from a view
});
},
Use the view-hook
Profile.update(res.locals.profile.id, update).then(function(profile) {
res.redirect(profileUrl);
sails.hooks.views.render("viewname",profile, function(err,html){
if(err) return console.log(err);
mailer.sendActivationEmail(
update.email,
res.i18n('Подтвердите свой адрес электронной почты'),
html
);
})
});
Edit: right callback
I think I would rather use a specific email module like this one:
https://github.com/niftylettuce/node-email-templates
Which can access EJS templates
I'm trying to use the routes.js to define a route to '/account'.
I want whoever is trying to access that path to go through the UserController and the checkLogin action and if the security check passes, then the user should be rendered with the defined view which is home/account
Here is my code:
routes.js:
'/account': {
controller: 'UserController',
action: 'checkLogin',
view: 'home/account'
}
policies.js:
UserController: {
'*': 'isAuthenticated',
'login': true,
'checkLogin': true
}
It let's me view /account without going through the isAuthenticated policy check for some reason.
There looks to be a little confusion here as to how policies, controllers and views work. As #bredikhin notes above, your controller will never be called because the route is being bound to a view. It's also important to note that policies cannot be bound to views, only to controllers. The correct setup should be something like:
In config/routes.js:
'/account': 'UserController.account'
In config/policies.js:
UserController: {
'*': 'isAuthenticated' // will run on all UserController actions
// or
'account': 'isAuthenticated' // will run just on account action
}
In api/policies/isAuthenticated.js:
module.exports = function(req, res, next) {
// Your auth code here, returning next() if auth passes, otherwise
// res.forbidden(), or throw error, or redirect, etc.
}
In api/controllers/UserController.js:
module.exports = {
account: function(req, res) {
res.view('home/account');
}
}
To put it short: either controller/action-style or view-style routing should be used within the same route in routes.js, not both simultaneously.
According to the router's source code, once there is a view property in a route object, binding stops, so basically Sails never knows to which controller your /account path should be routed, which means that your UserController-specific policy config never fires.
So, just remove the view property from the route, you can always specify the view path (if you want a non-standard one) with explicit rendering from within your action.
For statics work with policies, you can set your route with controller and action:
'GET /login': 'AuthController.index',
And set view/layout in your controller:
index: function (req, res) {
res.view('auth/login', { layout: 'path/layout' } );
},