Skip to content

Commit

Permalink
New options to add idp-level download statistics for federations
Browse files Browse the repository at this point in the history
  • Loading branch information
twoln committed Mar 4, 2024
1 parent 5843535 commit 81e2710
Show file tree
Hide file tree
Showing 4 changed files with 139 additions and 41 deletions.
16 changes: 15 additions & 1 deletion core/EntityWithDBProperties.php
Original file line number Diff line number Diff line change
Expand Up @@ -153,11 +153,15 @@ private function getRelevantIdentifier()
* are not considered.
*
* @param string $optionName optionally, the name of the attribute that is to be retrieved
* @param string$omittedOptionName optionally drop attibutes with that name
* @return array of arrays of attributes which were set for this IdP
*/
public function getAttributes(string $optionName = NULL)
public function getAttributes(string $optionName = NULL, string $omittedOptionName = NULL)
{
if ($optionName !== NULL) {
if ($optionName === $omittedOptionName) {
throw new Exception("The attibute to be shown has the same name as that to be omitted");
}
$returnarray = [];
foreach ($this->attributes as $theAttr) {
if ($theAttr['name'] == $optionName) {
Expand All @@ -166,9 +170,19 @@ public function getAttributes(string $optionName = NULL)
}
return $returnarray;
}
if ($omittedOptionName !== NULL) {
$returnarray = [];
foreach ($this->attributes as $theAttr) {
if ($theAttr['name'] !== $omittedOptionName) {
$returnarray[] = $theAttr;
}
}
return $returnarray;
}
return $this->attributes;
}


/**
* deletes all attributes in this profile except the _file ones, these are reported as array
*
Expand Down
61 changes: 44 additions & 17 deletions core/Federation.php
Original file line number Diff line number Diff line change
Expand Up @@ -68,35 +68,63 @@ class Federation extends EntityWithDBProperties
* @var string
*/
public $tld;

/**
* retrieve the statistics from the database in an internal array representation
*
* @param string $detail
* @return array
*/
private function downloadStatsCore()
private function downloadStatsCore($detail = '')
{
if ($detail !== 'ORGANISATIONS' && $detail !== 'PROFILES') {
$detail = '';
}
$grossAdmin = 0;
$grossUser = 0;
$grossSilverbullet = 0;
$dataArray = [];
// first, find out which profiles belong to this federation
$cohesionQuery = "SELECT downloads.device_id as dev_id, sum(downloads.downloads_user) as dl_user, sum(downloads.downloads_silverbullet) as dl_sb, sum(downloads.downloads_admin) as dl_admin FROM profile, institution, downloads WHERE profile.inst_id = institution.inst_id AND institution.country = ? AND profile.profile_id = downloads.profile_id group by device_id";
$profilesList = $this->databaseHandle->exec($cohesionQuery, "s", $this->tld);
if ($detail === 'ORGANISATIONS') {
$cohesionQuery = "SELECT profile.inst_id AS inst_id, downloads.device_id AS dev_id, sum(downloads.downloads_user) AS dl_user, sum(downloads.downloads_silverbullet) as dl_sb, sum(downloads.downloads_admin) AS dl_admin FROM downloads JOIN profile ON downloads.profile_id=profile.profile_id JOIN institution ON profile.inst_id=institution.inst_id WHERE institution.country = ? GROUP BY profile.inst_id, downloads.device_id";
} elseif ($detail === 'PROFILES') {
$cohesionQuery = "SELECT profile.inst_id AS inst_id, profile.profile_id AS profile_id, downloads.device_id AS dev_id, sum(downloads.downloads_user) AS dl_user, sum(downloads.downloads_silverbullet) as dl_sb, sum(downloads.downloads_admin) AS dl_admin FROM downloads JOIN profile ON downloads.profile_id=profile.profile_id JOIN institution ON profile.inst_id=institution.inst_id WHERE institution.country = ? GROUP BY profile.inst_id, profile.profile_id, downloads.device_id";
} else {
$cohesionQuery = "SELECT downloads.device_id as dev_id, sum(downloads.downloads_user) as dl_user, sum(downloads.downloads_silverbullet) AS dl_sb, sum(downloads.downloads_admin) as dl_admin FROM profile, institution, downloads WHERE profile.inst_id = institution.inst_id AND institution.country = ? AND profile.profile_id = downloads.profile_id group by device_id";
}
$downloadsList = $this->databaseHandle->exec($cohesionQuery, "s", $this->tld);
$deviceArray = \devices\Devices::listDevices();
// SELECT -> resource, no boolean
while ($queryResult = mysqli_fetch_object(/** @scrutinizer ignore-type */ $profilesList)) {
if (isset($deviceArray[$queryResult->dev_id])) {
$displayName = $deviceArray[$queryResult->dev_id]['display'];
} else { // this device has stats, but doesn't exist in current config. We don't even know its display name, so display its raw representation
$displayName = sprintf(_("(discontinued) %s"), $queryResult->dev_id);
while ($queryResult = mysqli_fetch_object(/** @scrutinizer ignore-type */ $downloadsList)) {
if ($detail === 'ORGANISATIONS' || $detail === 'PROFILES') {
$inst_id = $queryResult->inst_id;
if (isset($deviceArray[$queryResult->dev_id])) {
$displayName = $deviceArray[$queryResult->dev_id]['display'];
} else { // this device has stats, but doesn't exist in current config. We don't even know its display name, so display its raw representation
$displayName = sprintf(_("(discontinued) %s"), $queryResult->dev_id);
}
if (! isset($dataArray[$inst_id])) {
$dataArray[$inst_id] = [];
}
}
if ($detail === 'ORGANISATIONS') {
$dataArray[$inst_id][$displayName] = ["ADMIN" => $queryResult->dl_admin, "SILVERBULLET" => $queryResult->dl_sb, "USER" => $queryResult->dl_user];
} elseif ($detail === 'PROFILES') {
$profile_id = $queryResult->profile_id;
if (! isset($dataArray[$inst_id][$profile_id])) {
$dataArray[$inst_id][$profile_id] = [];
}
$dataArray[$inst_id][$profile_id][$displayName] = ["ADMIN" => $queryResult->dl_admin, "SILVERBULLET" => $queryResult->dl_sb, "USER" => $queryResult->dl_user];
}
if ($detail === '') {
$grossAdmin = $grossAdmin + $queryResult->dl_admin;
$grossSilverbullet = $grossSilverbullet + $queryResult->dl_sb;
$grossUser = $grossUser + $queryResult->dl_user;
}
$dataArray[$displayName] = ["ADMIN" => $queryResult->dl_admin, "SILVERBULLET" => $queryResult->dl_sb, "USER" => $queryResult->dl_user];
$grossAdmin = $grossAdmin + $queryResult->dl_admin;
$grossSilverbullet = $grossSilverbullet + $queryResult->dl_sb;
$grossUser = $grossUser + $queryResult->dl_user;
}
$dataArray["TOTAL"] = ["ADMIN" => $grossAdmin, "SILVERBULLET" => $grossSilverbullet, "USER" => $grossUser];
if ($detail === '') {
$dataArray["TOTAL"] = ["ADMIN" => $grossAdmin, "SILVERBULLET" => $grossSilverbullet, "USER" => $grossUser];
}
return $dataArray;
}

Expand All @@ -121,9 +149,9 @@ public function updateFreshness()
* @return string|array
* @throws Exception
*/
public function downloadStats($format)
public function downloadStats($format, $detail = '')
{
$data = $this->downloadStatsCore();
$data = $this->downloadStatsCore($detail);
$retstring = "";

switch ($format) {
Expand Down Expand Up @@ -153,7 +181,6 @@ public function downloadStats($format)
default:
throw new Exception("Statistics can be requested only in 'table' or 'XML' format!");
}

return $retstring;
}

Expand Down
36 changes: 30 additions & 6 deletions web/admin/API.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@
$adminApi->returnError(web\lib\admin\API::ERROR_API_DISABLED, "API is disabled in this instance of CAT");
exit(1);
}

$inputRaw = file_get_contents('php://input');

$inputDecoded = json_decode($inputRaw, TRUE);
if (!is_array($inputDecoded)) {
$adminApi->returnError(web\lib\admin\API::ERROR_MALFORMED_REQUEST, "Unable to decode JSON POST data." . json_last_error_msg() . $inputRaw);
Expand All @@ -61,14 +61,14 @@
exit(1);
}


// let's instantiate the fed, we will need it later
$fed = new \core\Federation($federation);
// it's a valid admin; what does he want to do?
if (!array_key_exists($inputDecoded['ACTION'], web\lib\admin\API::ACTIONS)) {
$adminApi->returnError(web\lib\admin\API::ERROR_NO_ACTION, "JSON request structure did not contain a valid ACTION");
exit(1);
}

// it's a valid ACTION, so let's sanitise the input parameters
$scrubbedParameters = $adminApi->scrub($inputDecoded, $fed);
$paramNames = [];
Expand Down Expand Up @@ -172,16 +172,30 @@
$adminApi->returnError(web\lib\admin\API::ERROR_INVALID_PARAMETER, "The admin with ID $toBeDeleted is not associated to IdP " . $idp->identifier);
break;
case web\lib\admin\API::ACTION_STATISTICS_FED:
$adminApi->returnSuccess($fed->downloadStats("array"));
$detail = $adminApi->firstParameterInstance($scrubbedParameters, web\lib\admin\API::AUXATTRIB_DETAIL);
$adminApi->returnSuccess($fed->downloadStats("array", $detail));
break;
case \web\lib\admin\API::ACTION_FEDERATION_LISTIDP:
$retArray = [];
$noLogo = null;
$idpIdentifier = $adminApi->firstParameterInstance($scrubbedParameters, web\lib\admin\API::AUXATTRIB_CAT_INST_ID);
$logoFlag = $adminApi->firstParameterInstance($scrubbedParameters, web\lib\admin\API::FLAG_NOLOGO);
$detail = $adminApi->firstParameterInstance($scrubbedParameters, web\lib\admin\API::AUXATTRIB_DETAIL);
$idpStatFlag = $adminApi->firstParameterInstance($scrubbedParameters, web\lib\admin\API::FLAG_ADD_STATS);
if ($logoFlag === "TRUE") {
$noLogo = 'general:logo_file';
}
if ($idpIdentifier === FALSE) {
$allIdPs = $fed->listIdentityProviders(0);
if ($idpStatFlag === "TRUE") {
$fedStats = $fed->downloadStats('array', $detail);
}
foreach ($allIdPs as $instanceId => $oneIdP) {
$theIdP = $oneIdP["instance"];
$retArray[$instanceId] = $theIdP->getAttributes();
$retArray[$instanceId] = $theIdP->getAttributes(null, $noLogo);
if ($idpStatFlag === "TRUE") {
$retArray[$instanceId]['STAT'] = $fedStats[$instanceId];
}
}
} else {
try {
Expand All @@ -190,9 +204,9 @@
$adminApi->returnError(web\lib\admin\API::ERROR_INVALID_PARAMETER, "IdP identifier does not exist!");
exit(1);
}
$retArray[$idpIdentifier] = $thisIdP->getAttributes();
$retArray[$idpIdentifier] = $thisIdP->getAttributes(null, $noLogo);
foreach ($thisIdP->listProfiles() as $oneProfile) {
$retArray[$idpIdentifier]["PROFILES"][$oneProfile->identifier] = $oneProfile->getAttributes();
$retArray[$idpIdentifier]["PROFILES"][$oneProfile->identifier] = $oneProfile->getAttributes(null, $noLogo);
}
}
foreach ($retArray as $instNumber => $oneInstData) {
Expand All @@ -213,6 +227,16 @@
}
}
}

/*
$retArray[$idpIdentifier] = [];
foreach ($thisIdP->listProfiles() as $oneProfile) {
$retArray[$idpIdentifier][$oneProfile->identifier] = $oneProfile->getUserDownloadStats();
}
*
*/

$adminApi->returnSuccess($retArray);
break;
case \web\lib\admin\API::ACTION_NEWPROF_RADIUS:
Expand Down
Loading

0 comments on commit 81e2710

Please sign in to comment.