diff --git a/app/Http/Controllers/SmsController.php b/app/Http/Controllers/SmsController.php new file mode 100644 index 0000000..cb80579 --- /dev/null +++ b/app/Http/Controllers/SmsController.php @@ -0,0 +1,114 @@ +middleware('auth'); + } + + private function max_message_length($numbers) { + $max_name_length = 0; + foreach($numbers as $n) { + if(strlen($n->name) > $max_name_length) { + $max_name_length = strlen($n->name); + } + } + return 160 - $max_name_length - 1; + } + + public function index() { + $this->authorize('admin'); + + $numbers = PhoneNumber::orderBy('name')->get(); + $maxlen = $this->max_message_length($numbers); + + return view('sms', [ + 'numbers' => $numbers, + 'maxlen' => $maxlen + ]); + } + + public function save(Request $request) { + $this->authorize('admin'); + + if(preg_match_all('/(.+)\s+([0-9\-]+)/', $request->input('input'), $matches)) { + + $contacts = []; + $errors = []; + foreach($matches[1] as $i=>$name) { + if(preg_match('/^1?(\d{3})-?(\d{3})-?(\d{4})$/', $matches[2][$i], $pm)) { + $contacts[] = [trim($name), $pm[1].'-'.$pm[2].'-'.$pm[3]]; + } else { + $errors[] = $matches[0][$i]; + } + } + + if(count($errors)) { + $request->session()->flash('status', 'danger'); + $request->session()->flash('status-message', 'There was a problem with some of your entries. No numbers were changed. The lines below had errors:
'.implode('
', array_map('htmlspecialchars', $errors))); + + } else { + DB::table('phone_numbers')->delete(); + foreach($contacts as $c) { + $p = new PhoneNumber; + $p->name = $c[0]; + $p->phone = $c[1]; + $p->save(); + } + + $request->session()->flash('status', 'success'); + $request->session()->flash('status-message', 'Phone numbers saved!'); + } + + + } else { + $request->session()->flash('status', 'danger'); + $request->session()->flash('status-message', 'Invalid input, phone numbers were not modified'); + } + + return redirect('sms'); + } + + public function send(Request $request) { + $this->authorize('admin'); + + $numbers = PhoneNumber::orderBy('name')->get(); + $maxlen = $this->max_message_length($numbers); + + if(strlen($request->input('text')) <= $maxlen) { + + $client = new \Twilio\Rest\Client(env('TWILIO_SID'), env('TWILIO_TOKEN')); + foreach($numbers as $number) { + $text = $request->input('text'); + $text = str_replace('{name}', $number->name, $text); + $message = $client->messages->create( + '+1'.str_replace('-','',$number->phone), + array( + 'from' => env('TWILIO_NUMBER'), + 'body' => $text + ) + ); + } + + $request->session()->flash('status', 'success'); + $request->session()->flash('status-message', 'Message was sent! It will take about 1 second per number to deliver all the messages!'); + } else { + $request->session()->flash('status', 'danger'); + $request->session()->flash('status-message', 'Your message was too long!'); + } + + return redirect('sms'); + } + +} diff --git a/app/PhoneNumber.php b/app/PhoneNumber.php new file mode 100644 index 0000000..8ec586a --- /dev/null +++ b/app/PhoneNumber.php @@ -0,0 +1,12 @@ +belongsTo('\App\User'); + } +} diff --git a/composer.json b/composer.json index 68a2542..4b58740 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,8 @@ "mnabialek/laravel-sql-logger": "^1.1", "predis/predis": "^1.1", "pusher/pusher-php-server": "^2.6", - "thujohn/twitter": "^2.2" + "thujohn/twitter": "^2.2", + "twilio/sdk": "^5.11" }, "require-dev": { "fzaninotto/faker": "~1.4", diff --git a/composer.lock b/composer.lock index 7024619..60908a8 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "content-hash": "5681db78f7fa8c08618795173764986e", + "content-hash": "41238565556ee0b0f7094b70d9cae03e", "packages": [ { "name": "dnoegel/php-xdg-base-dir", @@ -2461,6 +2461,52 @@ "homepage": "https://github.com/tijsverkoyen/CssToInlineStyles", "time": "2016-09-20T12:50:39+00:00" }, + { + "name": "twilio/sdk", + "version": "5.11.0", + "source": { + "type": "git", + "url": "https://github.com/twilio/twilio-php.git", + "reference": "6887cc761df5b011bce5460ad643e846ad8a5548" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/twilio/twilio-php/zipball/6887cc761df5b011bce5460ad643e846ad8a5548", + "reference": "6887cc761df5b011bce5460ad643e846ad8a5548", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "require-dev": { + "apigen/apigen": "^4.1", + "phpunit/phpunit": "4.5.*" + }, + "type": "library", + "autoload": { + "psr-4": { + "Twilio\\": "Twilio/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Twilio API Team", + "email": "api@twilio.com" + } + ], + "description": "A PHP wrapper for Twilio's API", + "homepage": "http://github.com/twilio/twilio-php", + "keywords": [ + "api", + "sms", + "twilio" + ], + "time": "2017-06-16T20:19:46+00:00" + }, { "name": "vlucas/phpdotenv", "version": "v2.4.0", diff --git a/database/migrations/2017_07_08_032850_BulkSMS.php b/database/migrations/2017_07_08_032850_BulkSMS.php new file mode 100644 index 0000000..5369007 --- /dev/null +++ b/database/migrations/2017_07_08_032850_BulkSMS.php @@ -0,0 +1,33 @@ +increments('id'); + $table->timestamps(); + $table->string('name', 255); + $table->string('phone', 255); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('phone_numbers'); + } +} diff --git a/database/migrations/2017_07_08_033123_sms_log.php b/database/migrations/2017_07_08_033123_sms_log.php new file mode 100644 index 0000000..360e2ea --- /dev/null +++ b/database/migrations/2017_07_08_033123_sms_log.php @@ -0,0 +1,33 @@ +increments('id'); + $table->timestamps(); + $table->text('text'); + $table->integer('user_id'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('sent_messages'); + } +} diff --git a/resources/views/layouts/app.blade.php b/resources/views/layouts/app.blade.php index e6ab758..e14d723 100644 --- a/resources/views/layouts/app.blade.php +++ b/resources/views/layouts/app.blade.php @@ -39,8 +39,9 @@ @if(!Auth::guest())
  • Dashboard
  • @endif +
  • Teams
  • @can('admin') -
  • Teams
  • +
  • SMS
  • @endcan
  • Slideshow
  • Scoreboard
  • diff --git a/resources/views/sms.blade.php b/resources/views/sms.blade.php new file mode 100644 index 0000000..9fbff8c --- /dev/null +++ b/resources/views/sms.blade.php @@ -0,0 +1,46 @@ +@extends('layouts.app') + +@section('content') +
    +
    +
    + + @if(session('status')) + + @endif + +
    +

    Broadcast a Message

    +

    Enter a message to send. The message length is limited based on the longest person's name. To include the person's name, enter the placeholder {name}.

    + +
    + +
    + + + + {{ csrf_field() }} +
    + + + +
    + +

    Phone Numbers

    +

    Enter your phone number database, one person per line. First name followed by their phone number. Numbers will be normalized to US format when saved.

    +
    + +
    + + + + {{ csrf_field() }} +
    + +
    +
    +
    +@endsection diff --git a/routes/web.php b/routes/web.php index c2b0212..c61a604 100644 --- a/routes/web.php +++ b/routes/web.php @@ -43,3 +43,7 @@ Route::post('/twitter/stream', 'TwitterController@input'); Route::get('/mission/{mission}', 'ShowTweetsController@mission')->name('mission'); Route::get('/team/{team}', 'ShowTweetsController@team')->name('team'); + +Route::get('/sms', 'SMSController@index')->name('sms'); +Route::post('/sms/save-numbers', 'SMSController@save')->name('sms-save'); +Route::post('/sms/send', 'SMSController@send')->name('sms-send');