From 6335ba717d046617afdab41ad24367282ff7d7ff Mon Sep 17 00:00:00 2001 From: Sahan H Date: Mon, 29 May 2017 00:59:20 +0530 Subject: [PATCH 01/17] opt-in into an exception based flow in repository updated addNeed to return created need for later access --- app/Repositories/NeedsRepository.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/app/Repositories/NeedsRepository.php b/app/Repositories/NeedsRepository.php index 0186d6f..5c574a2 100644 --- a/app/Repositories/NeedsRepository.php +++ b/app/Repositories/NeedsRepository.php @@ -11,6 +11,7 @@ use App\Need; use App\Repositories\Contracts\NeedsInterface; use Illuminate\Support\Facades\Log; +use DomainException; class NeedsRepository implements NeedsInterface { @@ -23,11 +24,9 @@ class NeedsRepository implements NeedsInterface public function addNeed($input) { try { - Need::create($input); - return true; + return Need::create($input); } catch (\Exception $e) { - Log::error($e->getMessage()); - return false; + throw new DomainException('Unable to create need.'); } } From 942708c9b4e75616d781564d812c82b1a7494d00 Mon Sep 17 00:00:00 2001 From: Sahan H Date: Mon, 29 May 2017 00:59:36 +0530 Subject: [PATCH 02/17] added fb sdk --- app/Services/FacebookNotification.php | 47 +++++++++++++++++++++++++++ composer.json | 3 +- config/services.php | 6 ++++ 3 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 app/Services/FacebookNotification.php diff --git a/app/Services/FacebookNotification.php b/app/Services/FacebookNotification.php new file mode 100644 index 0000000..e72f50d --- /dev/null +++ b/app/Services/FacebookNotification.php @@ -0,0 +1,47 @@ +fb = new Facebook([ + 'app_id' => Config::get('services.facebook.app_id'), + 'app_secret' => Config::get('services.facebook.app_secret'), + 'default_graph_version' => 'v2.9', + 'default_access_token' => Config::get('services.facebook.page_token') + ]); + } + + public function publishNeed(Need $need) + { + $content = []; + $content[] = $need->needs; + $content[] = $need->address; + $content[] = $need->city; + $content[] = "People - ". $need->heads; + $content[] = $need->name.' - '.$need->telephone; + + try { + $response = $this->fb->post('/me/feed', ['message' => implode($content, "\n")]); + } catch(FacebookResponseException $e) { + Log::error($e); + return false; + } catch(FacebookSDKException $e) { + Log::error($e); + return false; + } + } +} \ No newline at end of file diff --git a/composer.json b/composer.json index 497b120..3e59c76 100644 --- a/composer.json +++ b/composer.json @@ -1,4 +1,4 @@ - { +{ "name": "laravel/laravel", "description": "The Laravel Framework.", "keywords": ["framework", "laravel"], @@ -6,6 +6,7 @@ "type": "project", "require": { "php": ">=5.6.4", + "facebook/graph-sdk": "^5.5", "laravel/framework": "5.4.*", "laravel/tinker": "~1.0" }, diff --git a/config/services.php b/config/services.php index 4460f0e..8efb882 100644 --- a/config/services.php +++ b/config/services.php @@ -35,4 +35,10 @@ 'secret' => env('STRIPE_SECRET'), ], + 'facebook' => [ + 'app_id' => env('FB_APP_ID'), + 'app_secret' => env('FB_APP_SECRET'), + 'page_token' => env('FB_PAGE_TOKEN') + ] + ]; From 32c8c8483c2f46f2e653da2269f44a8ac4ea099a Mon Sep 17 00:00:00 2001 From: Sahan H Date: Mon, 29 May 2017 00:59:47 +0530 Subject: [PATCH 03/17] migration to add fb_post_id to db --- ...7_05_29_003241_add_fb_post_id_to_needs.php | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 database/migrations/2017_05_29_003241_add_fb_post_id_to_needs.php diff --git a/database/migrations/2017_05_29_003241_add_fb_post_id_to_needs.php b/database/migrations/2017_05_29_003241_add_fb_post_id_to_needs.php new file mode 100644 index 0000000..a0dfc8c --- /dev/null +++ b/database/migrations/2017_05_29_003241_add_fb_post_id_to_needs.php @@ -0,0 +1,32 @@ +string("fb_post_id", 100)->after("heads")->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('needs', function (Blueprint $table) { + $table->dropColumn("needs"); + }); + } +} From 23d907c01c29fb9811cd5a1fcbcc5ec20844d70c Mon Sep 17 00:00:00 2001 From: Sahan H Date: Mon, 29 May 2017 01:09:24 +0530 Subject: [PATCH 04/17] added fb_post_id to fillables --- app/Need.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Need.php b/app/Need.php index 39d3841..731ae80 100644 --- a/app/Need.php +++ b/app/Need.php @@ -12,6 +12,6 @@ class Need extends Model * @var array */ protected $fillable = [ - 'name', 'telephone', 'address', 'city', 'needs', 'heads' + 'name', 'telephone', 'address', 'city', 'needs', 'heads', 'fb_post_id' ]; } From f0a2475b0377eeac7fa3b79eff78612302b28094 Mon Sep 17 00:00:00 2001 From: Sahan H Date: Mon, 29 May 2017 01:09:32 +0530 Subject: [PATCH 05/17] implemented need update --- app/Repositories/NeedsRepository.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/app/Repositories/NeedsRepository.php b/app/Repositories/NeedsRepository.php index 5c574a2..40cdd11 100644 --- a/app/Repositories/NeedsRepository.php +++ b/app/Repositories/NeedsRepository.php @@ -30,6 +30,18 @@ public function addNeed($input) } } + public function updateNeed($id, array $input) + { + $need = $this->findNeed($id); + + if ($need) { + $need->fill($input); + return $need->save(); + } else { + return false; + } + } + /** * Get all donations * From 7ddaa5dc2b50f7353711b50fdfaa7128bfd0dd3e Mon Sep 17 00:00:00 2001 From: Sahan H Date: Mon, 29 May 2017 01:09:56 +0530 Subject: [PATCH 06/17] returning fb post id --- app/Services/FacebookNotification.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/Services/FacebookNotification.php b/app/Services/FacebookNotification.php index e72f50d..a61a168 100644 --- a/app/Services/FacebookNotification.php +++ b/app/Services/FacebookNotification.php @@ -35,7 +35,11 @@ public function publishNeed(Need $need) $content[] = $need->name.' - '.$need->telephone; try { + $response = $this->fb->post('/me/feed', ['message' => implode($content, "\n")]); + $response->decodeBody(); + return array_get($response->getDecodedBody(), 'id'); + } catch(FacebookResponseException $e) { Log::error($e); return false; From 2b193b40feb32db5e6c0f15d7176fd458bc107e4 Mon Sep 17 00:00:00 2001 From: Sahan H Date: Mon, 29 May 2017 01:10:08 +0530 Subject: [PATCH 07/17] implemented fb notification system --- app/Http/Controllers/NeedsController.php | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/app/Http/Controllers/NeedsController.php b/app/Http/Controllers/NeedsController.php index 9ea525f..1239378 100644 --- a/app/Http/Controllers/NeedsController.php +++ b/app/Http/Controllers/NeedsController.php @@ -6,18 +6,24 @@ use Illuminate\Http\Request; use Illuminate\Support\Facades\Response; use Validator; +use App\Services\FacebookNotification; +use DomainException; class NeedsController extends Controller { private $need; + private $fbNotifier; + /** * NeedsController constructor. * @param NeedsRepository $needsRepository + * @param FacebookNotification $fbNotifier */ - public function __construct(NeedsRepository $needsRepository) + public function __construct(NeedsRepository $needsRepository, FacebookNotification $fbNotifier) { $this->need = $needsRepository; + $this->fbNotifier = $fbNotifier; } /** @@ -63,12 +69,19 @@ public function save(Request $request) ->with('errors', $validator->errors()->all()) ->withInput(); } else { - $response = $this->need->addNeed($request->all()); - if ($response) { + try { + + $need = $this->need->addNeed($request->all()); + + //need is being created first and if fb posting fail rest of the logic + //is executed + $fbId = $this->fbNotifier->publishNeed($need); + $this->need->updateNeed($need->id, ['fb_post_id' => $fbId]); + return redirect('/needs') ->with('isSuccess', true) ->with('message', 'Needs added.'); - } else { + } catch (DomainException $e) { return redirect('/needs/add') ->with('isSuccess', false) ->with('errors', ['Needs adding failed. Please try again.']) From a3315c5645b0ad8674cc326af25f5d81b5438a90 Mon Sep 17 00:00:00 2001 From: Sahan H Date: Mon, 29 May 2017 01:10:47 +0530 Subject: [PATCH 08/17] updated sample env --- .env.example | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.env.example b/.env.example index e687634..b88b857 100644 --- a/.env.example +++ b/.env.example @@ -30,4 +30,8 @@ MAIL_ENCRYPTION=null PUSHER_APP_ID= PUSHER_APP_KEY= -PUSHER_APP_SECRET= \ No newline at end of file +PUSHER_APP_SECRET= + +FB_APP_ID= +FB_APP_SECRET= +FB_PAGE_TOKEN= \ No newline at end of file From f616d49ecf3cad6c3f25b560e7c57152ccc1ca01 Mon Sep 17 00:00:00 2001 From: Sahan H Date: Mon, 29 May 2017 00:59:20 +0530 Subject: [PATCH 09/17] opt-in into an exception based flow in repository updated addNeed to return created need for later access --- app/Repositories/NeedsRepository.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/app/Repositories/NeedsRepository.php b/app/Repositories/NeedsRepository.php index 0186d6f..5c574a2 100644 --- a/app/Repositories/NeedsRepository.php +++ b/app/Repositories/NeedsRepository.php @@ -11,6 +11,7 @@ use App\Need; use App\Repositories\Contracts\NeedsInterface; use Illuminate\Support\Facades\Log; +use DomainException; class NeedsRepository implements NeedsInterface { @@ -23,11 +24,9 @@ class NeedsRepository implements NeedsInterface public function addNeed($input) { try { - Need::create($input); - return true; + return Need::create($input); } catch (\Exception $e) { - Log::error($e->getMessage()); - return false; + throw new DomainException('Unable to create need.'); } } From f587d18d81e75b9e92c01fdd987b5dbba9d7840d Mon Sep 17 00:00:00 2001 From: Sahan H Date: Mon, 29 May 2017 00:59:36 +0530 Subject: [PATCH 10/17] added fb sdk --- app/Services/FacebookNotification.php | 47 +++++++++++++++++++++++++++ composer.json | 1 + config/services.php | 6 ++++ 3 files changed, 54 insertions(+) create mode 100644 app/Services/FacebookNotification.php diff --git a/app/Services/FacebookNotification.php b/app/Services/FacebookNotification.php new file mode 100644 index 0000000..e72f50d --- /dev/null +++ b/app/Services/FacebookNotification.php @@ -0,0 +1,47 @@ +fb = new Facebook([ + 'app_id' => Config::get('services.facebook.app_id'), + 'app_secret' => Config::get('services.facebook.app_secret'), + 'default_graph_version' => 'v2.9', + 'default_access_token' => Config::get('services.facebook.page_token') + ]); + } + + public function publishNeed(Need $need) + { + $content = []; + $content[] = $need->needs; + $content[] = $need->address; + $content[] = $need->city; + $content[] = "People - ". $need->heads; + $content[] = $need->name.' - '.$need->telephone; + + try { + $response = $this->fb->post('/me/feed', ['message' => implode($content, "\n")]); + } catch(FacebookResponseException $e) { + Log::error($e); + return false; + } catch(FacebookSDKException $e) { + Log::error($e); + return false; + } + } +} \ No newline at end of file diff --git a/composer.json b/composer.json index 103d83b..7b4e934 100644 --- a/composer.json +++ b/composer.json @@ -6,6 +6,7 @@ "type": "project", "require": { "php": ">=5.6.4", + "facebook/graph-sdk": "^5.5", "laravel/framework": "5.4.*", "laravel/tinker": "~1.0", "albertcht/invisible-recaptcha": "^1.3" diff --git a/config/services.php b/config/services.php index 4460f0e..8efb882 100644 --- a/config/services.php +++ b/config/services.php @@ -35,4 +35,10 @@ 'secret' => env('STRIPE_SECRET'), ], + 'facebook' => [ + 'app_id' => env('FB_APP_ID'), + 'app_secret' => env('FB_APP_SECRET'), + 'page_token' => env('FB_PAGE_TOKEN') + ] + ]; From 243ee508e449db04f43f120adf97218ceb59e227 Mon Sep 17 00:00:00 2001 From: Sahan H Date: Mon, 29 May 2017 00:59:47 +0530 Subject: [PATCH 11/17] migration to add fb_post_id to db --- ...7_05_29_003241_add_fb_post_id_to_needs.php | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 database/migrations/2017_05_29_003241_add_fb_post_id_to_needs.php diff --git a/database/migrations/2017_05_29_003241_add_fb_post_id_to_needs.php b/database/migrations/2017_05_29_003241_add_fb_post_id_to_needs.php new file mode 100644 index 0000000..a0dfc8c --- /dev/null +++ b/database/migrations/2017_05_29_003241_add_fb_post_id_to_needs.php @@ -0,0 +1,32 @@ +string("fb_post_id", 100)->after("heads")->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('needs', function (Blueprint $table) { + $table->dropColumn("needs"); + }); + } +} From 61eedb8e6a521cc7ff5df4e9bd414bbb6cc43a86 Mon Sep 17 00:00:00 2001 From: Sahan H Date: Mon, 29 May 2017 01:09:24 +0530 Subject: [PATCH 12/17] added fb_post_id to fillables --- app/Need.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Need.php b/app/Need.php index 4e626ad..6f09fb2 100644 --- a/app/Need.php +++ b/app/Need.php @@ -12,6 +12,6 @@ class Need extends Model * @var array */ protected $fillable = [ - 'name', 'telephone', 'address', 'city', 'needs', 'heads', 'source' + 'name', 'telephone', 'address', 'city', 'needs', 'heads', 'source', 'fb_post_id' ]; } From 859c4b9bb307bf813c058cd65c042fc6dc063019 Mon Sep 17 00:00:00 2001 From: Sahan H Date: Mon, 29 May 2017 01:09:32 +0530 Subject: [PATCH 13/17] implemented need update --- app/Repositories/NeedsRepository.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/app/Repositories/NeedsRepository.php b/app/Repositories/NeedsRepository.php index 5c574a2..40cdd11 100644 --- a/app/Repositories/NeedsRepository.php +++ b/app/Repositories/NeedsRepository.php @@ -30,6 +30,18 @@ public function addNeed($input) } } + public function updateNeed($id, array $input) + { + $need = $this->findNeed($id); + + if ($need) { + $need->fill($input); + return $need->save(); + } else { + return false; + } + } + /** * Get all donations * From f0f3c6a75452ace45e16e2d2c7a83d92ef064fd0 Mon Sep 17 00:00:00 2001 From: Sahan H Date: Mon, 29 May 2017 01:09:56 +0530 Subject: [PATCH 14/17] returning fb post id --- app/Services/FacebookNotification.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/Services/FacebookNotification.php b/app/Services/FacebookNotification.php index e72f50d..a61a168 100644 --- a/app/Services/FacebookNotification.php +++ b/app/Services/FacebookNotification.php @@ -35,7 +35,11 @@ public function publishNeed(Need $need) $content[] = $need->name.' - '.$need->telephone; try { + $response = $this->fb->post('/me/feed', ['message' => implode($content, "\n")]); + $response->decodeBody(); + return array_get($response->getDecodedBody(), 'id'); + } catch(FacebookResponseException $e) { Log::error($e); return false; From d7d012db424c6b94f6e2797fd0687838cf284c7c Mon Sep 17 00:00:00 2001 From: Sahan H Date: Mon, 29 May 2017 01:10:08 +0530 Subject: [PATCH 15/17] implemented fb notification system --- app/Http/Controllers/NeedsController.php | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/app/Http/Controllers/NeedsController.php b/app/Http/Controllers/NeedsController.php index d442e6c..16362ee 100644 --- a/app/Http/Controllers/NeedsController.php +++ b/app/Http/Controllers/NeedsController.php @@ -6,18 +6,24 @@ use Illuminate\Http\Request; use Illuminate\Support\Facades\Response; use Validator; +use App\Services\FacebookNotification; +use DomainException; class NeedsController extends Controller { private $need; + private $fbNotifier; + /** * NeedsController constructor. * @param NeedsRepository $needsRepository + * @param FacebookNotification $fbNotifier */ - public function __construct(NeedsRepository $needsRepository) + public function __construct(NeedsRepository $needsRepository, FacebookNotification $fbNotifier) { $this->need = $needsRepository; + $this->fbNotifier = $fbNotifier; } /** @@ -68,17 +74,27 @@ public function save(Request $request) ], $messages); if ($validator->fails()) { + return redirect('/needs/add') ->with('isSuccess', false) ->with('errors', $validator->errors()->all()) ->withInput(); } else { - $response = $this->need->addNeed($request->all()); - if ($response) { + + try { + + $need = $this->need->addNeed($request->all()); + + //need is being created first and if fb posting fail rest of the logic + //is executed + $fbId = $this->fbNotifier->publishNeed($need); + $this->need->updateNeed($need->id, ['fb_post_id' => $fbId]); + return redirect('/needs') ->with('isSuccess', true) ->with('message', 'සාර්ථකව ඇතුලත්කරන ලදී.'); - } else { + + } catch (DomainException $e) { return redirect('/needs/add') ->with('isSuccess', false) ->with('errors', ['ඇතුලත්කිරීම දෝෂ සහිතය.']) From 81f38e7708bbc2c602f749291e7cca513c05986d Mon Sep 17 00:00:00 2001 From: Sahan H Date: Mon, 29 May 2017 01:10:47 +0530 Subject: [PATCH 16/17] updated sample env --- .env.example | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.env.example b/.env.example index 333bfc0..990696d 100644 --- a/.env.example +++ b/.env.example @@ -32,9 +32,12 @@ PUSHER_APP_ID= PUSHER_APP_KEY= PUSHER_APP_SECRET= - INVISIBLE_RECAPTCHA_SITEKEY=6LfdQSMUAAAAAOP31dkmdZJeNvDghlBfqJsHT5M- INVISIBLE_RECAPTCHA_SECRETKEY=6LfdQSMUAAAAAAT5cKXa7lI3koiFy4c5BP7BX3m8 NOCAPTCHA_SECRET=6LfdQSMUAAAAAAT5cKXa7lI3koiFy4c5BP7BX3m8 NOCAPTCHA_SITEKEY=6LfdQSMUAAAAAOP31dkmdZJeNvDghlBfqJsHT5M- + +FB_APP_ID=424974257871315 +FB_APP_SECRET=94e6ed7204eb94082bc87feeb7bea7ca +FB_PAGE_TOKEN=EAAGCgwet2dMBAJJsZBgVTZCb4jdgTVnJD8TjvsOQ5JKyxEYWc7d6xSeosfZBqjITY95qC0jQ66RsBRZBlprHCbE5YYQl6cwaKHZAR4MXLZA977jtCaOP3Q5ZCXY7UrBJCV6IOcIAbmsBPFNoyecLgn6qVMecdxQrspbd31AoxvZBz4bZBZCOPSC6Cb From f725679d92b242e2bb32f14829b2ef963d97b136 Mon Sep 17 00:00:00 2001 From: Sahan H Date: Wed, 31 May 2017 11:59:41 +0530 Subject: [PATCH 17/17] updated readme with facebook intergration --- README.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/README.md b/README.md index 75392c2..88e12ca 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,29 @@ chmod -R 777 storage/ chmod 777 bootstrap/cache ``` +#### Facebook intergration + +Facebook intergration automatically post need requests to a facebook page. A facebook app and administrative rights to a page is required. Using them an access token to page should be generated to put in .env file. The app does not need to be approved if the page admin has has administrative rights to the app. + +![](http://d.pr/i/R3WrWj+) + +![](http://d.pr/i/othvIj+) +Click "Get Access Token" + +![](http://d.pr/i/JL3vnV+) + +The access token is short lived one (2 hours), now we need to convert it to long-lived. + +Visit below url and it will give you the access token + +`https://graph.facebook.com/oauth/access_token? + client_id=APP_ID& + client_secret=APP_SECRET& + grant_type=fb_exchange_token& + fb_exchange_token=EXISTING_ACCESS_TOKEN ` + +Refer to .env.sample to place the credentials. + ### Pull requests Send all the PRs to `dev` branch. We keep `master` and `prod` branches only for final releases and all the development works on the `dev`.