mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-08-07 10:01:47 -04:00
Merge pull request #743 from turbo124/push_notifications
Push notifications
This commit is contained in:
commit
0155f08d0d
@ -117,4 +117,77 @@ class AccountApiController extends BaseAPIController
|
|||||||
|
|
||||||
return $this->response($account);
|
return $this->response($account);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function addDeviceToken(Request $request)
|
||||||
|
{
|
||||||
|
$account = Auth::user()->account;
|
||||||
|
|
||||||
|
//scan if this user has a token already registered (tokens can change, so we need to use the users email as key)
|
||||||
|
$devices = json_decode($account->devices,TRUE);
|
||||||
|
|
||||||
|
|
||||||
|
for($x=0; $x<count($devices); $x++)
|
||||||
|
{
|
||||||
|
if ($devices[$x]['email'] == Auth::user()->username) {
|
||||||
|
$devices[$x]['token'] = $request->token; //update
|
||||||
|
$account->devices = json_encode($devices);
|
||||||
|
$account->save();
|
||||||
|
return $this->response($account);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//User does not have a device, create new record
|
||||||
|
|
||||||
|
$newDevice = [
|
||||||
|
'token' => $request->token,
|
||||||
|
'email' => $request->email,
|
||||||
|
'device' => $request->device,
|
||||||
|
'notify_sent' => TRUE,
|
||||||
|
'notify_viewed' => TRUE,
|
||||||
|
'notify_approved' => TRUE,
|
||||||
|
'notify_paid' => TRUE,
|
||||||
|
];
|
||||||
|
|
||||||
|
$devices[] = $newDevice;
|
||||||
|
$account->devices = json_encode($devices);
|
||||||
|
$account->save();
|
||||||
|
|
||||||
|
return $this->response($account);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function updatePushNotifications(Request $request)
|
||||||
|
{
|
||||||
|
$account = Auth::user()->account;
|
||||||
|
|
||||||
|
$devices = json_decode($account->devices, TRUE);
|
||||||
|
|
||||||
|
if(count($devices)<1)
|
||||||
|
return $this->errorResponse(['message'=>'no devices exist'], 400);
|
||||||
|
|
||||||
|
for($x=0; $x<count($devices); $x++)
|
||||||
|
{
|
||||||
|
if($devices[$x]['email'] == Auth::user()->username)
|
||||||
|
{
|
||||||
|
unset($devices[$x]);
|
||||||
|
|
||||||
|
$newDevice = [
|
||||||
|
'token' => $request->token,
|
||||||
|
'email' => $request->email,
|
||||||
|
'device' => $request->device,
|
||||||
|
'notify_sent' => $request->notify_sent,
|
||||||
|
'notify_viewed' => $request->notify_viewed,
|
||||||
|
'notify_approved' => $request->notify_approved,
|
||||||
|
'notify_paid' => $request->notify_paid,
|
||||||
|
];
|
||||||
|
|
||||||
|
$devices[] = $newDevice;
|
||||||
|
$account->devices = json_encode($devices);
|
||||||
|
$account->save();
|
||||||
|
|
||||||
|
return $this->response($account);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -235,6 +235,8 @@ Route::group(['middleware' => 'api', 'prefix' => 'api/v1'], function()
|
|||||||
Route::resource('tax_rates', 'TaxRateApiController');
|
Route::resource('tax_rates', 'TaxRateApiController');
|
||||||
Route::resource('users', 'UserApiController');
|
Route::resource('users', 'UserApiController');
|
||||||
Route::resource('expenses','ExpenseApiController');
|
Route::resource('expenses','ExpenseApiController');
|
||||||
|
Route::post('add_token', 'AccountApiController@addDeviceToken');
|
||||||
|
Route::post('update_notifications', 'AccountApiController@updatePushNotifications');
|
||||||
|
|
||||||
// Vendor
|
// Vendor
|
||||||
Route::resource('vendors', 'VendorApiController');
|
Route::resource('vendors', 'VendorApiController');
|
||||||
@ -552,6 +554,9 @@ if (!defined('CONTACT_EMAIL')) {
|
|||||||
define('TEST_PASSWORD', 'password');
|
define('TEST_PASSWORD', 'password');
|
||||||
define('API_SECRET', 'API_SECRET');
|
define('API_SECRET', 'API_SECRET');
|
||||||
|
|
||||||
|
define('IOS_PRODUCTION_PUSH','ninjaIOS');
|
||||||
|
define('IOS_DEV_PUSH','devNinjaIOS');
|
||||||
|
|
||||||
define('TOKEN_BILLING_DISABLED', 1);
|
define('TOKEN_BILLING_DISABLED', 1);
|
||||||
define('TOKEN_BILLING_OPT_IN', 2);
|
define('TOKEN_BILLING_OPT_IN', 2);
|
||||||
define('TOKEN_BILLING_OPT_OUT', 3);
|
define('TOKEN_BILLING_OPT_OUT', 3);
|
||||||
|
@ -9,16 +9,19 @@ use App\Events\InvoiceInvitationWasViewed;
|
|||||||
use App\Events\QuoteInvitationWasViewed;
|
use App\Events\QuoteInvitationWasViewed;
|
||||||
use App\Events\QuoteInvitationWasApproved;
|
use App\Events\QuoteInvitationWasApproved;
|
||||||
use App\Events\PaymentWasCreated;
|
use App\Events\PaymentWasCreated;
|
||||||
|
use App\Ninja\Notifications;
|
||||||
|
|
||||||
class NotificationListener
|
class NotificationListener
|
||||||
{
|
{
|
||||||
protected $userMailer;
|
protected $userMailer;
|
||||||
protected $contactMailer;
|
protected $contactMailer;
|
||||||
|
protected $pushService;
|
||||||
|
|
||||||
public function __construct(UserMailer $userMailer, ContactMailer $contactMailer)
|
public function __construct(UserMailer $userMailer, ContactMailer $contactMailer, Notifications\PushService $pushService)
|
||||||
{
|
{
|
||||||
$this->userMailer = $userMailer;
|
$this->userMailer = $userMailer;
|
||||||
$this->contactMailer = $contactMailer;
|
$this->contactMailer = $contactMailer;
|
||||||
|
$this->pushService = $pushService;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function sendEmails($invoice, $type, $payment = null)
|
private function sendEmails($invoice, $type, $payment = null)
|
||||||
@ -35,26 +38,31 @@ class NotificationListener
|
|||||||
public function emailedInvoice(InvoiceWasEmailed $event)
|
public function emailedInvoice(InvoiceWasEmailed $event)
|
||||||
{
|
{
|
||||||
$this->sendEmails($event->invoice, 'sent');
|
$this->sendEmails($event->invoice, 'sent');
|
||||||
|
$this->pushService->sendNotification($event->invoice, 'sent');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function emailedQuote(QuoteWasEmailed $event)
|
public function emailedQuote(QuoteWasEmailed $event)
|
||||||
{
|
{
|
||||||
$this->sendEmails($event->quote, 'sent');
|
$this->sendEmails($event->quote, 'sent');
|
||||||
|
$this->pushService->sendNotification($event->quote, 'sent');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function viewedInvoice(InvoiceInvitationWasViewed $event)
|
public function viewedInvoice(InvoiceInvitationWasViewed $event)
|
||||||
{
|
{
|
||||||
$this->sendEmails($event->invoice, 'viewed');
|
$this->sendEmails($event->invoice, 'viewed');
|
||||||
|
$this->pushService->sendNotification($event->invoice, 'viewed');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function viewedQuote(QuoteInvitationWasViewed $event)
|
public function viewedQuote(QuoteInvitationWasViewed $event)
|
||||||
{
|
{
|
||||||
$this->sendEmails($event->quote, 'viewed');
|
$this->sendEmails($event->quote, 'viewed');
|
||||||
|
$this->pushService->sendNotification($event->quote, 'viewed');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function approvedQuote(QuoteInvitationWasApproved $event)
|
public function approvedQuote(QuoteInvitationWasApproved $event)
|
||||||
{
|
{
|
||||||
$this->sendEmails($event->quote, 'approved');
|
$this->sendEmails($event->quote, 'approved');
|
||||||
|
$this->pushService->sendNotification($event->quote, 'approved');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function createdPayment(PaymentWasCreated $event)
|
public function createdPayment(PaymentWasCreated $event)
|
||||||
@ -66,6 +74,8 @@ class NotificationListener
|
|||||||
|
|
||||||
$this->contactMailer->sendPaymentConfirmation($event->payment);
|
$this->contactMailer->sendPaymentConfirmation($event->payment);
|
||||||
$this->sendEmails($event->payment->invoice, 'paid', $event->payment);
|
$this->sendEmails($event->payment->invoice, 'paid', $event->payment);
|
||||||
|
|
||||||
|
$this->pushService->sendNotification($event->payment->invoice, 'paid');
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
96
app/Ninja/Notifications/PushFactory.php
Normal file
96
app/Ninja/Notifications/PushFactory.php
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Ninja\Notifications;
|
||||||
|
|
||||||
|
use Davibennun\LaravelPushNotification\Facades\PushNotification;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class PushFactory
|
||||||
|
* @package App\Ninja\Notifications
|
||||||
|
*/
|
||||||
|
|
||||||
|
class PushFactory
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* PushFactory constructor.
|
||||||
|
*
|
||||||
|
* @param $this->certificate - Development or production.
|
||||||
|
*
|
||||||
|
* Static variables defined in routes.php
|
||||||
|
*
|
||||||
|
* IOS_PRODUCTION_PUSH
|
||||||
|
* IOS_DEV_PUSH
|
||||||
|
*/
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->certificate = IOS_DEV_PUSH;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* customMessage function
|
||||||
|
*
|
||||||
|
* Send a message with a nested custom payload to perform additional trickery within application
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
*
|
||||||
|
* @param $token
|
||||||
|
* @param $message
|
||||||
|
* @param $messageArray
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function customMessage($token, $message, $messageArray)
|
||||||
|
{
|
||||||
|
$customMessage = PushNotification::Message($message, $messageArray);
|
||||||
|
|
||||||
|
$this->message($token, $customMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* message function
|
||||||
|
*
|
||||||
|
* Send a plain text only message to a single device.
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
*
|
||||||
|
* @param $token - device token
|
||||||
|
* @param $message - user specific message
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
public function message($token, $message)
|
||||||
|
{
|
||||||
|
PushNotification::app($this->certificate)
|
||||||
|
->to($token)
|
||||||
|
->send($message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getFeedback function
|
||||||
|
*
|
||||||
|
* Returns an array of expired/invalid tokens to be removed from iOS PUSH notifications.
|
||||||
|
*
|
||||||
|
* We need to run this once ~ 24hrs
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
*
|
||||||
|
* @param string $token - A valid token (can be any valid token)
|
||||||
|
* @param string $message - Nil value for message
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getFeedback($token, $message = '')
|
||||||
|
{
|
||||||
|
|
||||||
|
$feedback = PushNotification::app($this->certificate)
|
||||||
|
->to($token)
|
||||||
|
->send($message);
|
||||||
|
|
||||||
|
return $feedback->getFeedback();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
171
app/Services/PushService.php
Normal file
171
app/Services/PushService.php
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use App\Ninja\Notifications\PushFactory;
|
||||||
|
/**
|
||||||
|
* Class PushService
|
||||||
|
* @package App\Ninja\Notifications
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* $account->devices Definition
|
||||||
|
*
|
||||||
|
* @param string token (push notification device token)
|
||||||
|
* @param string email (user email address - required for use as key)
|
||||||
|
* @param string device (ios, gcm etc etc)
|
||||||
|
* @param bool notify_sent
|
||||||
|
* @param bool notify_paid
|
||||||
|
* @param bool notify_approved
|
||||||
|
* @param bool notify_viewed
|
||||||
|
*/
|
||||||
|
|
||||||
|
class PushService
|
||||||
|
{
|
||||||
|
protected $pushFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param PushFactory $pushFactory
|
||||||
|
*/
|
||||||
|
public function __construct(PushFactory $pushFactory)
|
||||||
|
{
|
||||||
|
$this->pushFactory = $pushFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $invoice - Invoice object
|
||||||
|
* @param $type - Type of notification, ie. Quote APPROVED, Invoice PAID, Invoice/Quote SENT, Invoice/Quote VIEWED
|
||||||
|
*/
|
||||||
|
|
||||||
|
public function sendNotification($invoice, $type)
|
||||||
|
{
|
||||||
|
//check user has registered for push notifications
|
||||||
|
if(!$this->checkDeviceExists($invoice->account))
|
||||||
|
return;
|
||||||
|
|
||||||
|
//Harvest an array of devices that are registered for this notification type
|
||||||
|
$devices = json_decode($invoice->account->devices, TRUE);
|
||||||
|
|
||||||
|
foreach($devices as $device)
|
||||||
|
{
|
||||||
|
if(($device["notify_{$type}"] == TRUE) && ($device['device'] == 'ios'))
|
||||||
|
$this->pushMessage($invoice, $device['token'], $device["notify_{$type}"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pushMessage function
|
||||||
|
*
|
||||||
|
* method to dispatch iOS notifications
|
||||||
|
*
|
||||||
|
* @param $invoice
|
||||||
|
* @param $token
|
||||||
|
* @param $type
|
||||||
|
*/
|
||||||
|
private function pushMessage($invoice, $token, $type)
|
||||||
|
{
|
||||||
|
$this->pushFactory->message($token, $this->messageType($invoice, $type));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* checkDeviceExists function
|
||||||
|
*
|
||||||
|
* Returns a boolean if this account has devices registered for PUSH notifications
|
||||||
|
*
|
||||||
|
* @param $account
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
private function checkDeviceExists($account)
|
||||||
|
{
|
||||||
|
$devices = json_decode($account->devices, TRUE);
|
||||||
|
|
||||||
|
if(count($devices) >= 1)
|
||||||
|
return TRUE;
|
||||||
|
else
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* messageType function
|
||||||
|
*
|
||||||
|
* method which formats an appropriate message depending on message type
|
||||||
|
*
|
||||||
|
* @param $invoice
|
||||||
|
* @param $type
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function messageType($invoice, $type)
|
||||||
|
{
|
||||||
|
switch($type)
|
||||||
|
{
|
||||||
|
case 'notify_sent':
|
||||||
|
return $this->entitySentMessage($invoice);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'notify_paid':
|
||||||
|
return $this->invoicePaidMessage($invoice);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'notify_approved':
|
||||||
|
return $this->quoteApprovedMessage($invoice);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'notify_viewed':
|
||||||
|
return $this->entityViewedMessage($invoice);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $invoice
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function entitySentMessage($invoice)
|
||||||
|
{
|
||||||
|
if($invoice->is_quote)
|
||||||
|
return 'Quote #{$invoice->invoice_number} sent!';
|
||||||
|
else
|
||||||
|
return 'Invoice #{$invoice->invoice_number} sent!';
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $invoice
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function invoicePaidMessage($invoice)
|
||||||
|
{
|
||||||
|
return 'Invoice #{$invoice->invoice_number} paid!';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $invoice
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function quoteApprovedMessage($invoice)
|
||||||
|
{
|
||||||
|
return 'Quote #{$invoice->invoice_number} approved!';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $invoice
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function entityViewedMessage($invoice)
|
||||||
|
{
|
||||||
|
if($invoice->is_quote)
|
||||||
|
return 'Quote #{$invoice->invoice_number} viewed!';
|
||||||
|
else
|
||||||
|
return 'Invoice #{$invoice->invoice_number} viewed!';
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -10,6 +10,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"require": {
|
"require": {
|
||||||
|
"turbo124/laravel-push-notification": "dev-laravel5",
|
||||||
"omnipay/mollie": "dev-master#22956c1a62a9662afa5f5d119723b413770ac525",
|
"omnipay/mollie": "dev-master#22956c1a62a9662afa5f5d119723b413770ac525",
|
||||||
"omnipay/2checkout": "dev-master#e9c079c2dde0d7ba461903b3b7bd5caf6dee1248",
|
"omnipay/2checkout": "dev-master#e9c079c2dde0d7ba461903b3b7bd5caf6dee1248",
|
||||||
"omnipay/gocardless": "dev-master",
|
"omnipay/gocardless": "dev-master",
|
||||||
|
816
composer.lock
generated
816
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@ -164,6 +164,7 @@ return [
|
|||||||
'App\Providers\RouteServiceProvider',
|
'App\Providers\RouteServiceProvider',
|
||||||
|
|
||||||
'Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider',
|
'Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider',
|
||||||
|
'Davibennun\LaravelPushNotification\LaravelPushNotificationServiceProvider',
|
||||||
],
|
],
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -249,6 +250,7 @@ return [
|
|||||||
'Rocketeer' => 'Rocketeer\Facades\Rocketeer',
|
'Rocketeer' => 'Rocketeer\Facades\Rocketeer',
|
||||||
'Socialite' => 'Laravel\Socialite\Facades\Socialite',
|
'Socialite' => 'Laravel\Socialite\Facades\Socialite',
|
||||||
'Excel' => 'Maatwebsite\Excel\Facades\Excel',
|
'Excel' => 'Maatwebsite\Excel\Facades\Excel',
|
||||||
|
'PushNotification' => 'Davibennun\LaravelPushNotification\Facades\PushNotification',
|
||||||
|
|
||||||
],
|
],
|
||||||
|
|
||||||
|
23
config/push-notification.php
Normal file
23
config/push-notification.php
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
|
||||||
|
'devNinjaIOS' => [
|
||||||
|
'environment' =>'development',
|
||||||
|
'certificate'=>app_path().'/certs/ninjaIOS.pem',
|
||||||
|
'passPhrase' =>'',
|
||||||
|
'service' =>'apns'
|
||||||
|
],
|
||||||
|
'ninjaIOS' => [
|
||||||
|
'environment' =>'production',
|
||||||
|
'certificate'=>app_path().'/certs/productionNinjaIOS.pem',
|
||||||
|
'passPhrase' =>'',
|
||||||
|
'service' =>'apns'
|
||||||
|
],
|
||||||
|
'ninjaAndroid' => [
|
||||||
|
'environment' =>'production',
|
||||||
|
'apiKey' =>'yourAPIKey',
|
||||||
|
'service' =>'gcm'
|
||||||
|
]
|
||||||
|
|
||||||
|
];
|
Loading…
x
Reference in New Issue
Block a user