From 7f3bd44d9ae8540bd32f2ed3b7647a63fbaadf5c Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Thu, 4 Aug 2016 20:01:30 +0300 Subject: [PATCH] Working on bots --- app/Console/Kernel.php | 1 - app/Http/Controllers/BotController.php | 89 ++++++++++++++++++++ app/Http/routes.php | 5 +- app/Ninja/Intents/BaseIntent.php | 24 ++++++ app/Ninja/Intents/CreateInvoiceIntent.php | 43 ++++++++++ app/Ninja/Presenters/InvoicePresenter.php | 8 ++ app/Ninja/Repositories/ClientRepository.php | 43 ++++++++++ database/seeds/PaymentStatusSeeder.php | 2 +- resources/lang/en/texts.php | 1 + resources/views/bots/skype/card.blade.php | 43 ++++++++++ resources/views/bots/skype/invoice.blade.php | 43 ++++++++++ 11 files changed, 299 insertions(+), 3 deletions(-) create mode 100644 app/Http/Controllers/BotController.php create mode 100644 app/Ninja/Intents/BaseIntent.php create mode 100644 app/Ninja/Intents/CreateInvoiceIntent.php create mode 100644 resources/views/bots/skype/card.blade.php create mode 100644 resources/views/bots/skype/invoice.blade.php diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index 722a14dbe77f..0cda6a4c8676 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -23,7 +23,6 @@ class Kernel extends ConsoleKernel 'App\Console\Commands\SendReminders', 'App\Console\Commands\GenerateResources', 'App\Console\Commands\TestOFX', - 'App\Console\Commands\TestBot', ]; /** diff --git a/app/Http/Controllers/BotController.php b/app/Http/Controllers/BotController.php new file mode 100644 index 000000000000..dc55ed141632 --- /dev/null +++ b/app/Http/Controllers/BotController.php @@ -0,0 +1,89 @@ +invoiceRepo = $invoiceRepo; + } + + public function handleMessage($platform) + { + //$message = 'Here\'s your invoice'; + $message = 'create an invoice for test client'; + $to = '29:1C-OsU7OWBEDOYJhQUsDkYHmycOwOq9QOg5FVTwRX9ts'; + + $appId = env('MSBOT_LUIS_APP_ID'); + $subKey = env('MSBOT_LUIS_SUBSCRIPTION_KEY'); + $message = rawurlencode($message); + + $url = sprintf('%s?id=%s&subscription-key=%s&q=%s', MSBOT_LUIS_URL, $appId, $subKey, $message); + $data = file_get_contents($url); + $data = json_decode($data); + + if ( ! count($data->intents)) { + return false; + } + + $intent = $data->intents[0]; + $intentType = $intent->intent; + + $intent = BaseIntent::createIntent($intentType, $data->entities); + $message = $intent->process(); + + $this->sendResponse($to, $message); + } + + private function sendResponse($to, $message) + { + $clientId = env('MSBOT_CLIENT_ID'); + $clientSecret = env('MSBOT_CLIENT_SECRET'); + $scope = 'https://graph.microsoft.com/.default'; + + $data = sprintf('grant_type=client_credentials&client_id=%s&client_secret=%s&scope=%s', $clientId, $clientSecret, $scope); + $curl = curl_init(); + + $opts = [ + CURLOPT_URL => MSBOT_LOGIN_URL, + CURLOPT_RETURNTRANSFER => true, + CURLOPT_POST => 'POST', + CURLOPT_POSTFIELDS => $data, + ]; + + curl_setopt_array($curl, $opts); + curl_exec($curl); + + + $response = json_decode(curl_exec($curl)); + $token = $response->access_token; + print_r($token); + + $url = sprintf('%s/conversations/%s/activities/', SKYPE_API_URL, $to); + + $opts = [ + CURLOPT_URL => $url, + CURLOPT_RETURNTRANSFER => true, + CURLOPT_POST => 'POST', + CURLOPT_POSTFIELDS => $message, + CURLOPT_HTTPHEADER => [ + 'Authorization: Bearer ' . $token, + ], + ]; + + curl_setopt_array($curl, $opts); + $response = curl_exec($curl); + curl_close($curl); + + var_dump($response); + } + +} diff --git a/app/Http/routes.php b/app/Http/routes.php index b001ce159856..ea8f6308fff7 100644 --- a/app/Http/routes.php +++ b/app/Http/routes.php @@ -85,6 +85,7 @@ Route::match(['GET', 'POST'], '/buy_now/{gateway_type?}', 'OnlinePaymentControll Route::post('/hook/email_bounced', 'AppController@emailBounced'); Route::post('/hook/email_opened', 'AppController@emailOpened'); +Route::any('/hook/bot/{platform?}', 'BotController@handleMessage'); Route::post('/payment_hook/{accountKey}/{gatewayId}', 'OnlinePaymentController@handlePaymentWebhook'); // Laravel auth routes @@ -609,7 +610,7 @@ if (!defined('CONTACT_EMAIL')) { define('NINJA_WEB_URL', env('NINJA_WEB_URL', 'https://www.invoiceninja.com')); define('NINJA_APP_URL', env('NINJA_APP_URL', 'https://app.invoiceninja.com')); define('NINJA_DATE', '2000-01-01'); - define('NINJA_VERSION', '2.6.7' . env('NINJA_VERSION_SUFFIX')); + define('NINJA_VERSION', '2.6.8' . env('NINJA_VERSION_SUFFIX')); define('SOCIAL_LINK_FACEBOOK', env('SOCIAL_LINK_FACEBOOK', 'https://www.facebook.com/invoiceninja')); define('SOCIAL_LINK_TWITTER', env('SOCIAL_LINK_TWITTER', 'https://twitter.com/invoiceninja')); @@ -627,6 +628,8 @@ if (!defined('CONTACT_EMAIL')) { define('OFX_HOME_URL', env('OFX_HOME_URL', 'http://www.ofxhome.com/index.php/home/directory/all')); define('GOOGLE_ANALYITCS_URL', env('GOOGLE_ANALYITCS_URL', 'https://www.google-analytics.com/collect')); define('MSBOT_LOGIN_URL', 'https://login.microsoftonline.com/common/oauth2/v2.0/token'); + define('MSBOT_LUIS_URL', 'https://api.projectoxford.ai/luis/v1/application'); + define('SKYPE_API_URL', 'https://apis.skype.com/v3'); define('BLANK_IMAGE', 'data:image/png;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs='); diff --git a/app/Ninja/Intents/BaseIntent.php b/app/Ninja/Intents/BaseIntent.php new file mode 100644 index 000000000000..c4fa0aff3fb8 --- /dev/null +++ b/app/Ninja/Intents/BaseIntent.php @@ -0,0 +1,24 @@ +parameters = $parameters; + } + + public static function createIntent($intentType, $parameters) + { + $className = "App\\Ninja\\Intents\\{$intentType}Intent"; + return new $className($parameters); + } + + public function process() + { + // do nothing by default + } + +} diff --git a/app/Ninja/Intents/CreateInvoiceIntent.php b/app/Ninja/Intents/CreateInvoiceIntent.php new file mode 100644 index 000000000000..46ef9ce9fddb --- /dev/null +++ b/app/Ninja/Intents/CreateInvoiceIntent.php @@ -0,0 +1,43 @@ +parameters as $param) { + if ($param->type == 'client') { + $client = $clientRepo->findPhonetically($param->entity); + } + } + + if ($client) { + $data = [ + 'client_id' => $client->id, + 'invoice_items' => [], + ]; + + $invoice = $invoiceRepo->save($data); + + return view('bots.skype.invoice', [ + 'invoice' => $invoice + ])->render(); + + + /* + if ($invoice->amount > 0) { + + } else { + return view('bots.skype.card', [ + 'title' => 'Testing', + 'subtitle' => $invoice->invoice_number, + ])->render(); + } + */ + } + } + +} diff --git a/app/Ninja/Presenters/InvoicePresenter.php b/app/Ninja/Presenters/InvoicePresenter.php index 2af94f8060a7..07b9a68ab20c 100644 --- a/app/Ninja/Presenters/InvoicePresenter.php +++ b/app/Ninja/Presenters/InvoicePresenter.php @@ -14,6 +14,14 @@ class InvoicePresenter extends EntityPresenter { return $this->entity->user->getDisplayName(); } + public function amount() + { + $invoice = $this->entity; + $account = $invoice->account; + + return $account->formatMoney($invoice->amount, $invoice->client); + } + public function balanceDueLabel() { if ($this->entity->partial > 0) { diff --git a/app/Ninja/Repositories/ClientRepository.php b/app/Ninja/Repositories/ClientRepository.php index 31ca425253c3..ae67f918ab7d 100644 --- a/app/Ninja/Repositories/ClientRepository.php +++ b/app/Ninja/Repositories/ClientRepository.php @@ -132,4 +132,47 @@ class ClientRepository extends BaseRepository return $client; } + + public function findPhonetically($clientName) + { + $clientNameMeta = metaphone($clientName); + + $map = []; + $max = 0; + $clientId = 0; + + $clients = Client::scope()->get(['id', 'name']); + + foreach ($clients as $client) { + if ( ! $client->name) { + continue; + } + + $map[$client->id] = $client; + $similar = similar_text($clientNameMeta, metaphone($client->name), $percent); + + if ($percent > $max) { + $clientId = $client->id; + $max = $percent; + } + } + + $contacts = Contact::scope()->get(['client_id', 'first_name', 'last_name']); + + foreach ($contacts as $contact) { + if ( ! $contact->getFullName()) { + continue; + } + + $similar = similar_text($clientNameMeta, metaphone($contact->getFullName()), $percent); + + if ($percent > $max) { + $clientId = $contact->client_id; + $max = $percent; + } + } + + return isset($map[$clientId]) ? $map[$clientId] : null; + } + } diff --git a/database/seeds/PaymentStatusSeeder.php b/database/seeds/PaymentStatusSeeder.php index 4b3da3d085b8..808b7b3f5a45 100644 --- a/database/seeds/PaymentStatusSeeder.php +++ b/database/seeds/PaymentStatusSeeder.php @@ -33,5 +33,5 @@ class PaymentStatusSeeder extends Seeder PaymentStatus::create($status); } } - } + } } diff --git a/resources/lang/en/texts.php b/resources/lang/en/texts.php index 439889307b22..a96ba845f887 100644 --- a/resources/lang/en/texts.php +++ b/resources/lang/en/texts.php @@ -2051,6 +2051,7 @@ $LANG = array( 'gateway_config_error' => 'It may help to set new passwords or generate new API keys.', 'payment_type_on_file' => ':type on file', + 'invoice_for_client' => 'Invoice :invoice for :client', ); diff --git a/resources/views/bots/skype/card.blade.php b/resources/views/bots/skype/card.blade.php new file mode 100644 index 000000000000..93b138c61d47 --- /dev/null +++ b/resources/views/bots/skype/card.blade.php @@ -0,0 +1,43 @@ +{ + "type":"message/card.carousel", + "attachments":[ + { + "contentType":"application/vnd.microsoft.card.hero", + "content":{ + "title":"{!! $title !!}" + @if ( ! empty($subtitle)) + , "subtitle":"{!! $subtitle !!}" + @endif + @if ( ! empty($text)) + , "text":"{!! $text !!}" + @endif + @if ( ! empty($images)) + , "images":[ + @foreach($images as $image) + @if ($images[0] != $image) + , + @endif + { + "image":"{{ $image }}" + } + @endforeach + ] + @endif + @if ( ! empty($buttons)) + , "buttons":[ + @foreach($buttons as $button) + @if ($buttons[0] != $button) + , + @endif + { + "type":"{{ $button['type'] }}", + "title":"{!! $button['title'] !!}", + "value":"{!! $button['value'] !!}" + } + @endforeach + ] + @endif + } + } + ] +} diff --git a/resources/views/bots/skype/invoice.blade.php b/resources/views/bots/skype/invoice.blade.php new file mode 100644 index 000000000000..5f2f7daa4416 --- /dev/null +++ b/resources/views/bots/skype/invoice.blade.php @@ -0,0 +1,43 @@ +{ + "type":"message/card.receipt", + "attachments":[ + { + "contentType":"application/vnd.microsoft.card.receipt", + "content":{ + "title" : '{!! trans('texts.invoice_for_client', [ + 'invoice' => link_to($invoice->getRoute(), $invoice->invoice_number), + 'client' => link_to($invoice->client->getRoute(), $invoice->client->getDisplayName()) + ]) !!}', + "items":[ + @foreach ($invoice->invoice_items as $item) + @if ($invoice->invoice_items[0] != $item) + , + @endif + { + "title":"{{ $item->product_key }}", + "subtitle":"{{ $item->notes }}", + "price":"{{ $item->cost }}", + "quantity":"{{ $item->qty }}" + } + @endforeach + ], + @if (false) + "tax":"0.00", + @endif + "total":"{{ $invoice->present()->amount }}", + "buttons":[ + { + "type":"imBack", + "title":"{{ trans('texts.send_email') }}", + "value":"send_email" + }, + { + "type":"imBack", + "title":"{{ trans('texts.download_pdf') }}", + "value":"download_pdf" + } + ] + } + } + ] +}