Function not firing when I run a test - laravel

I am new to Laravel so I only have a vague idea of what I am doing. I am doing a feature tests and a function that I know fires when I use postman to test the api, but doesn't during the test. Here is the test
public function testVerify(){
$this->createTestUserParams();
$response = $this->post(route('register'), $this->user_params);
$response->assertOk();
$user = User::where('email','test#gmail.com')->first();
if($user){
$token = $user->verifyUser->token;
$id = $user->verifyUser->user_id;
$response2 = $this->post(route('email.customVerify'), ['user_id' => $id, 'token' => $token]);
$response2->assertOk();
//$user->markEmailAsVerified();
$this->assertNotNull($user->email_verified_at);
}else{
$this->fail('should find a user');
}
}
and here is the code for the function the route controller points to
public function customVerify(Request $request){
if(!isset($request->user_id)){
return response()->json(['message' => 'No user ID'],400);
}
if(!isset($request->token)){
return response()->json(['message' => 'No user token'],400);
}
$user = User::where('id',$request->user_id)->first();
if($user == null){
return response()->json(['message' => 'Bad User Id'],400);
}
if ($user->hasVerifiedEmail()) {
return response()->json(['message' => 'Already verified'],400);
}
if($request->token == $user->verifyUser->token){
if($user->markEmailAsVerified()){
event(new Verified($user));
VerifyUser::where('user_id',$user->verifyUser->user_id)->first()->delete();
return response()->json(['message' => 'Everything is swell'],200);
}
}else{
return response()->json(['message' => 'Bad token'],400);
}
}
My problem is that the field email_verified_at is coming back null when it shouldn't.
The strange thing there is an $response->assertOk(); and response will only be OK if the markEmailAsVerified() function fires successfully, otherwise the response will not be code 200. And the markEmailAsVerified() function is doing what it is supposed to because when I invoke it byitself in the test where it is commented out, the test comes back fine.
I am using the passport library for auth if that helps.

Trying getting a fresh instance of your user?
$user = $user->fresh();
$this->assertNotNull($user->email_verified_at);

Related

Store the login details in session in laravel

I have a function in controller checklogin() which checks the user details. I want to store into session. So I can get the name of the user and display in blade view
Controller
public function checklogin(Request $request)
{
$req=$request->validate([
'name'=>'required',
'email'=>'required|email',
'password'=>'required|regex:/^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[#_!]){8,}/'
]);
$userdata = array(
'name' => $request->input('name') ,
'email'=>$request->input('email'),
'password' => $request->input('password')
);
if (Auth::attempt($userdata))
{
$data = $request->session()->put('user',$userdata['name']);
dd($data) ; //returning null
return redirect('/home');
}
else
{
return back()->with('error', 'Wrong Login Details');
}
}
No need to store logged in user detail in session.You can call auth helper function which will return auth instance.
{{auth()->user()->name}}
if you have both logged in or guest page same then you can do null check
{{ auth()->user()!=null?auth()->user()->name:null }}

How to access laravel API with VUE JS?

so i want to use mylogin api but its not working,it keep push the route to dashboard even the email and the password incorrect
here is my code
export default {
data(){
return{
form: {
email: null,
password: null
},
user: {},
error: false
}
},
methods: {
login() {
this.user.append("email", this.form.email);
this.user.append("password", this.form.password);
this.axios.post('http://127.0.0.1:8000/api/login', this.user).then(response => {
localStorage.setItem("Name", response.data.first_name);
this.$router.push('/userDashboard/Dashboard')
});
},
register() {
this.$router.push('/RegisterPage')
}
},}
my laravel route api
Route::post('/login', 'UserController#login');
Login function
public function login(Request $request, User $user)
{
$email = $request->input('email');
$password = $request->input('password');
$user = User::where('email', '=', $email)->first();
if (!$user) {
return response()->json(['success'=>false, 'message' => 'Login Fail, please check email']);
}
if (!Hash::check($password, $user->password)) {
return response()->json(['success'=>false, 'message' => 'Login Fail, pls check password']);
}
return response()->json(['success'=>true,'message'=>'success', 'data' => $user]);
}
sorry for my english
This is because your laravel app always return 200 HTTP responses and this causes the .then( ... ) in the frontend to always be executed.
Either in the .then( ... ) your check the success value on the response that your Laravel has set, like this:
this.user.append("email", this.form.email);
this.user.append("password", this.form.password);
this.axios.post('http://127.0.0.1:8000/api/login', this.user).then(response => {
if (response.data.success === false) {
// handle the error and stop the code with a return
this.handleError();
return;
}
localStorage.setItem("Name", response.data.first_name);
this.$router.push('/userDashboard/Dashboard')
});
OR, you can also in Laravel throw a 401 or 400 response to say the login failed which will throw an exeception in the frontend, that you can catch with .then( ... ).catch( ... ).
That is the most clean way, because no need to send 'success' => true true anymore, since the HTTP code will be the source of truth with what happend.
public function login(Request $request, User $user)
{
$email = $request->input('email');
$password = $request->input('password');
$user = User::where('email', '=', $email)->first();
if (!$user || !Hash::check($password, $user->password)) {
// never tell the person if it's email or password, always say it's one of both for security reasons
return response(401)->json(['message' => 'Login Fail, please check email or password']);
}
return response()->json(['data' => $user]);
}
Last thing, I don't understand how this.user.append("email", this.form.email); works, because this.user seems to just be a simple object, so there isn't any append method on it.
So unless I'm missing something here, the best thing should just be to do:
const user = {
email: this.form.email,
password: this.form.password
}
// OR, make a copy
const user = { ...this.form }
// then send the user var to axios
this.axios.post('your url', user).then( ... )

Authorise a user with Laravel Passport when testing RESTful controllers update method

Every time I run the test, I'm getting a 403 response status, what am I doing wrong in here?
I have tried to remove Passport authorization from the test, but then I'm getting a redirect to a login page, 302 status response.
//PostTest:
public function test_can_update_post()
{
//creating a user
$user = factory(User::class)->create();
//creating an author for post
$author = factory(Author::class)->create([
'user_id' => $user->id,
]);
//creating a post
$post = factory(Post::class)->create([
'author_id' => $author->id,
]);
$data = [
'title' => $this->faker->title,
'content' => $this->faker->paragraph,
];
//authorizing user
//I have tried to remove this line, then I'm gettig a redirect to login page 302
$user = Passport::actingAs($user);
$this->actingAs($user)
->patch(route('posts.update', $post->id), $data)
->assertStatus(200);// why I'm getting 403???
}
//API route:
Route::patch('posts/{post}')
->uses('PostController#update')
->middleware('auth:api')
->name('posts.update');
//PostController update method:
public function update(PostUpdateRequest $request, Post $post)
{
$this->authorize('update', $post);
$post->title = $request->input('title');
$post->content = $request->input('content');
$post->save();
return new PostResource($post);
}
//PostPolocy
public function update(User $user, Post $post)
{
return Author::where('user_id', $user->id)->first()->id === $post->author_id;
}
I expect response status 200
I have changed the line in PostPolicy update method to:
if(!$user->author) {
return false;
}
return $user->author->id == $post->author_id;
This worked for me.

Laravel Socialite Google login only with one domain

I have a Google+ login on my app with Laravel Socialite. When the login is done I have a callback to connect the user (I create her in database if necessary).
But I want to restrain the connection to only the company (email like "example#company.com", so only the email with "company.com").
Can I do it with Laravel Socialite ? I can make the verification manually in my callback but if Socialite can do it, it's better.
Thank you
My callback :
public function handleProviderCallback($provider){
$user = Socialite::driver($provider)->user();
if ($user) {
$local_user = User::whereEmail($user->getEmail())->first();
// If we don't have a user create a new user
if (!$local_user) {
$fragment = explode(' ', $user->getName());
$local_user = User::create([
'first_name' => isset($fragment[0]) ? $fragment[0] : '',
'last_name' => isset($fragment[1]) ? $fragment[1] : '',
'email' => $user->getEmail(),
'last_seen' => Carbon::now(),
'password' => ''
]);
$local_user->roles()->attach(Role::whereName('User')->first());
}
auth()->login($local_user);
}
return redirect($this->redirectTo);
}
You have a step by step guide for domain restriction.
In controller you need to specifiy these actions:
public function handleProviderCallback()
{
try {
$user = Socialite::driver('google')->user();
} catch (\Exception $e) {
return redirect('/login');
}
// only allow people with #company.com to login
if(explode("#", $user->email)[1] !== 'company.com'){
return redirect()->to('/');
}
// check if they're an existing user
$existingUser = User::where('email', $user->email)->first();
if($existingUser){
// log them in
auth()->login($existingUser, true);
} else {
// create a new user
$newUser = new User;
$newUser->name = $user->name;
$newUser->email = $user->email;
$newUser->google_id = $user->id;
$newUser->avatar = $user->avatar;
$newUser->avatar_original = $user->avatar_original;
$newUser->save();
auth()->login($newUser, true);
}
return redirect()->to('/home');
}
No, you can’t do it in Socialite itself because Socialite is just a mechanism of retrieving tokens from OAuth-compliant servers.
If you only want to accept users with a particular email suffix, then that’s business logic so something you should handle in your callback:
public function handleProviderCallback()
{
$user = Socialite::driver('google')->user();
if (Str::endsWith($user->getEmail(), '#example.com')) {
// Look up user and authenticate them
}
abort(400, 'User does not belong to organization');
}

Return user info in Sentry2

I want to return the users info to my view when a user logs in but I keep getting an error message that says "Undefined variable: user"
Here is my controller code:
public function postLogin()
{
$credentials = array(
'email' => \Input::get('email'),
'password' => \Input::get('password')
);
try
{
$user = \Sentry::authenticate($credentials, false);
if ($user);
{
$user = \Sentry::getUser();
\Notification::succes('Succesvol ingelogd als,'. $user->name);
return \Redirect::back()-with($user);
}
}
catch(\Exception $e)
{
\Notification::error($e->getMessage());
return \Redirect::back();
}
}
and in my view I try to use the $user variable but then I get the error.
When you do:
Redirect::back()->with('user',$user);
In your new request you must get the user from the Session:
$user = Session::get('user');
and pass it to your view:
return View::make('view')->with('user', $user);
Because Laravel doesn't create global variables as it does when you:
return View::make('view')->with('variableName', $value);

Resources