A better way of passing variables from controller to view in symfony - authentication

Hey.
I've got a login form with post as method. The action goes to 'auth/login' and will check the database if the user exists. If the user exists, I call the $this->getUser->setAuthenticated(true);. After this I want to redirect to a welcome page if success.
If the login failed, I would want to tell the user so in the view of course. But settings variables in the controller only if login failed, and check in the view if each of those variables are set, is a lot of work?
This means I have to check almost all variables I want to use in the view set from the controller. If it should happen that it is not set, and I just go ahead and echo it, I get an error from symfony, and production stage-mode-ish don't show anything but an 500 internal server error .
Thanks
EDIT:
This is my current, new and better solution. Still looking for feeback.
in /templates/loginSuccess
if ($sf_params->has('bad_login')) {
echo "Wrong username or password";
}
And in my controller:
$this->redirect('auth/login?bad_login=');

Take a look at how sfDoctrineGuardPlugin (the de-facto standard for authentication) does it: they created sfGuardValidatorUser and use it as a post validator in the signin form.
Advantage of this method: the form takes care of the username/password validation, you do not need to put that code in your action. It simplifies that to a simple $form->isValid() { $this->redirect("#homepage"); }.

It seems like you could use symfony's form to take care of the validation. Since the forms show errors built in, you could put this into the form validation and then your controller looks something like:
$form = new LoginForm;
if ($request->isMethod('post'))
{
if ($form->isValid())
{
$this->redirect('account');
}
else
{
// this would show the form, and since you put the login in the form validation it will show errors. You could have the username show the error
}
}
To do what you are doing though, I'd recommend this. That way you aren't accessing any parameters in the view as well.
Controller:
$this->bad_login = $this->getParameter('bad_login',false);
View:
if ($bad_login) { echo 'bad login'; }

Use forward()
Put all the logic required for the view population into separate method of a controller, and call it in both places.
Use cgratigny's solution - put login form and processing code in a single action, and redirect to welcome page if isMethod('post') && $login_success

Related

Prestashop 1.6: how to load a different template after an admin form submission?

I'm new to Prestashop and currently working on a custom admin module in 1.6.
My scenario is, users can load orders to this module/admin controller and from the list they can select which ever order they like using 'Select All' checkbox selector.
And then these selected order ids are submitted back to admin controller to be displayed on a different template with full information in a form.
And then again this form will be submitted to a third party API for further processing.
Now my problem is I can get the order listing to my admin controller and get them submitted back to the same controller. But I do not know how to switch to a different template to display in a form.
And also how to call a different method to process and export once second form substitution is done.
Any advice would be greatly appreciated.
Thanks in advance
Roshan
In your AdminController extend the method initContent with a condition that is you need to check if a certain button was pressed. Something like
public function initContent()
{
if (Tools::isSubmit('the_button')) {
'do what you want to do'
}
parent::initContent();
}
if you want to redirect to a different controller use Tools::redirectAdmin() and set the path of redirection like Context::getContext()->link->getAdminLink('your_another_controller', true), also you can send all necessary data with the third parameter of the method(array)
public function initContent()
{
if (Tools::isSubmit('the_button')) {
Tools::redirectAdmin(
Context::getContext()->link->getAdminLink('your_another_controller', true, $orders)
);
}
parent::initContent();
}
You can use as many conditions, inside the method, as you need so I hope it will help you in all your cases.

Calling a controller method (from an external email link) that does not return a View, but simply exits

I have an MVC 4 Razor intranet app using Windows credentials where a new user must register (existing users are automatically redirected to the main user page). This generates an approval request email to the admin and returns a view with an Exit button simply saying your application has been submitted. The user then closes the app.
The email is in HTML and presents the user's entered data and has Approved or Declined selections. It then has a button to invoke code to insert the user into the Members table (if accepted) and return an email to the user with the decision.
Since some time may transpire between the app mailing the admin and the admin making the decision, the session will originally terminate. I need to have the email invoke a method to persist the new user, email the decision, and then simply exit. It will not involve the browser in any way, so no Views are involved. I could write this as a background console app, but that would involve duplicating a lot of code in the MVC app - with referential integrity issues on bug fixes or updates.
How can I write a method in the Controller that can be invoked by a link in the email as if from a browser that does the work and then exits without returning anything to a browser?
If I make the method an ActionResult method and return new EmptyResult() or return(null) I assume it will try to return an empty page to nowhere.
Can I alternatively construct a method in my Controller, where it has access to all of the support code, like?
public void EnrollMember(Member member, bool decision)
{
if (decision == true)
{
// insert new user into Members table
// generate accepted email
}
else
{
// generate declined email
}
}
and then just link to it the same way I link to Index(), /MyController/EnrollMember(...)?
There is no main() in the app since it is an ASP.NET MVC app, and I don't know how to terminate the app from within a Controller method without trying to return something, instead of from a View in the browser.
I'm a long-time programmer, but a .NET newbie so this probably has a simple answer.
The "view" is just the response. You don't necessarily have to return a view, but you must return a response. There's no way around that. If the link opens in a browser, then something will be displayed, regardless. Even if you were to just return an empty ContentResult, at least a blank page will be displayed in the browser.
To achieve something akin to what you're looking for, your best bet would be to return an HTML document with just a simple bit of JavaScript that will act to close the window:
<html>
<body>
<script>
window.close();
</script>
</body>
</html>

How do I simply set the ModelStateError from the HandleUnauthorizedRequest method?

So what is happening is that I have a condition within my override of the HandleUnauthorizedRequest method in my custom authorize attribute. Up to this point, I've been throwing a 403 which gets picked up and redirects to a custom error page. Well now, that's not really what I want. What I actually want is to show the same login page but add a message to the validation summary "You do not have access to this resource.", that way it's a bit more user friendly. It'll indicate that your creds were good, but you don't belong here.
I thought something like this would work:
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
// passed authentication, failed authorization
if (filterContext.HttpContext.User.Identity.IsAuthenticated)
{
filterContext.Controller.ViewData.ModelState.AddModelError("", "Not Authorized");
return;
}
base.HandleUnauthorizedRequest(filterContext);
}
But this isn't working. What's happening is that the login page simply reloads. So this makes me feel like I'm close, but I need that model error to show up.
Any ideas?
UPDATE:
It would seem that the Controller that I'm adding an error to here is actually controller of whichever action had the attribute that led to here. I need to somehow add the error to the login controller. Not sure if that's even possible.
You are calling the base method here:
base.HandleUnauthorizedRequest(filterContext);
If you are using Forms Authentication this base method simply redirects you to the login page. And a redirect means a new HTTP request from the client. The current context and whatever you stored in it is lost. Well, to be more precise, the base method is returning a 401 HTTP status code which is then intercepted by the FormsAuthenticationModule which redirects to the login page defined in your web.config. But this implementation details is not important.
What you could do is perform the redirect yourself to the login page instead of leaving it to the base method. You could do this by setting the filterContext.Result property to a RedirectToRouteResult instance. In this case you could pass the error message as a query string parameter.
UPDATE:
According to your updated question it seems that you are calling return; after setting the ModelState value and not calling the base method and thus no redirect will happen to the login url. You could in this case return some error view by setting the filterContext.Result to an instance of a ViewResult in which view you could use the value you stored in the ModelState.

Setting returnURL for CButtonColumn button

I'm looking at the controller for the default Delete button in the CButtonColumn class. It manages to return to the previous web-page after deleting a CGridView line and remain on the same page of the CGridView, as opposed to going to the first page. The lines responsible for this in the associated controller seem to be:
if (!isset($_GET['ajax']))
$this->redirect(isset($_POST['returnUrl']) ? $_POST['returnUrl'] : array('admin'));
I would like to create a new custom button that has this behavior (i.e. returning to the previous view without resetting the pagination to page 1), but simply including the above lines of code in the button's associated action does not do the trick. I think I need to send that 'returnUrl' parameter somehow, but I cannot figure out how :)
The 'returnUrl' code you are looking at uses a POST variable for the returnUrl. To use this, you will need to POST that somehow. On the View this code is called from I am assuming there is a <input name="returnUrl"> field in the form. You should make sure this field (populated with the correct URL value) is on all of the Views you are POSTing from in order to access that POST variable in your Controller action.
If you are POSTing to the deleteAction via AJAX, I think you can set the $_POST['returnUrl'] variable with the jQuery AJAX function.
Another way to go might be to use CWebUser's returnUrl SESSION variable instead of this POST variable. I have never done this, but it's built in to Yii so I assume it works OK.
I never really liked the hacky $_POST['returnUrl'] that Gii generates anyway.
ANOTHER thing you could do, possibly, is look at the $_SERVER['HTTP_REFERER'] variable, and use that for the return redirect in your deleteAction. I don't know if that will be set correctly though, with complications from the 302 redirect/rewrites that Yii does.
Good luck!
You can set the return url via the CHtml::link call. Here is an example using delete
CHtml::link(
'Delete',
'#',
array('submit'=>array('delete','id'=>$model->id),
'params'=>('returnUrl'=>'controller/action...'),
'confirm' => 'Are you sure?'
)
);
Pulled from this Stackoverflow answer.

authentication in CodeIgniter

in the project I'm creating I need to check if the user is logged in or not, the tutorials I have seen do explain how to authenticate in the controllers and give access to a page or not. But I want all the pages to be visible to everyone but only show certain options if a user is logged in or not.
something like this in the views
if(is_logged_in()):
//some options here
else:
echo "you need to login to have more options";
endif;
so where should I add this code? in the helper folder?
EDIT: I'm now checking in the views like this, it works but I don't know if it's a best practice. The 'is_logged_in' is something I set to true when the credentials were validated
if($this->session->userdata('is_logged_in'))
EDIT:
so if I make a helper to call that function. Can I check using the userdata function?
this is the function that creates the session
$data = array(
'username' => $this->input->post('username'),
//usertype toevoegen hier
//email toevoegen
//deposit money
'is_logged_in' => true
);
$this->session->set_userdata($data);
How could I used the session data in the function in my helper file?
If you want to have it as a stand-alone function that you can call from anywhere then you are best making it an helper. It might be helpful to think of helpers as the blades of a swiss army knife in your CodeIgniter toolbox.
That way you can change your checks later, move things all around, and still be making calls to isloggedin(). However, both ways work. $this->user->isloggedin() is slightly more verbose, but presents the same useful separation of concerns.
EDIT:
If you want to make calls to your session data in a helper, the way to do that is via get_instance().
In the beginning of your helper file, do this: $CI =& get_instance();
function user_logged_in() {
$CI =& get_instance();
// Do what you want to do with session.
// Simply replace $this->session ... etc. with
// $CI->session ... etc.
...
}
It would be fine to add it into the view, and this is presentation logic.