Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

1550 platform api receive [WIP] #1665

Merged
merged 57 commits into from
Feb 7, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
b819d5b
Allow users to specify for form inbound data
willdoran Mar 30, 2017
79d55d2
Adding ability to set a destination field based on a user set form - …
willdoran Mar 30, 2017
692935e
Adding api keys to API - designed to allow multiple keys and later cl…
willdoran Mar 30, 2017
2ebd493
Adding external api route
willdoran Mar 31, 2017
53b24b7
Linting
willdoran Mar 31, 2017
9c7e777
do not require source and destination fields to be set
willdoran Mar 31, 2017
0a085b2
remove :
willdoran Mar 31, 2017
51a6b00
Fixing test
willdoran Mar 31, 2017
609a019
Removing another :
willdoran Mar 31, 2017
7697bb3
Adding webhook_uuid to entity
willdoran Mar 31, 2017
ed29ed5
fixing test
willdoran Mar 31, 2017
f59f0c3
Updating tests
willdoran Apr 4, 2017
8496f6e
Full route from platform to yodie and back operational
willdoran Apr 4, 2017
c585e41
remove logging
willdoran Apr 4, 2017
ba68a23
Remove logging
willdoran Apr 5, 2017
6473865
Adding source, destination and form fields to webhooks
willdoran Apr 6, 2017
a49491b
Adding webhook form_id, source and destination uuid
willdoran Apr 6, 2017
633da4b
Adding update, delete event handler
willdoran Apr 6, 2017
a24eb37
Fixing typo
willdoran Apr 6, 2017
f59a1fa
Updating webhook validation
willdoran Apr 6, 2017
2d46387
fixing migrations
willdoran Apr 6, 2017
9068567
Disabled delete event for the moment
willdoran Apr 6, 2017
51c0c95
Twitter correctly map to forms
willdoran Apr 12, 2017
b9af5e5
Updating webhooks
willdoran Apr 13, 2017
562b350
Changing to use array key indexes
willdoran Apr 13, 2017
d43b97c
Complete flow working
willdoran Apr 13, 2017
9083e3c
Remove webhook jobs
willdoran Apr 14, 2017
be7df25
Merging develop
willdoran Apr 14, 2017
7ed7297
Fixed webhook test
willdoran Apr 14, 2017
e6f519c
linting
willdoran Apr 14, 2017
75d2c50
Fix missing comma
willdoran Apr 14, 2017
6a83985
Fix missing comma
willdoran Apr 14, 2017
75f2ab8
Reverting change
willdoran Apr 14, 2017
161ac3c
Fixing tests and ensuring flow works
willdoran Apr 14, 2017
0b82717
Remove incorrect validation
willdoran Apr 17, 2017
8053934
Fix indenting
willdoran Apr 21, 2017
3c1e622
Merge branch 'develop' into 1550-platform-api-receive
willdoran Apr 21, 2017
794400f
Fixed spec test
willdoran Apr 21, 2017
81af526
disabling test
willdoran Apr 21, 2017
8475da8
Merge develop
willdoran May 22, 2017
cb88d4b
Updating linting
willdoran May 22, 2017
96b2757
Fixed linting
willdoran May 22, 2017
253a044
Adding survey linking to sms and email datasources
willdoran May 23, 2017
495422b
Adding form linking for all datasources
willdoran May 23, 2017
0342b73
Fix incorrect var
willdoran May 23, 2017
1d7b527
Setting var default
willdoran May 23, 2017
b23c238
Fix webhook updating
willdoran May 24, 2017
07c6be3
Fix webhook updating
willdoran May 24, 2017
db4d4a6
Merge branch 'develop' into 1550-platform-api-receive
willdoran Jun 1, 2017
aa790b8
Merging Develop
willdoran Sep 19, 2017
88d2977
Updating fixtures
willdoran Sep 19, 2017
f0c36ed
Merge branch 'develop' into 1550-platform-api-receive
willdoran Dec 18, 2017
e264700
Adding separate route for legacy saving of tags
willdoran Dec 18, 2017
59feb69
fix tests
willdoran Dec 20, 2017
6888151
Changing permission check to new version
willdoran Jan 25, 2018
62a05f9
Merge branch 'develop' into 1550-platform-api-receive
willdoran Feb 5, 2018
6fca3c9
Merge branch 'develop' into 1550-platform-api-receive
willdoran Feb 7, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions application/classes/Controller/Api/Apikeys.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php defined('SYSPATH') OR die('No direct access allowed.');

/**
* Ushahidi API Keys Controller
*
* @author Ushahidi Team <team@ushahidi.com>
* @package Ushahidi\Application\Controllers
* @copyright 2013 Ushahidi
* @license https://www.gnu.org/licenses/agpl-3.0.html GNU Affero General Public License Version 3 (AGPL3)
*/

class Controller_Api_ApiKeys extends Ushahidi_Rest {

protected function _scope()
{
return 'apikeys';
}
}
67 changes: 67 additions & 0 deletions application/classes/Controller/Api/Webhooks/Posts.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?php defined('SYSPATH') OR die('No direct access allowed.');

/**
* Ushahidi API External Webhook Posts Controller
*
* @author Ushahidi Team <team@ushahidi.com>
* @package Ushahidi\Application\Controllers
* @copyright 2013 Ushahidi
* @license https://www.gnu.org/licenses/agpl-3.0.html GNU Affero General Public License Version 3 (AGPL3)
*/

use Ushahidi\Core\Tool\Signer;

class Controller_Api_Webhooks_Posts extends Controller_Api_Posts {

protected function _is_auth_required()
{
return false;
}

public function checkApiKey($data)
{

if (isset($data['api_key'])) {
// Get api key and compare
return service('repository.apikey')->apiKeyExists($data['api_key']);
}

return false;
}

public function checkSignature($data)
{
$signature = $this->request->headers('X-Ushahidi-Signature');

if (isset($data['webhook_uuid']) && $signature) {

// Get webhook and validate signature
$webhook = service('repository.webhook')->getByUUID($data['webhook_uuid']);
$signer = new Signer($webhook->shared_secret);
$fullURL = URL::site(Request::detect_uri(), TRUE) . URL::query();

return $signer->validate($signature, $fullURL, $data);
}
return false;
}

public function before()
{
parent::before();

$post = $this->_request_payload;

if (!$this->checkApiKey($post) || !$this->checkSignature($post))
{
throw HTTP_Exception::factory(403, 'Forbidden');
}
}

public function action_put_index()
{
$this->_usecase = service('factory.usecase')
->get($this->_resource(), 'webhook-update')
->setIdentifiers($this->_identifiers())
->setPayload($this->_payload());
}
}
47 changes: 33 additions & 14 deletions application/classes/Ushahidi/Console/Webhook.php
Original file line number Diff line number Diff line change
Expand Up @@ -105,27 +105,46 @@ protected function executeSend(InputInterface $input, OutputInterface $output)
private function generateRequest($webhook_request)
{
// Delete queued webhook request
//$this->webhookJobRepository->delete($webhook_request);
$this->webhookJobRepository->delete($webhook_request);

// Get post data
$post = $this->postRepository->get($webhook_request->post_id);
$json = json_encode($post->asArray());

// Get webhook data
$webhook = $this->webhookRepository->getByEventType($webhook_request->event_type);
$webhooks = $this->webhookRepository->getAllByEventType($webhook_request->event_type);

$this->signer = new Signer($webhook->shared_secret);
foreach ($webhooks as $webhook) {

$signature = $this->signer->sign($webhook->url, $json);
if ($post->form_id == $webhook['form_id']) {
$this->signer = new Signer($webhook['shared_secret']);

// This is an asynchronous request, we don't expect a result
// this can be extended to allow for handling of the returned promise
$promise = $this->client->request('POST', $webhook->url, [
'headers' => [
'X-Platform-Signature' => $signature,
'Accept' => 'application/json'
],
'json' => $post->asArray()
]);
$data = $post->asArray();

// Attach Webhook Uuid so that service can subsequently identify itself
// when sending data to the Platform
$data['webhook_uuid'] = $webhook['webhook_uuid'];

// If set append the source and destination fields to the request
// These fields identify the UUIDs of the Post fields which the remot service should
// treat as the source of data and the destination for any data to be posted back to the Platform
$data['source_field_key'] = $webhook['source_field_key'] ?: null;
$data['destination_field_key'] = $webhook['destination_field_key'] ?: null;

$json = json_encode($data);
$signature = $this->signer->sign($webhook['url'], $json);

// This is an asynchronous request, we don't expect a result
// this can be extended to allow for handling of the returned promise
//TODO: HANDLE HTTP ERRORS
$promise = $this->client->request('POST', $webhook['url'], [
'headers' => [
'X-Ushahidi-Signature' => $signature,
'Accept' => 'application/json'
],
'json' => $data
]);

}
}
}
}
11 changes: 10 additions & 1 deletion application/classes/Ushahidi/Core.php
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,8 @@ public static function init()
];
$di->params['Ushahidi\Factory\ValidatorFactory']['map']['posts'] = [
'create' => $di->lazyNew('Ushahidi_Validator_Post_Create'),
'update' => $di->lazyNew('Ushahidi_Validator_Post_Create'),
'webhook-update' => $di->lazyNew('Ushahidi_Validator_Post_Create'),
'update' => $di->lazyNew('Ushahidi_Validator_Post_Update'),
'import' => $di->lazyNew('Ushahidi_Validator_Post_Import'),
];
Expand Down Expand Up @@ -287,6 +289,10 @@ public static function init()
'create' => $di->lazyNew('Ushahidi_Validator_Notification_Create'),
'update' => $di->lazyNew('Ushahidi_Validator_Notification_Update'),
];
$di->params['Ushahidi\Factory\ValidatorFactory']['map']['apikeys'] = [
'create' => $di->lazyNew('Ushahidi_Validator_ApiKey_Create'),
'update' => $di->lazyNew('Ushahidi_Validator_ApiKey_Update'),
];
$di->params['Ushahidi\Factory\ValidatorFactory']['map']['webhooks'] = [
'create' => $di->lazyNew('Ushahidi_Validator_Webhook_Create'),
'update' => $di->lazyNew('Ushahidi_Validator_Webhook_Update'),
Expand Down Expand Up @@ -339,7 +345,8 @@ public static function init()
'savedsearches_posts' => $di->lazyNew('Ushahidi_Formatter_Post'),
'users' => $di->lazyNew('Ushahidi_Formatter_User'),
'notifications' => $di->lazyNew('Ushahidi_Formatter_Notification'),
'webhooks' => $di->lazyNew('Ushahidi_Formatter_Webhook'),
'webhooks' => $di->lazyNew('Ushahidi_Formatter_Webhook'),
'apikeys' => $di->lazyNew('Ushahidi_Formatter_Apikey'),
'contacts' => $di->lazyNew('Ushahidi_Formatter_Contact'),
'csv' => $di->lazyNew('Ushahidi_Formatter_CSV'),
'roles' => $di->lazyNew('Ushahidi_Formatter_Role'),
Expand Down Expand Up @@ -368,6 +375,7 @@ public static function init()
'set_post',
'notification',
'webhook',
'apikey',
'contact',
'role',
'permission',
Expand Down Expand Up @@ -436,6 +444,7 @@ public static function init()
$di->set('repository.role', $di->lazyNew('Ushahidi_Repository_Role'));
$di->set('repository.notification', $di->lazyNew('Ushahidi_Repository_Notification'));
$di->set('repository.webhook', $di->lazyNew('Ushahidi_Repository_Webhook'));
$di->set('repository.apikey', $di->lazyNew('Ushahidi_Repository_ApiKey'));
$di->set('repository.csv', $di->lazyNew('Ushahidi_Repository_CSV'));
$di->set('repository.notification.queue', $di->lazyNew('Ushahidi_Repository_Notification_Queue'));
$di->set('repository.webhook.job', $di->lazyNew('Ushahidi_Repository_Webhook_Job'));
Expand Down
4 changes: 2 additions & 2 deletions application/classes/Ushahidi/DataProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,15 @@ public function send($to, $message, $title = "")
* @param string data_provider_message_id Message ID
* @return void
*/
public function receive($type, $from, $message, $to = NULL, $title = NULL, $data_provider_message_id = NULL, Array $additional_data = NULL)
public function receive($type, $from, $message, $to = NULL, $title = NULL, $date = NULL, $data_provider_message_id = NULL, Array $additional_data = NULL)
{
$data_provider = $this->provider_name();
$contact_type = $this->contact_type;

$usecase = service('factory.usecase')->get('messages', 'receive');
try
{
$usecase->setPayload(compact(['type', 'from', 'message', 'to', 'title', 'data_provider_message_id', 'data_provider', 'contact_type', 'additional_data']))
$usecase->setPayload(compact(['type', 'from', 'message', 'to', 'title', 'date', 'data_provider_message_id', 'data_provider', 'contact_type', 'additional_data']))
->interact();
}
catch (Ushahidi\Core\Exception\NotFoundException $e)
Expand Down
17 changes: 17 additions & 0 deletions application/classes/Ushahidi/Formatter/Apikey.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php defined('SYSPATH') OR die('No direct access allowed.');

/**
* Ushahidi API Formatter for Api Keys
*
* @author Ushahidi Team <team@ushahidi.com>
* @package Ushahidi\Application
* @copyright 2014 Ushahidi
* @license https://www.gnu.org/licenses/agpl-3.0.html GNU Affero General Public License Version 3 (AGPL3)
*/

use Ushahidi\Core\Traits\FormatterAuthorizerMetadata;

class Ushahidi_Formatter_Apikey extends Ushahidi_Formatter_API
{
use FormatterAuthorizerMetadata;
}
88 changes: 88 additions & 0 deletions application/classes/Ushahidi/Repository/ApiKey.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
<?php defined('SYSPATH') OR die('No direct access allowed.');

/**
* Ushahidi ApiKey Repository
*
* @author Ushahidi Team <team@ushahidi.com>
* @package Ushahidi\Application
* @copyright 2014 Ushahidi
* @license https://www.gnu.org/licenses/agpl-3.0.html GNU Affero General Public License Version 3 (AGPL3)
*/

use Ushahidi\Core\Entity;
use Ushahidi\Core\SearchData;
use Ushahidi\Core\Entity\ApiKey;
use Ushahidi\Core\Entity\ApiKeyRepository;
use Ushahidi\Core\Traits\AdminAccess;

use Ramsey\Uuid\Uuid;
use Ramsey\Uuid\Exception\UnsatisfiedDependencyException;

class Ushahidi_Repository_ApiKey extends Ushahidi_Repository implements ApiKeyRepository
{
use AdminAccess;

protected function getTable()
{
return 'apikeys';
}

public function getEntity(Array $data = null)
{
return new ApiKey($data);
}

// Ushahidi_Repository
public function setSearchConditions(SearchData $search)
{
$query = $this->search_query;

return $query;
}

// CreateRepository
public function create(Entity $entity)
{

$record = $entity->asArray();
try {
$uuid = Uuid::uuid4();
$record['api_key'] = $uuid->toString();
} catch (UnsatisfiedDependencyException $e) {
Kohana::$log->add(Log::ERROR, $e->getMessage());
}

$state = [
'created' => time(),
];

return $this->executeInsert($this->removeNullValues($record));
}

// UpdateRepository
public function update(Entity $entity)
{

$record = $entity->asArray();
$record['updated'] = time();
try {
$uuid = Uuid::uuid4();
$record['api_key'] = $uuid->toString();
} catch (UnsatisfiedDependencyException $e) {
Kohana::$log->add(Log::ERROR, $e->getMessage());
}

return $this->executeUpdate(['id' => $entity->id], $record);
}

public function apiKeyExists($api_key)
{
return (bool) $this->selectCount(compact('api_key'));
}

public function getSearchFields()
{
return [
];
}
}
Loading