Skip to content

Commit

Permalink
Merge pull request #178 from silinternational/feature/show-api-usage-…
Browse files Browse the repository at this point in the history
…by-key

Show API usage by Key
  • Loading branch information
forevermatt authored May 14, 2021
2 parents 4dc778c + 7a95414 commit 91dae3e
Show file tree
Hide file tree
Showing 9 changed files with 240 additions and 74 deletions.
138 changes: 70 additions & 68 deletions application/composer.lock

Large diffs are not rendered by default.

69 changes: 69 additions & 0 deletions application/direct-dependencies.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
{
"installed": [
{
"name": "forevermatt/calc-api-sig",
"version": "0.1.1",
"description": null
},
{
"name": "guzzlehttp/guzzle",
"version": "5.3.4",
"description": "Guzzle is a PHP HTTP client library and framework for building RESTful web service clients"
},
{
"name": "guzzlehttp/guzzle-services",
"version": "0.6.0",
"description": "Provides an implementation of the Guzzle Command library that uses Guzzle service descriptions to describe web services, serialize requests, and parse responses into easy to use model structures."
},
{
"name": "hybridauth/hybridauth",
"version": "3.7.1",
"description": "PHP Social Authentication Library"
},
{
"name": "phake/phake",
"version": "v3.1.9",
"description": "The Phake mock testing library"
},
{
"name": "phpunit/phpunit",
"version": "8.5.15",
"description": "The PHP Unit Testing framework."
},
{
"name": "roave/security-advisories",
"version": "dev-master 5ffdb87",
"description": "Prevents installation of composer packages with known security vulnerabilities: no API, simply require it"
},
{
"name": "silinternational/apiaxle-sdk-php",
"version": "1.0.3",
"description": "PHP client for ApiAxle APIs"
},
{
"name": "silinternational/php-env",
"version": "0.2.0",
"description": null
},
{
"name": "simplesamlphp/simplesamlphp",
"version": "v1.18.8",
"description": "A PHP implementation of a SAML 2.0 service provider and identity provider, also compatible with Shibboleth 1.3 and 2.0."
},
{
"name": "symfony/string",
"version": "v5.2.8",
"description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way"
},
{
"name": "symfony/translation-contracts",
"version": "v2.4.0",
"description": "Generic abstractions related to translation"
},
{
"name": "yiisoft/yii",
"version": "1.1.23",
"description": "Yii Web Programming Framework"
}
]
}
1 change: 1 addition & 0 deletions application/protected/components/Controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ final public function accessRules()
'inviteUser',
'pendingKeys',
'usage',
'usageByKey',
),
'roles' => array('owner'),
),
Expand Down
9 changes: 9 additions & 0 deletions application/protected/components/LinksManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,15 @@ public static function getApiDetailsActionLinksForUser($api, $user)
'signal'
);

$actionLinks[] = new ActionLink(
array(
'/api/usage-by-key/',
'code' => $api->code,
),
'See API Usage By Key',
'signal'
);

if ($api->approvedKeyCount > 0) {
$actionLinks[] = new ActionLink(sprintf(
'mailto:%s?subject=%s&bcc=%s',
Expand Down
28 changes: 28 additions & 0 deletions application/protected/controllers/ApiController.php
Original file line number Diff line number Diff line change
Expand Up @@ -1193,4 +1193,32 @@ public function actionUsage($code)
'summary' => $api->getUsageSummary()
));
}

public function actionUsageByKey($code)
{
// Get the current user's model.
/* @var $currentUser User */
$currentUser = \Yii::app()->user->user;

// Get the API by the code name.
/* @var $api Api */
$api = Api::model()->findByAttributes(['code' => $code]);

// If that is NOT an Api that the User has permission to manage, say so.
if ( ! $currentUser->hasAdminPrivilegesForApi($api)) {
throw new \CHttpException(
403,
'That is not an API that you have permission to manage.'
);
}

$interval = \UsageStats::INTERVAL_DAY;
$usageStats = $api->getUsageStatsForKeys($interval);

// Show the page.
$this->render('usage-by-key', array(
'api' => $api,
'usageStats' => $usageStats,
));
}
}
40 changes: 35 additions & 5 deletions application/protected/models/Api.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,6 @@
namespace Sil\DevPortal\models;

use Sil\DevPortal\components\ApiAxle\Client as ApiAxleClient;
use Sil\DevPortal\models\ApiVisibilityDomain;
use Sil\DevPortal\models\ApiVisibilityUser;
use Sil\DevPortal\models\Event;
use Sil\DevPortal\models\Key;
use Sil\DevPortal\models\User;

/**
* The followings are the available model relations (defined in the parent
Expand Down Expand Up @@ -573,6 +568,41 @@ public function getUsage(
// Return the resulting data.
return $usage;
}

/**
* Get the usage stats for the approved Keys to this Api.
*
* @param string $interval The name of the time interval (e.g. -
* 'second', 'minute', 'hour', 'day') by which the data should be
* grouped.
* @param int $rewindBy (Optional:) How many intervals to "back up"
* the starting point by. Used for getting older data.
* @return \UsageStats
*/
public function getUsageStatsForKeys(string $interval, $rewindBy = 0): \UsageStats
{
// Get all of this Api's Keys.
$keys = Key::model()->with('user')->findAllByAttributes([
'status' => Key::STATUS_APPROVED,
'api_id' => $this->api_id,
], [
'order' => 'user.display_name',
]);

// Get the keys' usage.
$usageStats = new \UsageStats($interval, $rewindBy);
foreach ($keys as $key) {
try {
$usage = $key->getUsage($interval, true, $rewindBy);
} catch (\Exception $e) {
$usage = $e->getMessage();
}
$usageStats->addEntry($key->user->display_name, $usage);
}

// Return the resulting usage stats.
return $usageStats;
}

/**
* Get a summary of this Api's usage (by month).
Expand Down
3 changes: 3 additions & 0 deletions application/protected/tests/unit/LinksManagerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ public function testGetApiDetailsActionLinksForUser_adminUser_apiWithKeys()
'Show Active Keys',
'Show Pending Keys',
'See API Usage',
'See API Usage By Key',
'Email Users With Keys',
'Edit API',
'Delete API',
Expand Down Expand Up @@ -152,6 +153,7 @@ public function testGetApiDetailsActionLinksForUser_adminUser_apiWithoutKeys()
'Show Active Keys',
'Show Pending Keys',
'See API Usage',
'See API Usage By Key',
'Edit API',
'Delete API',
);
Expand Down Expand Up @@ -185,6 +187,7 @@ public function testGetApiDetailsActionLinksForUser_ownerOfApi()
'Show Active Keys',
'Show Pending Keys',
'See API Usage',
'See API Usage By Key',
'Email Users With Keys',
'Edit API',
'Delete API',
Expand Down
24 changes: 24 additions & 0 deletions application/protected/views/api/usage-by-key.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php
/* @var $this \Sil\DevPortal\controllers\ApiController */
/* @var $api \Sil\DevPortal\models\Api */
/* @var $usageStats UsageStats */

// Set up the breadcrumbs.
$this->breadcrumbs += array(
'APIs' => array('/api/'),
$api->display_name => array('/api/details/', 'code' => $api->code),
'API Usage By Key',
);

$this->pageTitle = 'API Usage By Key';

?>
<dl class="dl-horizontal">
<dt><?php echo CHtml::encode($api->code); ?></dt>
<dd><?php echo CHtml::encode($api->display_name); ?></dd>
</dl>
<div class="row">
<div class="span12">
<?= $usageStats->generateChartHtml(); ?>
</div>
</div>
2 changes: 1 addition & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ services:
volumes_from:
- data
working_dir: /data
command: composer update --no-scripts
command: bash -c "composer update --no-scripts; composer show --direct --format=json > direct-dependencies.json"

yiimigrate:
image: developer-portal-local
Expand Down

0 comments on commit 91dae3e

Please sign in to comment.