Laravel db transaction half condition - database

Hi i found some bug in my laravel app and wondering how to fix it :/
My controlers code
public function patvirtinimas($id,$bookid)
{
return \View::make('grazintiknyga.patvirtinti',compact('id','bookid'));
}
public function grazintiknygasave($id,$bookid,Request $request)
{
if(Input::get('taip'))
{
$grazinimas = Carbon::now();
$grazinimas->format("Y-m-d");
$kasprieme = Auth::user()->id;
$resetas = NULL;
//dd($kasprieme);
DB::beginTransaction();
try {
DB::table('borrows')
->where('id', $id)
->update(['grazinimo_data' => $grazinimas,
'prieme' => $kasprieme
]);
DB::table('books')
->where('id', $bookid)
->update(['isdavimo_data' => $resetas,
'terminas' => $resetas,
'grazinimo_data' => $resetas
]);
DB::commit();
// jeigu viskas gerai
} catch (\Exception $e) {
DB::rollback();
dd($e);
// jeigu kazkas negerai
}
return \Redirect::to(url('grazinti-knyga'))->with('grazinta','Knyga grąžinta sėkmingai!');
}
elseif(Input::get('ne'))
{
return \Redirect::to(url('grazinti-knyga'))->with('negrazinta','Knygos grąžinimas atšauktas!');
}
}
One function for viewing other for updating tables in db
routes
Route::get('patvirtinti-grazinima-{id}-{bookid}', 'BorrowController#patvirtinimas');
Route::post('grazinimas-save-{id}-{bookid}', 'BorrowController#grazintiknygasave');
The problem is when i edit route directly in my browser grazinimas-save-{someid}-{somebookid}
When one of parameters matches other dont then half of db transaction works and
other doesn't update and destroys my db :? can some one help fix this bugs ? that both parameters must match in db to update. Maybe there is some parameters hidding and validation?

Slashes / are the expected way to separate arguments in your routes.
Your parameters are not getting passed on properly to your Controller.
Changes the routes to the following (if you can)
Route::get('patvirtinti-grazinima/{id}/{bookid}', 'BorrowController#patvirtinimas');
Route::post('grazinimas-save/{id}/{bookid}', 'BorrowController#grazintiknygasave');
Another option is to handle the logic in your Controller or a Middleware (https://laracasts.com/discuss/channels/laravel/using-dash-instead-of-slash-in-routes)

Related

How to redirect url from angularjs login submission via laravel 5

i'm developing my website with angularjs and laravel5. i wrote code for login and registration page in both angularjs and laravel5 where validate my value and insert everything works good but redirect url in laravel 5 not occur .
i wrote code like return redirect('Home/profile') in login controller. it returns total page to angularjs controller not redirecting page.
routes.php in laravel:
Route::group(array('prefix'=>'api'),function(){
Route::resource('register','Registration\RegisterController#basicForm');
Route::resource('login','Registration\RegisterController#makeLogin');
});
my controller :
public function makeLogin()
{
$email=Input::get('email');
$pwd=Input::get('pwd');
$verify=Authenticated::attempt($email,$pwd);
if($verify)
{
return redirect('Home/profile');
}
else if($verify=='user')
{
return redirect('/')->with('Email address mismatch');
}
else if($verify=='pwd')
{
return redirect('/')->with('Password Authentication Failed');
}
}
i send post request from angular js controller via factory method:
this.scope.authUserInfo.authenticateUser(this.scope.signin).then(function(data){
console.log(data.data);
});
In this console.log,display 'Home/profile' page
I can see many mistakes in the Laravel code.
What is Authenticated in your code? The authentication service in Laravel is called Auth. The way you use the attempt() method is not correct; this is the method signature:
attempt(array $credentials = array(), bool $remember = false, bool $login = true)
so you should pass the email and the password in the first parameter as an array, something like:
$verify = Auth::attempt(['email' => $email, 'password' =>
Moreover, the attempt() method returns a boolean: true on success and false on failure. Your code
if ($verify) {
// ...
} else if ($verify == 'user') {
// ...
} else if ($verify == 'pwd') {
// ...
}
has no sense and you never run the else parts because on failure false is always different from either 'user' or 'pwd'. So, when the authentication fails you reach the end of the makeLogin() method and Laravel returns a blank page.
You should use something like:
if ($verify) {
// authenticated: go to the profile page
} else {
// username OR password are wrong
}
(In my opinion you shouldn't give hints on what of the two is wrong for security reasons: a potential attacker would know if he/she guessed a right email and concentrate the attempts on guessing the password.)
If you really want to give a hint to the user on what was wrong with her data, you should use a different technique, like searching the users table for a record with the right email to know whether the user exists (the provided password was wrong) or not (the provided email was wrong).
On the client side, I don't think Angular will redirect on your own. See answer to Handle an express redirect from Angular POST, even if in that question the server uses ExpressJs and not Laravel, but the basics are the same.
You should understand that in most cases an Angular client expect to receive only data and not a full HTML page. Here is my little attempt to do what you want:
On the Laravel side:
public function makeLogin(Request $request)
{
$email = $request->get('email');
$pwd = $request->get('pwd');
if (Auth::attempt(['email' => $email, 'password' => $pwd])) {
// authenticated!
// if you return an array from a controller public method, Laravel
// will convert it to JSON; I also use the url() Laravel helper to
// generate a fully qualified url to the path
return [
'status' => 'redirect',
'to' => url('home/profile')
];
}
// failed
return [
'status' => 'failed',
'message' => 'Email or password are wrong'
];
}
Now the method will return a JSON answer. On the Angular side, you can do something like (I'm not an Angular guru, there could be mistakes here):
this.scope.authUserInfo.authenticateUser(this.scope.signin).then(function(data) {
if (data.response == 'redirect') {
$location.url(data.to);
} else {
// failed: you can show the error message
console.log(data.message);
}
});
UPDATE
I noticed there is something wrong in the routes too. Your controller does not seems a resourceful controller, so don't use the Route::resource() method. Use the get() and post() methods instead:
Route::group(array('prefix'=>'api'),function(){
Route::get('register', 'Registration\RegisterController#basicForm');
Route::post('login', 'Registration\RegisterController#makeLogin');
});
so that you can give the method that should be called in your controller.

Cakephp 2.3 beforeFilter and implementedEvents aren't able to co-exist

Using cakephp 2.3.5.
I use beforeFilter in several controllers to allow certain actions without the need to log in. I've used it successfully for quite some time. However, I've noticed that I can't get beforeFilter to fire if the controller also has the implementedEvents() method.
public function beforeFilter() {
parent::beforeFilter();
$this->Auth->allow('matchWwiProducts');
}
public function implementedEvents() {
return array(
'Controller.Product.delete' => 'deleteSku',
'Controller.Product.price' => 'notifySubscribers',
'Controller.Product.stock' => 'notifySubscribers'
);
}
For the code as displayed above I will be forced to do a login if I call the method www.example.com/products/matchWwiProducts.
When I comment out the implementedEvents() everything works as intended. I've searched around and can't find any references to implementedEvents() creating issues with beforeFilter.
The action matchWwiProducts() is as follows. It works perfectly when I log in. However, I don't want to force a log in for this action to take place.
public function matchWwiProducts() {
// this is an audit function that matches Products sourced by wwi
//
$this->autoRender = false; // no view to be rendered
// retrieve products sourced from wwi from Table::Product
$this->Product->contain();
$wwiProducts = $this->Product->getWwiSkus();
$wwiProductCount = count($wwiProducts);
// retrieve products sourced from wwi from Table:Wwiproduct
$this->loadModel('WwiProduct');
$this->Wwiproduct->contain();
$wwiSource = $this->Wwiproduct->getSkuList();
$wwiSourceCount = count($wwiSource);
// identify SKUs in $wwiProducts that are not in $wwiSource
$invalidSkus = array_diff($wwiProducts, $wwiSource);
// identify SKUs in $wwiSource that are not in $wwiProducts
$missingSkus = array_diff($wwiSource, $wwiProducts);
$missingSkuDetails = array();
foreach ($missingSkus as $missingSku) {
$skuStockStatus = $this->Wwiproduct->getStockStatus($missingSku);
$missingSkuDetails[$missingSku] = $skuStockStatus;
}
$email = new CakeEmail();
$email->config('sourcewwi');
$email->template('sourcewwiaudit', 'sourcewwi');
if (count($invalidSkus) > 0 || count($missingSkus) > 0) {
$email->subject('WWI Source Audit: Invalid or Missing SKUs');
$email->viewVars(array('invalidSkus' => $invalidSkus,
'missingSkuDetails' => $missingSkuDetails,
'wwiProductCount' => $wwiProductCount,
'wwiSourceCount' => $wwiSourceCount));
} else {
$email->subject('WWI Source Audit: No Exceptions');
$email->viewVars(array('wwiProductCount' => $wwiProductCount,
'wwiSourceCount' => $wwiSourceCount));
}
$email->send();
}
It doesn't fire because you're overloading the implementendEvents() method without making sure you keep the existing events there.
public function implementedEvents() {
return array_merge(parent::implementedEvents(), array(
'Controller.Product.delete' => 'deleteSku',
'Controller.Product.price' => 'notifySubscribers',
'Controller.Product.stock' => 'notifySubscribers'
));
}
Overloading in php.
Check most of the base classes, Controller, Table, Behavior, Component, they all fire or listen to events. So be careful when extending certain methods there. Most simple way might to do a search for "EventListenerInterface" in all classes. A class that implements this interface is likely to implement event callbacks.

How to redirect to CodeIgniter controller using angular js

I am using CodeIgniter controller functions.
(example)
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class Me extends CI_Controller {
public function __construct()
{
parent::__construct();
if (is_logged_in()){if (is_admin()) { redirect('login'); }}
else { redirect('login');}
}
public function change_password()
{
$id=$this->session->userdata['user_data']['id'];
$data = json_decode(file_get_contents("php://input"));
$my_data=array(
'pass'=>$data->pass,
'new_pass'=>$data->new_pass,
);
$result=$this->vanesh_model->change_pass($id,$my_data);
if($result==1)
{
$arr = array('msg' => "Password changed successfuly.", 'error' => '');
$jsn = json_encode($arr);
print_r($jsn);
}
else if($result==2)
{
$arr = array('msg' => "", 'error' => 'Old Password is Invalid');
$jsn = json_encode($arr);
print_r($jsn);
}
else if($result==3)
{
$arr = array('msg' => "", 'error' => 'Sorry, Password change failed');
$jsn = json_encode($arr);
print_r($jsn);
}
}
}
?>
I am afraid of using angular session services, so I want to maintain sessions with only CI. What I am doing in my application is add, update, delete only if he is logged in. And I am using information stored in session. Consider the situation, suppose, I am logged in and doing something, side by side: I destroy the session using browser tools. Now I am continuing with application (doing operations like: change password). I have/had maintained error messages, success messages, its ok. If session OFF, it gives error message. But instead of error messages, I want to redirect to LOGIN page(with page refresh).
Note: For CI Login controller, I didn't used angular js. I have used angularjs only after login.
If by opening new tab I destroy the session, and come back to application's tab: I am able to perform tasks(may be with errors,). If session is OFF I see this in Browser's console: http://localhost/ums/login
This is because of CI constructor(please look over the code).
You should separate angular and CI as much as possible, since both have view-controller it creates a mess. Instead you should have CI in a separate folder, call it api, for example, after that anything you will need from CI should be acessed from angular with ajax calls.
I made a small webapp a while ago and this seemed to be the best way to organize code.
Few updates have been made to angular since then so if there's a better way please let me know
Solved.
Used javascript function. Checking session by http request everytime. If response comes "1". Means redirect to login as:
/* function for checking logged-in and role */
function check_session()
{
$.get("servercontroller/check_session", function(data, status){
if(data=="1") /* error 1 => un-athorized user */
{
window.location.href="/login-page-url";
}
});
}

Cake: Access the controller in a static method in a component

we have a static method in a Cake component. The task was to redirect the user to the login page, if this component throws a specific error. The current (working) solution is:
class SomeComponent extends Component {
static $controllerObject;
function startup(&$controller) {
SomeComponent::$controllerObject =& $controller;
}
(...)
public static function decodeResponse($response) {
if($response == null || trim($response) == '') {
return null;
}
$result = json_decode($response, true);
if($result == null) {
throw new FatalErrorException('Could not parse api server response: ' . $response);
}
if(isset($result['error'])) {
if ($result['error'] === "IncorrectCredentialsException") {
self::$controllerObject->Session->destroy();
self::$controllerObject->Session->setFlash(__('Your session has ended. Please log in again.', true), 'default', array(), 'error');
self::$controllerObject->redirect(array(
'language' => Configure::read('Config.language'),
'controller' => 'users',
'action' => 'login'
));
}
else { throw new ApiServerException($result); }
}
return $result;
}
However, my team colleague, who is responsible for the software quality, doesn't find this solution satisfying. He says: "pls find a better way to pass the controller to the decode method. Setting the controller as static variable is not the best way".
Is there any better way to do this?
I think the problem is that your method does two different things: decoding and error handling. Instead of handling the IncorrectCredentialsException inside your method, I would move this functionality to where you handle the other exceptions and just throw an IncorrectCredentialsException in your method. With this change you no longer need to access the controller in your static method.

Unable to update user profile data in database

In my controller
public function profile() {
$UserInfo = $this->Auth->user()
if(!empty($this->data)) {
print_r($this->data);
$this->User->save($this->data);
}
if(!empty($UserInfo['id'])){
$this->data = $this->User->find('first',array('conditions'=>array('id'=>$UserInfo['id'])));
}
}
when i submit the data it is not submitted to db and i get only previous value.
Why are you querying the session here? of course this will always get you the old data again after the save.
Use the database as always, update the database again and only then overwrite the session maybe (You seem to be using cake 1.3):
public function profile() {
$uid = $this->Session->read('Auth.User.id');
if (!empty($this->data)) {
$this->data['User']['id'] = $uid;
if ($this->User->save($this->data, true, array('email', 'first_name', 'last_name', 'id', ...))) {
// if you rely on auth session data from the user, make sure to update that here
$this->Session->write('Auth.User.email', $this->data['User']['email']); // etc
...
// OK, redirect
} else {
// ERROR
}
} else {
$this->data = $this->User->find('first', ...);
}
}
As you can see I update the session keys that have been changed.
If you are using 2.x (which you did not specify as for now) you could also use
$this->Auth->login($this->request->data['User']); // must be the User array directly
although you will have to careful to pass all the data that has been in the session before.
If you plan on using login(), it would be better to find(first) the updated record again and pass this into login() then.
But personally, I prefer to only update the fields that actually changed.
see Editing own account/profile

Resources