diff --git a/app/Http/Controllers/Auth/LoginController.php b/app/Http/Controllers/Auth/LoginController.php
index 9d44665779d0..64dbfd4b823b 100644
--- a/app/Http/Controllers/Auth/LoginController.php
+++ b/app/Http/Controllers/Auth/LoginController.php
@@ -13,6 +13,7 @@ namespace App\Http\Controllers\Auth;
use App\DataMapper\Analytics\LoginFailure;
use App\DataMapper\Analytics\LoginSuccess;
+use App\Events\User\UserLoggedIn;
use App\Http\Controllers\BaseController;
use App\Http\Controllers\Controller;
use App\Jobs\Account\CreateAccount;
@@ -24,6 +25,7 @@ use App\Models\CompanyToken;
use App\Models\CompanyUser;
use App\Models\User;
use App\Transformers\CompanyUserTransformer;
+use App\Utils\Ninja;
use App\Utils\Traits\UserSessionAttributes;
use Google_Client;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
@@ -170,6 +172,8 @@ class LoginController extends BaseController
$user = $this->guard()->user();
+ event(new UserLoggedIn($user, $user->account->default_company, Ninja::eventVars($user->id)));
+
//if user has 2fa enabled - lets check this now:
if($user->google_2fa_secret && $request->has('one_time_password'))
diff --git a/app/Http/Middleware/TokenAuth.php b/app/Http/Middleware/TokenAuth.php
index b93f7c90479e..bcea2cb8d26e 100644
--- a/app/Http/Middleware/TokenAuth.php
+++ b/app/Http/Middleware/TokenAuth.php
@@ -68,8 +68,6 @@ class TokenAuth
//stateless, don't remember the user.
auth()->login($user, false);
- event(new UserLoggedIn($user, $company_token->company, Ninja::eventVars()));
-
} else {
$error = [
'message' => 'Invalid token',
diff --git a/app/Listeners/User/UpdateUserLastLogin.php b/app/Listeners/User/UpdateUserLastLogin.php
index 6bb1d37d11ff..ed833a9cbac1 100644
--- a/app/Listeners/User/UpdateUserLastLogin.php
+++ b/app/Listeners/User/UpdateUserLastLogin.php
@@ -11,7 +11,10 @@
namespace App\Listeners\User;
+use App\Jobs\Mail\NinjaMailerJob;
+use App\Jobs\Mail\NinjaMailerObject;
use App\Libraries\MultiDB;
+use App\Mail\User\UserLoggedIn;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Events\Dispatchable;
@@ -38,11 +41,29 @@ class UpdateUserLastLogin implements ShouldQueue
*/
public function handle($event)
{
+
MultiDB::setDb($event->company->db);
$user = $event->user;
-
$user->last_login = now();
$user->save();
+
+ $event_vars = $event->event_vars;
+ $ip = array_key_exists('ip', $event->event_vars) ? $event->event_vars['ip'] : 'IP address not resolved';
+
+ if($user->ip != $ip)
+ {
+ $nmo = new NinjaMailerObject;
+ $nmo->mailable = new UserLoggedIn($user, $user->account->companies()->first(), $ip);
+ $nmo->company = $user->account->companies()->first();
+ $nmo->settings = $user->account->companies()->first()->settings;
+ $nmo->to_user = $user;
+ NinjaMailerJob::dispatch($nmo);
+
+ $user->ip = $ip;
+ $user->save();
+ }
+
+
}
}
diff --git a/app/Mail/Import/ImportCompleted.php b/app/Mail/Import/ImportCompleted.php
index ecb50e51487f..8396fda29903 100644
--- a/app/Mail/Import/ImportCompleted.php
+++ b/app/Mail/Import/ImportCompleted.php
@@ -1,4 +1,13 @@
whitelabel = $this->company->account->isPaid();
return $this->from(config('mail.from.address'), config('mail.from.name'))
+ ->subject(ctrans('texts.max_companies'))
->view('email.migration.max_companies');
}
}
diff --git a/app/Mail/User/UserLoggedIn.php b/app/Mail/User/UserLoggedIn.php
new file mode 100644
index 000000000000..7eade000111e
--- /dev/null
+++ b/app/Mail/User/UserLoggedIn.php
@@ -0,0 +1,59 @@
+company = $company;
+ $this->user = $user;
+ $this->ip = $ip;
+ }
+
+ /**
+ * Build the message.
+ *
+ * @return $this
+ */
+ public function build()
+ {
+
+ return $this->from(config('mail.from.address'), config('mail.from.name'))
+ ->subject(ctrans('texts.new_login_detected'))
+ ->view('email.admin.notification')
+ ->with([
+ 'settings' => $this->company->settings,
+ 'logo' => $this->company->present()->logo(),
+ 'title' => ctrans('texts.new_login_detected'),
+ 'body' => ctrans('texts.new_login_description', ['email' =>$this->user->email, 'ip' => $this->ip, 'time' => now()]),
+ 'whitelabel' => $this->company->account->isPaid(),
+ ]);
+ }
+}
diff --git a/resources/lang/en/texts.php b/resources/lang/en/texts.php
index a10ad715f272..2a46a25013ba 100644
--- a/resources/lang/en/texts.php
+++ b/resources/lang/en/texts.php
@@ -4246,6 +4246,8 @@ $LANG = array(
'activity_102' => ':user archived recurring invoice :recurring_invoice',
'activity_103' => ':user deleted recurring invoice :recurring_invoice',
'activity_104' => ':user restored recurring invoice :recurring_invoice',
+ 'new_login_detected' => 'New login detected for your account.',
+ 'new_login_description' => 'You recently logged in to your Invoice Ninja account from a new location or device:
IP: :ip
Time: :time
Email: :email',
);
return $LANG;
diff --git a/resources/views/email/admin/notification.blade.php b/resources/views/email/admin/notification.blade.php
new file mode 100644
index 000000000000..7565faf86e21
--- /dev/null
+++ b/resources/views/email/admin/notification.blade.php
@@ -0,0 +1,18 @@
+@component('email.template.master', ['design' => 'light', 'settings' => $settings])
+
+ @slot('header')
+ @include('email.components.header', ['logo' => $logo])
+ @endslot
+
+
{!! $body !!}
+ + @if(isset($whitelabel) && !$whitelabel) + @slot('footer') + @component('email.components.footer', ['url' => 'https://invoiceninja.com', 'url_text' => '© InvoiceNinja']) + For any info, please visit InvoiceNinja. + @endcomponent + @endslot + @endif +@endcomponent