feat(cloudron): add tirreno package artifacts

- Add CloudronStack/output/CloudronPackages-Artifacts/tirreno/ directory and its contents
- Includes package manifest, Dockerfile, source code, documentation, and build artifacts
- Add tirreno-1761840148.tar.gz as a build artifact
- Add tirreno-cloudron-package-1761841304.tar.gz as the Cloudron package
- Include all necessary files for the tirreno Cloudron package

This adds the complete tirreno Cloudron package artifacts to the repository.
This commit is contained in:
2025-10-30 11:43:06 -05:00
parent 0ce353ea9d
commit 91d52d2de5
1692 changed files with 202851 additions and 0 deletions

View File

@@ -0,0 +1,309 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\Api;
class Data extends \Controllers\Base {
use \Traits\ApiKeys;
protected $ENRICHED_ATTRIBUTES = [];
public function __construct() {
parent::__construct();
$this->ENRICHED_ATTRIBUTES = array_keys(\Utils\Constants::get('ENRICHING_ATTRIBUTES'));
}
public function proceedPostRequest(array $params): array {
$cmd = $params['cmd'] ?? '';
return match ($cmd) {
'resetKey' => $this->resetApiKey($params),
'updateApiUsage' => $this->updateApiUsage($params),
'enrichAll' => $this->enrichAll($params),
default => []
};
}
public function getUsageStats(int $operatorId): array {
$model = new \Models\ApiKeys();
$apiKeys = $model->getKeys($operatorId);
$isOwner = true;
if (!$apiKeys) {
$coOwnerModel = new \Models\ApiKeyCoOwner();
$coOwnerModel->getCoOwnership($operatorId);
if ($coOwnerModel->loaded()) {
$isOwner = false;
$apiKeys[] = $model->getKeyById($coOwnerModel->api);
}
}
if (!$isOwner) {
return ['data' => []];
}
$resultKeys = [];
foreach ($apiKeys as $key) {
$subscriptionStats = [];
if ($key->token !== null) {
[$code, $response, $error] = $this->getSubscriptionStats($key->token);
$subscriptionStats = strlen($error) > 0 || $code > 201 ? [] : $response;
}
$remaining = $subscriptionStats['remaining'] ?? null;
$total = $subscriptionStats['total'] ?? null;
$used = $remaining !== null && $total !== null ? $total - $remaining : null;
$resultKeys[] = [
'id' => $key->id,
'key' => $key->key,
'apiToken' => $key->token ?? null,
'sub_status' => $subscriptionStats['status'] ?? null,
'sub_calls_left' => $remaining,
'sub_calls_used' => $used,
'sub_calls_limit' => $total,
'sub_next_billed' => $subscriptionStats['next_billed_at'] ?? null,
'sub_update_url' => $subscriptionStats['update_url'] ?? null,
'sub_plan_id' => $subscriptionStats['current_subscription_plan']['sub_id'] ?? null,
'sub_plan_api_calls' => $subscriptionStats['current_subscription_plan']['api_calls'] ?? null,
//'all_subscription_plans' => $subscriptionStats['all_subscription_plans'] ?? null,
];
}
return ['data' => $resultKeys];
}
public function getOperatorApiKeysDetails(int $operatorId): array {
[$isOwner, $apiKeys] = $this->getOperatorApiKeys($operatorId);
$resultKeys = [];
foreach ($apiKeys as $key) {
$resultKeys[] = [
'id' => $key->id,
'key' => $key->key,
'created_at' => $key->created_at,
'skip_enriching_attributes' => $key->skip_enriching_attributes,
'enrichedAttributes' => $this->getEnrichedAttributes($key),
'retention_policy' => $key->retention_policy,
'skip_blacklist_sync' => $key->skip_blacklist_sync,
'apiToken' => $key->token ?? null,
];
}
return [$isOwner, $resultKeys];
}
private function getSubscriptionStats(string $token): array {
$api = \Utils\Variables::getEnrichtmentApi();
$options = [
'method' => 'GET',
'header' => [
'Authorization: Bearer ' . $token,
'User-Agent: ' . $this->f3->get('USER_AGENT'),
],
];
/** @var array{request: array<string>, body: string, headers: array<string>, engine: string, cached: bool, error: string} $result */
$result = \Web::instance()->request(
url: sprintf('%s/usage-stats', $api),
options: $options,
);
$matches = [];
preg_match('/^HTTP\/(\d+)(?:\.\d)? (\d{3})/', $result['headers'][0], $matches);
$statusCode = (int) ($matches[2] ?? 0);
$errorMessage = $result['error'];
$jsonResponse = json_decode($result['body'], true);
return [$statusCode, $jsonResponse, $errorMessage];
}
public function resetApiKey(array $params): array {
$pageParams = [];
$errorCode = $this->validateResetApiKey($params);
if ($errorCode) {
$pageParams['ERROR_CODE'] = $errorCode;
} else {
$keyId = isset($params['keyId']) ? (int) $params['keyId'] : null;
$model = new \Models\ApiKeys();
$model->getKeyById($keyId);
$model->resetKey($keyId, $model->creator);
$pageParams['SUCCESS_MESSAGE'] = $this->f3->get('AdminApi_reset_success_message');
}
return $pageParams;
}
public function enrichAll(array $data): array {
$pageParams = [];
$errorCode = $this->validateEnrichAll($data);
if ($errorCode) {
$pageParams['ERROR_CODE'] = $errorCode;
} else {
$apiKey = $this->getCurrentOperatorApiKeyId();
$model = new \Models\Users();
$accountsForEnrichment = $model->notCheckedUsers($apiKey);
$actionType = new \Type\QueueAccountOperationActionType(\Type\QueueAccountOperationActionType::ENRICHMENT);
$accountOpQueueModel = new \Models\Queue\AccountOperationQueue($actionType);
$accountOpQueueModel->addBatchIds($accountsForEnrichment, $apiKey);
$pageParams['SUCCESS_MESSAGE'] = $this->f3->get('AdminApi_manual_enrichment_success_message');
}
return $pageParams;
}
public function validateEnrichAll(array $params): int|false {
$errorCode = \Utils\Access::CSRFTokenValid($params, $this->f3);
if ($errorCode) {
return $errorCode;
}
return false;
}
public function validateResetApiKey(array $params): int|false {
$errorCode = \Utils\Access::CSRFTokenValid($params, $this->f3);
if ($errorCode) {
return $errorCode;
}
$keyId = isset($params['keyId']) ? (int) $params['keyId'] : null;
if (!$keyId) {
return \Utils\ErrorCodes::API_KEY_ID_DOESNT_EXIST;
}
if ($keyId !== $this->getCurrentOperatorApiKeyId()) {
return \Utils\ErrorCodes::API_KEY_WAS_CREATED_FOR_ANOTHER_USER;
}
return false;
}
private function validateApiKeyAccess(int $keyId, int $operatorId): bool {
$model = new \Models\ApiKeys();
$model->getByKeyAndOperatorId($keyId, $operatorId);
if (!$model->loaded()) {
$coOwnerModel = new \Models\ApiKeyCoOwner();
$coOwnerModel->getCoOwnership($operatorId);
if (!$coOwnerModel->loaded()) {
return false;
}
}
return true;
}
public function getEnrichedAttributes(\Models\ApiKeys $key): array {
$enrichedAttributes = [];
$skipAttributes = \json_decode($key->skip_enriching_attributes);
foreach ($this->ENRICHED_ATTRIBUTES as $attribute) {
$enrichedAttributes[$attribute] = !\in_array($attribute, $skipAttributes);
}
return $enrichedAttributes;
}
public function updateApiUsage(array $params): array {
$errorCode = $this->validateUpdateApiUsage($params);
$pageParams = [];
if ($errorCode) {
$pageParams['ERROR_CODE'] = $errorCode;
} else {
$keyId = isset($params['keyId']) ? (int) $params['keyId'] : null;
$model = new \Models\ApiKeys();
$model->getKeyById($keyId);
if ($params['apiToken'] !== null) {
$apiToken = trim($params['apiToken']);
[$code, , $error] = $this->getSubscriptionStats($apiToken);
if (strlen($error) > 0 || $code > 201) {
$pageParams['ERROR_CODE'] = \Utils\ErrorCodes::SUBSCRIPTION_KEY_INVALID_UPDATE;
return $pageParams;
}
$model->updateInternalToken($apiToken);
}
$enrichedAttributes = $params['enrichedAttributes'] ?? [];
$skipEnrichingAttributes = \array_diff($this->ENRICHED_ATTRIBUTES, \array_keys($enrichedAttributes));
$model->updateSkipEnrichingAttributes($skipEnrichingAttributes);
$skipBlacklistSync = !isset($params['exchangeBlacklist']);
$model->updateSkipBlacklistSynchronisation($skipBlacklistSync);
$pageParams['SUCCESS_MESSAGE'] = $this->f3->get('AdminApi_data_enrichment_success_message');
}
return $pageParams;
}
public function validateUpdateApiUsage(array $params): int|false {
$errorCode = \Utils\Access::CSRFTokenValid($params, $this->f3);
if ($errorCode) {
return $errorCode;
}
$keyId = isset($params['keyId']) ? (int) $params['keyId'] : null;
if (!$keyId) {
return \Utils\ErrorCodes::API_KEY_ID_DOESNT_EXIST;
}
$currentOperator = $this->f3->get('CURRENT_USER');
$operatorId = $currentOperator->id;
if (!$this->validateApiKeyAccess($keyId, $operatorId)) {
return \Utils\ErrorCodes::API_KEY_WAS_CREATED_FOR_ANOTHER_USER;
}
$enrichedAttributes = $params['enrichedAttributes'] ?? [];
$unknownAttributes = \array_diff(\array_keys($enrichedAttributes), $this->ENRICHED_ATTRIBUTES);
if ($unknownAttributes) {
return \Utils\ErrorCodes::UNKNOWN_ENRICHMENT_ATTRIBUTES;
}
return false;
}
public function getNotCheckedEntitiesForLoggedUser(): bool {
$apiKey = $this->getCurrentOperatorApiKeyId();
$controller = new \Controllers\Admin\Enrichment\Data();
return $controller->getNotCheckedExists($apiKey);
}
public function getScheduledForEnrichment(): bool {
$apiKey = $this->getCurrentOperatorApiKeyId();
$actionType = new \Type\QueueAccountOperationActionType(\Type\QueueAccountOperationActionType::ENRICHMENT);
$accountOpQueueModel = new \Models\Queue\AccountOperationQueue($actionType);
// do not use isInQueue() to prevent true on failed state
return $accountOpQueueModel->actionIsInQueueProcessing($apiKey);
}
}

View File

@@ -0,0 +1,36 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\Api;
class Navigation extends \Controllers\Base {
use \Traits\ApiKeys;
use \Traits\Navigation;
public function showIndexPage(): void {
$this->redirectIfUnlogged();
$pageController = new Page();
$this->response = new \Views\Frontend();
$this->response->data = $pageController->getPageParams();
}
public function getUsageStats(): array {
$currentOperator = $this->f3->get('CURRENT_USER');
$operatorId = $currentOperator->id;
return $operatorId ? (new Data())->getUsageStats($operatorId) : [];
}
}

View File

@@ -0,0 +1,59 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\Api;
class Page extends \Controllers\Pages\Base {
use \Traits\ApiKeys;
public $page = 'AdminApi';
public function getPageParams(): array {
$dataController = new Data();
$currentOperator = $this->f3->get('CURRENT_USER');
$operatorId = $currentOperator->id;
$scheduledForEnrichment = $dataController->getScheduledForEnrichment();
$pageParams = [
'LOAD_AUTOCOMPLETE' => true,
'LOAD_DATATABLE' => true,
'HTML_FILE' => 'admin/api.html',
'JS' => 'admin_api.js',
'API_URL' => \Utils\Variables::getSiteWithProtocol() . '/sensor/',
'SCHEDULED_FOR_ENRICHMENT' => $scheduledForEnrichment,
];
if ($this->isPostRequest()) {
$params = $this->f3->get('POST');
$params['id'] = $operatorId;
$operationResponse = $dataController->proceedPostRequest($params);
$pageParams = array_merge($pageParams, $operationResponse);
$pageParams['CMD'] = $params['cmd'] ?? null;
}
// set these params after proccessing POST request
[$isOwner, $apiKeys] = $dataController->getOperatorApiKeysDetails($operatorId);
$pageParams['IS_OWNER'] = $isOwner;
$pageParams['API_KEYS'] = $apiKeys;
$pageParams['NOT_CHECKED'] = $dataController->getNotCheckedEntitiesForLoggedUser();
return parent::applyPageParams($pageParams);
}
}

View File

@@ -0,0 +1,40 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\Blacklist;
class Data extends \Controllers\Base {
public function getList(int $apiKey): array {
$model = new \Models\Grid\Blacklist\Grid($apiKey);
return $model->getAllBlacklistedItems();
}
public function removeItemFromBlacklist(int $itemId, string $type, int $apiKey): void {
$model = null;
if ($type === 'ip') {
$model = new \Models\Ip();
}
if ($type === 'email') {
$model = new \Models\Email();
}
if ($type === 'phone') {
$model = new \Models\Phone();
}
$model->updateFraudFlag([$itemId], false, $apiKey);
}
}

View File

@@ -0,0 +1,51 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\Blacklist;
class Navigation extends \Controllers\Base {
use \Traits\ApiKeys;
use \Traits\Navigation;
public function showIndexPage(): void {
$this->redirectIfUnlogged();
$pageController = new Page();
$this->response = new \Views\Frontend();
$this->response->data = $pageController->getPageParams();
}
public function getList(): array {
$apiKey = $this->getCurrentOperatorApiKeyId();
return $apiKey ? (new Data())->getList($apiKey) : [];
}
public function removeItemFromList(): array {
$dataController = new Data();
$apiKey = $this->getCurrentOperatorApiKeyId();
$id = $this->f3->get('REQUEST.id');
$type = $this->f3->get('REQUEST.type');
$dataController->removeItemFromBlacklist($id, $type, $apiKey);
$successCode = \Utils\ErrorCodes::ITEM_HAS_BEEN_SUCCESSFULLY_REMOVED_FROM_BLACK_LIST;
return [
'success' => $successCode,
'id' => $id,
];
}
}

View File

@@ -0,0 +1,37 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\Blacklist;
class Page extends \Controllers\Pages\Base {
public $page = 'AdminBlacklist';
public function getPageParams(): array {
$searchPlacholder = $this->f3->get('AdminBlacklist_search_placeholder');
$pageParams = [
'SEARCH_PLACEHOLDER' => $searchPlacholder,
'LOAD_UPLOT' => true,
'LOAD_DATATABLE' => true,
'LOAD_CHOICES' => true,
'LOAD_AUTOCOMPLETE' => true,
'HTML_FILE' => 'admin/blacklist.html',
'JS' => 'admin_blacklist.js',
'ENTITY_TYPES' => \Utils\Constants::get('ENTITY_TYPES'),
];
return parent::applyPageParams($pageParams);
}
}

View File

@@ -0,0 +1,59 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\Bot;
class Data extends \Controllers\Base {
use \Traits\ApiKeys;
public function proceedPostRequest(array $params): array {
return match ($params['cmd']) {
'reenrichment' => $this->enrichEntity($params),
default => []
};
}
public function enrichEntity(array $params): array {
$dataController = new \Controllers\Admin\Enrichment\Data();
$apiKey = $this->getCurrentOperatorApiKeyId();
$enrichmentKey = $this->getCurrentOperatorEnrichmentKeyString();
$type = $params['type'];
$search = $params['search'] ?? null;
$entityId = isset($params['entityId']) ? (int) $params['entityId'] : null;
return $dataController->enrichEntity($type, $search, $entityId, $apiKey, $enrichmentKey);
}
public function checkIfOperatorHasAccess(int $botId): bool {
$apiKey = $this->getCurrentOperatorApiKeyId();
$model = new \Models\Bot();
return $model->checkAccess($botId, $apiKey);
}
public function getBotDetails(int $botId): array {
$apiKey = $this->getCurrentOperatorApiKeyId();
$model = new \Models\Bot();
return $model->getFullBotInfoById($botId, $apiKey);
}
public function isEnrichable(): bool {
$apiKey = $this->getCurrentOperatorApiKeyId();
$model = new \Models\ApiKeys();
return $model->attributeIsEnrichable('ua', $apiKey);
}
}

View File

@@ -0,0 +1,40 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\Bot;
class Navigation extends \Controllers\Base {
use \Traits\ApiKeys;
use \Traits\Navigation;
public function showIndexPage(): void {
$this->redirectIfUnlogged();
$pageController = new Page();
$this->response = new \Views\Frontend();
$this->response->data = $pageController->getPageParams();
}
public function getBotDetails(): array {
$dataController = new Data();
$botId = $this->f3->get('REQUEST.botId');
$hasAccess = $dataController->checkIfOperatorHasAccess($botId);
if (!$hasAccess) {
$this->f3->error(404);
}
return $dataController->getBotDetails($botId);
}
}

View File

@@ -0,0 +1,59 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\Bot;
class Page extends \Controllers\Pages\Base {
public $page = 'AdminBot';
public function getPageParams(): array {
$dataController = new Data();
$botId = $this->integerParam($this->f3->get('PARAMS.botId'));
$hasAccess = $dataController->checkIfOperatorHasAccess($botId);
if (!$hasAccess) {
$this->f3->error(404);
}
$bot = $dataController->getBotDetails($botId);
$pageTitle = $this->getInternalPageTitleWithPostfix($bot['id']);
$isEnrichable = $dataController->isEnrichable();
$pageParams = [
'LOAD_DATATABLE' => true,
'LOAD_JVECTORMAP' => true,
'LOAD_ACCEPT_LANGUAGE_PARSER' => true,
'LOAD_AUTOCOMPLETE' => true,
'HTML_FILE' => 'admin/bot.html',
'BOT' => $bot,
'PAGE_TITLE' => $pageTitle,
'LOAD_UPLOT' => true,
'JS' => 'admin_bot.js',
'IS_ENRICHABLE' => $isEnrichable,
];
if ($this->isPostRequest()) {
$params = $this->f3->get('POST');
$operationResponse = $dataController->proceedPostRequest($params);
$pageParams = array_merge($pageParams, $operationResponse);
$pageParams['CMD'] = $params['cmd'];
// recall bot data
$pageParams['BOT'] = $dataController->getBotDetails($botId);
}
return parent::applyPageParams($pageParams);
}
}

View File

@@ -0,0 +1,24 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\Bots;
class Data extends \Controllers\Base {
public function getList(int $apiKey): array {
$model = new \Models\Grid\Bots\Grid($apiKey);
return $model->getAllBots();
}
}

View File

@@ -0,0 +1,35 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\Bots;
class Navigation extends \Controllers\Base {
use \Traits\ApiKeys;
use \Traits\Navigation;
public function showIndexPage(): void {
$this->redirectIfUnlogged();
$pageController = new Page();
$this->response = new \Views\Frontend();
$this->response->data = $pageController->getPageParams();
}
public function getList(): array {
$apiKey = $this->getCurrentOperatorApiKeyId();
return $apiKey ? (new Data())->getList($apiKey) : [];
}
}

View File

@@ -0,0 +1,36 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\Bots;
class Page extends \Controllers\Pages\Base {
public $page = 'AdminBots';
public function getPageParams(): array {
$searchPlacholder = $this->f3->get('AdminBots_search_placeholder');
$pageParams = [
'SEARCH_PLACEHOLDER' => $searchPlacholder,
'LOAD_UPLOT' => true,
'LOAD_DATATABLE' => true,
'LOAD_ACCEPT_LANGUAGE_PARSER' => true,
'LOAD_AUTOCOMPLETE' => true,
'HTML_FILE' => 'admin/bots.html',
'JS' => 'admin_bots.js',
];
return parent::applyPageParams($pageParams);
}
}

View File

@@ -0,0 +1,39 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\Context;
class Data extends \Controllers\Base {
private \Models\Context\Data $model;
public function __construct() {
$this->model = new \Models\Context\Data();
}
public function getContextByAccountIds(array $accountIds, int $apiKey): array {
return $this->getContext($accountIds, $apiKey);
}
public function getContextByAccountId(int $accountId, int $apiKey): array {
$accountIds = [$accountId];
$context = $this->getContext($accountIds, $apiKey);
return $context[$accountId] ?? [];
}
private function getContext(array $accountIds, int $apiKey): array {
return $this->model->getContext($accountIds, $apiKey);
}
}

View File

@@ -0,0 +1,79 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\Countries;
class Data extends \Controllers\Base {
public function getList(int $apiKey): array {
$result = [];
$model = new \Models\Grid\Countries\Grid($apiKey);
$result = $model->getAllCountries();
$ids = array_column($result['data'], 'id');
if ($ids) {
$model = new \Models\Country();
$model->updateTotalsByEntityIds($ids, $apiKey);
$result['data'] = $model->refreshTotals($result['data'], $apiKey);
}
return $result;
}
public function getMap(int $apiKey): array {
$result = [];
$model = new \Models\Map();
$ispId = $this->f3->get('REQUEST.ispId');
$userId = $this->f3->get('REQUEST.userId');
$botId = $this->f3->get('REQUEST.botId');
$domainId = $this->f3->get('REQUEST.domainId');
$resourceId = $this->f3->get('REQUEST.resourceId');
if (isset($userId) && is_numeric($userId)) {
$result = $model->getCountriesByUserId($userId, $apiKey);
}
if (isset($ispId) && is_numeric($ispId)) {
$result = $model->getCountriesByIspId($ispId, $apiKey);
}
if (isset($domainId) && is_numeric($domainId)) {
$result = $model->getCountriesByDomainId($domainId, $apiKey);
}
if (isset($botId) && is_numeric($botId)) {
$result = $model->getCountriesByBotId($botId, $apiKey);
}
if (isset($resourceId) && is_numeric($resourceId)) {
$result = $model->getCountriesByResourceId($resourceId, $apiKey);
}
if (!$result) {
$dateFrom = $this->f3->get('REQUEST.dateFrom');
$dateTo = $this->f3->get('REQUEST.dateTo');
$dateFrom = ($dateFrom) ? date('Y-m-d H:i:s', strtotime($dateFrom)) : null;
$dateTo = ($dateTo) ? date('Y-m-d H:i:s', strtotime($dateTo)) : null;
$result = $model->getAllCountries($dateFrom, $dateTo, $apiKey);
}
return $result;
}
}

View File

@@ -0,0 +1,41 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\Countries;
class Navigation extends \Controllers\Base {
use \Traits\ApiKeys;
use \Traits\Navigation;
public function showIndexPage(): void {
$this->redirectIfUnlogged();
$pageController = new Page();
$this->response = new \Views\Frontend();
$this->response->data = $pageController->getPageParams();
}
public function getList(): array {
$apiKey = $this->getCurrentOperatorApiKeyId();
return $apiKey ? (new Data())->getList($apiKey) : [];
}
public function getMap(): array {
$apiKey = $this->getCurrentOperatorApiKeyId();
return $apiKey ? (new Data())->getMap($apiKey) : [];
}
}

View File

@@ -0,0 +1,35 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\Countries;
class Page extends \Controllers\Pages\Base {
public $page = 'AdminCountries';
public function getPageParams(): array {
$searchPlacholder = $this->f3->get('AdminCountries_search_placeholder');
$pageParams = [
'SEARCH_PLACEHOLDER' => $searchPlacholder,
'LOAD_JVECTORMAP' => true,
'LOAD_DATATABLE' => true,
'LOAD_AUTOCOMPLETE' => true,
'HTML_FILE' => 'admin/countries.html',
'JS' => 'admin_countries.js',
];
return parent::applyPageParams($pageParams);
}
}

View File

@@ -0,0 +1,34 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\Country;
class Data extends \Controllers\Base {
use \Traits\ApiKeys;
public function checkIfOperatorHasAccess(int $countryId): bool {
$apiKey = $this->getCurrentOperatorApiKeyId();
$model = new \Models\Country();
return $model->checkAccess($countryId, $apiKey);
}
public function getCountryById(int $countryId): array {
$apiKey = $this->getCurrentOperatorApiKeyId();
$model = new \Models\Country();
return $model->getCountryById($countryId, $apiKey);
}
}

View File

@@ -0,0 +1,29 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\Country;
class Navigation extends \Controllers\Base {
use \Traits\ApiKeys;
use \Traits\Navigation;
public function showIndexPage(): void {
$this->redirectIfUnlogged();
$pageController = new Page();
$this->response = new \Views\Frontend();
$this->response->data = $pageController->getPageParams();
}
}

View File

@@ -0,0 +1,49 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\Country;
class Page extends \Controllers\Pages\Base {
use \Traits\ApiKeys;
public $page = 'AdminCountry';
public function getPageParams(): array {
$dataController = new Data();
$countryId = $this->integerParam($this->f3->get('PARAMS.countryId'));
$hasAccess = $dataController->checkIfOperatorHasAccess($countryId);
if (!$hasAccess) {
$this->f3->error(404);
}
$country = $dataController->getCountryById($countryId);
$pageTitle = $this->getInternalPageTitleWithPostfix($country['value']);
$pageParams = [
'LOAD_DATATABLE' => true,
'LOAD_UPLOT' => true,
'LOAD_AUTOCOMPLETE' => true,
'LOAD_ACCEPT_LANGUAGE_PARSER' => true,
'HTML_FILE' => 'admin/country.html',
'COUNTRY' => $country,
'PAGE_TITLE' => $pageTitle,
'JS' => 'admin_country.js',
];
return parent::applyPageParams($pageParams);
}
}

View File

@@ -0,0 +1,272 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\Data;
class Data extends \Controllers\Base {
// POST requests
public function enrichEntity(): array {
$controller = new \Controllers\Admin\Enrichment\Navigation();
return $controller->enrichEntity();
}
public function saveRule(): array {
$controller = new \Controllers\Admin\Rules\Navigation();
return $controller->saveRule();
}
public function removeFromBlacklist(): array {
$controller = new \Controllers\Admin\Blacklist\Navigation();
return $controller->removeItemFromList();
}
public function removeFromWatchlist(): array {
$controller = new \Controllers\Admin\Watchlist\Navigation();
return $controller->removeUserFromList();
}
public function manageUser(): array {
$controller = new \Controllers\Admin\User\Navigation();
return $controller->manageUser();
}
// GET requests
public function checkRule(): array {
$controller = new \Controllers\Admin\Rules\Navigation();
return $controller->checkRule();
}
public function getTimeFrameTotal(): array {
$controller = new \Controllers\Admin\Totals\Navigation();
return $controller->getTimeFrameTotal();
}
public function getCountries(): array {
$controller = new \Controllers\Admin\Countries\Navigation();
return $controller->getList();
}
public function getMap(): array {
$controller = new \Controllers\Admin\Countries\Navigation();
return $controller->getMap();
}
public function getIps(): array {
$controller = new \Controllers\Admin\IPs\Navigation();
return $controller->getList();
}
public function getEvents(): array {
$controller = new \Controllers\Admin\Events\Navigation();
return $controller->getList();
}
public function getLogbook(): array {
$controller = new \Controllers\Admin\Logbook\Navigation();
return $controller->getList();
}
public function getUsers(): array {
$controller = new \Controllers\Admin\Users\Navigation();
return $controller->getList();
}
public function getBots(): array {
$controller = new \Controllers\Admin\Bots\Navigation();
return $controller->getList();
}
public function getDevices(): array {
$controller = new \Controllers\Admin\Devices\Navigation();
return $controller->getList();
}
public function getResources(): array {
$controller = new \Controllers\Admin\Resources\Navigation();
return $controller->getList();
}
public function getDashboardStat(): array {
$controller = new \Controllers\Admin\Home\Navigation();
return $controller->getDashboardStat();
}
public function getTopTen(): array {
$controller = new \Controllers\Admin\Home\Navigation();
return $controller->getTopTen();
}
public function getChart(): array {
$controller = new \Controllers\Admin\Home\Navigation();
return $controller->getChart();
}
public function getEventDetails(): array {
$controller = new \Controllers\Admin\Events\Navigation();
return $controller->getEventDetails();
}
public function getLogbookDetails(): array {
$controller = new \Controllers\Admin\Logbook\Navigation();
return $controller->getLogbookDetails();
}
public function getEmailDetails(): array {
$controller = new \Controllers\Admin\Emails\Navigation();
return $controller->getEmailDetails();
}
public function getPhoneDetails(): array {
$controller = new \Controllers\Admin\Phones\Navigation();
return $controller->getPhoneDetails();
}
public function getUserDetails(): array {
$controller = new \Controllers\Admin\UserDetails\Navigation();
return $controller->getUserDetails();
}
public function getUserEnrichmentDetails(): array {
$controller = new \Controllers\Admin\UserDetails\Navigation();
return $controller->getUserEnrichmentDetails();
}
public function getNotCheckedEntitiesCount(): array {
$controller = new \Controllers\Admin\Enrichment\Navigation();
return $controller->getNotCheckedEntitiesCount();
}
public function getEmails(): array {
$controller = new \Controllers\Admin\Emails\Navigation();
return $controller->getList();
}
public function getPhones(): array {
$controller = new \Controllers\Admin\Phones\Navigation();
return $controller->getList();
}
public function getFieldAuditTrail(): array {
$controller = new \Controllers\Admin\Payloads\FieldAuditTrail\Navigation();
return $controller->getList();
}
public function getUserScoreDetails(): array {
$controller = new \Controllers\Admin\User\Navigation();
return $controller->getUserScoreDetails();
}
public function getIsps(): array {
$controller = new \Controllers\Admin\ISPs\Navigation();
return $controller->getList();
}
public function getDomains(): array {
$controller = new \Controllers\Admin\Domains\Navigation();
return $controller->getList();
}
public function getReviewUsersQueue(): array {
$controller = new \Controllers\Admin\ReviewQueue\Navigation();
return $controller->getList();
}
public function getReviewUsersQueueCount(): array {
$controller = new \Controllers\Admin\ReviewQueue\Navigation();
return $controller->getNumberOfNotReviewedUsers(false, true); // do not use cache, overall count
}
public function getIspDetails(): array {
$controller = new \Controllers\Admin\ISP\Navigation();
return $controller->getIspDetails();
}
public function getIpDetails(): array {
$controller = new \Controllers\Admin\IP\Navigation();
return $controller->getIpDetails();
}
public function getDeviceDetails(): array {
$controller = new \Controllers\Admin\Devices\Navigation();
return $controller->getDeviceDetails();
}
public function getBotDetails(): array {
$controller = new \Controllers\Admin\Bot\Navigation();
return $controller->getBotDetails();
}
public function getDomainDetails(): array {
$controller = new \Controllers\Admin\Domain\Navigation();
return $controller->getDomainDetails();
}
public function getSearchResults(): array {
$controller = new \Controllers\Admin\Search\Navigation();
return $controller->getSearchResults();
}
public function getBlacklist(): array {
$controller = new \Controllers\Admin\Blacklist\Navigation();
return $controller->getList();
}
public function getUsageStats(): array {
$controller = new \Controllers\Admin\Api\Navigation();
return $controller->getUsageStats();
}
}

View File

@@ -0,0 +1,204 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\Data;
class Navigation extends \Controllers\Base {
use \Traits\Navigation;
private $dataController;
public function beforeroute(): void {
$errorCode = $this->validateCsrfToken();
if ($errorCode) {
$this->f3->error(403);
}
$this->redirectIfUnlogged();
$this->dataController = new Data();
$this->response = new \Views\Json();
}
// POST requests
public function enrichEntity(): void {
$this->response->data = $this->dataController->enrichEntity();
}
public function manageUser(): void {
$this->response->data = $this->dataController->manageUser();
}
public function removeFromWatchlist(): void {
$this->response->data = $this->dataController->removeFromWatchlist();
}
public function removeFromBlacklist(): void {
$this->response->data = $this->dataController->removeFromBlacklist();
}
public function saveRule(): void {
$this->response->data = $this->dataController->saveRule();
}
// GET requests
public function checkRule(): void {
$this->response->data = $this->dataController->checkRule();
}
public function getTimeFrameTotal(): void {
$this->response->data = $this->dataController->getTimeFrameTotal();
}
public function getCountries(): void {
$this->response->data = $this->dataController->getCountries();
}
public function getMap(): void {
$this->response->data = $this->dataController->getMap();
}
public function getIps(): void {
$this->response->data = $this->dataController->getIps();
}
public function getEvents(): void {
$this->response->data = $this->dataController->getEvents();
}
public function getLogbook(): void {
$this->response->data = $this->dataController->getLogbook();
}
public function getUsers(): void {
$this->response->data = $this->dataController->getUsers();
}
public function getBots(): void {
$this->response->data = $this->dataController->getBots();
}
public function getDevices(): void {
$this->response->data = $this->dataController->getDevices();
}
public function getResources(): void {
$this->response->data = $this->dataController->getResources();
}
public function getTopTen(): void {
$this->response->data = $this->dataController->getTopTen();
}
public function getDashboardStat(): void {
$this->response->data = $this->dataController->getDashboardStat();
}
public function getChart(): void {
$this->response->data = $this->dataController->getChart();
}
public function getEventDetails(): void {
$this->response->data = $this->dataController->getEventDetails();
}
public function getLogbookDetails(): void {
$this->response->data = $this->dataController->getLogbookDetails();
}
public function getEmailDetails(): void {
$this->response->data = $this->dataController->getEmailDetails();
}
public function getPhoneDetails(): void {
$this->response->data = $this->dataController->getPhoneDetails();
}
public function getUserDetails(): void {
$this->response->data = $this->dataController->getUserDetails();
}
public function getUserEnrichmentDetails(): void {
$this->response->data = $this->dataController->getUserEnrichmentDetails();
}
public function getNotCheckedEntitiesCount(): void {
$this->response->data = $this->dataController->getNotCheckedEntitiesCount();
}
public function getEmails(): void {
$this->response->data = $this->dataController->getEmails();
}
public function getPhones(): void {
$this->response->data = $this->dataController->getPhones();
}
public function getFieldAuditTrail(): void {
$this->response->data = $this->dataController->getFieldAuditTrail();
}
public function getUserScoreDetails(): void {
$this->response->data = $this->dataController->getUserScoreDetails();
}
public function getIsps(): void {
$this->response->data = $this->dataController->getIsps();
}
public function getDomains(): void {
$this->response->data = $this->dataController->getDomains();
}
public function getIspDetails(): void {
$this->response->data = $this->dataController->getIspDetails();
}
public function getIpDetails(): void {
$this->response->data = $this->dataController->getIpDetails();
}
public function getDeviceDetails(): void {
$this->response->data = $this->dataController->getDeviceDetails();
}
public function getBotDetails(): void {
$this->response->data = $this->dataController->getBotDetails();
}
public function getDomainDetails(): void {
$this->response->data = $this->dataController->getDomainDetails();
}
public function getReviewUsersQueue(): void {
$this->response->data = $this->dataController->getReviewUsersQueue();
}
public function getReviewUsersQueueCount(): void {
$this->response->data = $this->dataController->getReviewUsersQueueCount();
}
public function getSearchResults(): void {
$this->response->data = $this->dataController->getSearchResults();
}
public function getBlacklist(): void {
$this->response->data = $this->dataController->getBlacklist();
}
public function getUsageStats(): void {
$this->response->data = $this->dataController->getUsageStats();
}
}

View File

@@ -0,0 +1,65 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\Devices;
class Data extends \Controllers\Base {
public function getList(int $apiKey): array {
$result = [];
$model = new \Models\Grid\Devices\Grid($apiKey);
$ipId = $this->f3->get('REQUEST.ipId');
$userId = $this->f3->get('REQUEST.userId');
$resourceId = $this->f3->get('REQUEST.resourceId');
if (isset($ipId) && is_numeric($ipId)) {
$result = $model->getDevicesByIpId($ipId);
}
if (isset($userId) && is_numeric($userId)) {
$result = $model->getDevicesByUserId($userId);
}
if (isset($resourceId) && is_numeric($resourceId)) {
$result = $model->getDevicesByResourceId($resourceId);
}
if (!$result) {
$result = $model->getAllDevices();
}
return $result;
}
public function getDeviceDetails(int $apiKey): array {
$params = $this->f3->get('GET');
$id = $params['id'];
$model = new \Models\Device();
$details = $model->getFullDeviceInfoById($id, $apiKey);
$details['enrichable'] = $this->isEnrichable($apiKey);
$tsColumns = ['created'];
\Utils\TimeZones::localizeTimestampsForActiveOperator($tsColumns, $details);
return $details;
}
private function isEnrichable(int $apiKey): bool {
$model = new \Models\ApiKeys();
return $model->attributeIsEnrichable('ua', $apiKey);
}
}

View File

@@ -0,0 +1,33 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\Devices;
class Navigation extends \Controllers\Base {
use \Traits\ApiKeys;
use \Traits\Navigation;
public function getList(): array {
$apiKey = $this->getCurrentOperatorApiKeyId();
return $apiKey ? (new Data())->getList($apiKey) : [];
}
public function getDeviceDetails(): array {
$apiKey = $this->getCurrentOperatorApiKeyId();
return $apiKey ? (new Data())->getDeviceDetails($apiKey) : [];
}
}

View File

@@ -0,0 +1,64 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\Domain;
class Data extends \Controllers\Base {
use \Traits\ApiKeys;
public function proceedPostRequest(array $params): array {
return match ($params['cmd']) {
'reenrichment' => $this->enrichEntity($params),
default => []
};
}
public function enrichEntity(array $params): array {
$dataController = new \Controllers\Admin\Enrichment\Data();
$apiKey = $this->getCurrentOperatorApiKeyId();
$enrichmentKey = $this->getCurrentOperatorEnrichmentKeyString();
$type = $params['type'];
$search = $params['search'] ?? null;
$entityId = isset($params['entityId']) ? (int) $params['entityId'] : null;
return $dataController->enrichEntity($type, $search, $entityId, $apiKey, $enrichmentKey);
}
public function checkIfOperatorHasAccess(int $domainId): bool {
$apiKey = $this->getCurrentOperatorApiKeyId();
$model = new \Models\Domain();
return $model->checkAccess($domainId, $apiKey);
}
public function getDomainDetails(int $domainId): array {
$apiKey = $this->getCurrentOperatorApiKeyId();
$model = new \Models\Domain();
$result = $model->getFullDomainInfoById($domainId, $apiKey);
$tsColumns = ['lastseen'];
\Utils\TimeZones::localizeTimestampsForActiveOperator($tsColumns, $result);
return $result;
}
public function isEnrichable(): bool {
$apiKey = $this->getCurrentOperatorApiKeyId();
$model = new \Models\ApiKeys();
return $model->attributeIsEnrichable('domain', $apiKey);
}
}

View File

@@ -0,0 +1,41 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\Domain;
class Navigation extends \Controllers\Base {
use \Traits\ApiKeys;
use \Traits\Navigation;
public function showIndexPage(): void {
$this->redirectIfUnlogged();
$pageController = new Page();
$this->response = new \Views\Frontend();
$this->response->data = $pageController->getPageParams();
}
public function getDomainDetails(): array {
$dataController = new Data();
$domainId = $this->f3->get('REQUEST.domainId');
$hasAccess = $dataController->checkIfOperatorHasAccess($domainId);
if (!$hasAccess) {
$this->f3->error(404);
}
return $dataController->getDomainDetails($domainId);
}
}

View File

@@ -0,0 +1,60 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\Domain;
class Page extends \Controllers\Pages\Base {
public $page = 'AdminDomain';
public function getPageParams(): array {
$dataController = new Data();
$domainId = $this->integerParam($this->f3->get('PARAMS.domainId'));
$hasAccess = $dataController->checkIfOperatorHasAccess($domainId);
if (!$hasAccess) {
$this->f3->error(404);
}
$domain = $dataController->getDomainDetails($domainId);
$pageTitle = $this->getInternalPageTitleWithPostfix($domain['domain']);
$isEnrichable = $dataController->isEnrichable();
$pageParams = [
'LOAD_DATATABLE' => true,
'LOAD_JVECTORMAP' => true,
'LOAD_AUTOCOMPLETE' => true,
'HTML_FILE' => 'admin/domain.html',
'DOMAIN' => $domain,
'PAGE_TITLE' => $pageTitle,
'LOAD_UPLOT' => true,
'LOAD_ACCEPT_LANGUAGE_PARSER' => true,
'JS' => 'admin_domain.js',
'IS_ENRICHABLE' => $isEnrichable,
];
if ($this->isPostRequest()) {
$params = $this->f3->get('POST');
$operationResponse = $dataController->proceedPostRequest($params);
$pageParams = array_merge($pageParams, $operationResponse);
$pageParams['CMD'] = $params['cmd'];
// recall domain data
$pageParams['DOMAIN'] = $dataController->getDomainDetails($domainId);
}
return parent::applyPageParams($pageParams);
}
}

View File

@@ -0,0 +1,42 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\Domains;
class Data extends \Controllers\Base {
public function getList(int $apiKey): array {
$result = [];
$model = new \Models\Grid\Domains\Grid($apiKey);
$domainId = $this->f3->get('REQUEST.domainId');
if (isset($domainId)) {
$result = $model->getDomainsBySameIpDomainId($domainId);
}
if (!$result) {
$result = $model->getAllDomains();
}
$ids = array_column($result['data'], 'id');
if ($ids) {
$model = new \Models\Domain();
$model->updateTotalsByEntityIds($ids, $apiKey);
$result['data'] = $model->refreshTotals($result['data'], $apiKey);
}
return $result;
}
}

View File

@@ -0,0 +1,35 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\Domains;
class Navigation extends \Controllers\Base {
use \Traits\ApiKeys;
use \Traits\Navigation;
public function showIndexPage(): void {
$this->redirectIfUnlogged();
$pageController = new Page();
$this->response = new \Views\Frontend();
$this->response->data = $pageController->getPageParams();
}
public function getList(): array {
$apiKey = $this->getCurrentOperatorApiKeyId();
return $apiKey ? (new Data())->getList($apiKey) : [];
}
}

View File

@@ -0,0 +1,35 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\Domains;
class Page extends \Controllers\Pages\Base {
public $page = 'AdminDomains';
public function getPageParams(): array {
$searchPlacholder = $this->f3->get('AdminDomains_search_placeholder');
$pageParams = [
'SEARCH_PLACEHOLDER' => $searchPlacholder,
'LOAD_UPLOT' => true,
'LOAD_DATATABLE' => true,
'LOAD_AUTOCOMPLETE' => true,
'HTML_FILE' => 'admin/domains.html',
'JS' => 'admin_domains.js',
];
return parent::applyPageParams($pageParams);
}
}

View File

@@ -0,0 +1,51 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\Emails;
class Data extends \Controllers\Base {
public function getList(int $apiKey): array {
$result = [];
$model = new \Models\Grid\Emails\Grid($apiKey);
$userId = $this->f3->get('REQUEST.userId');
if (isset($userId) && is_numeric($userId)) {
$result = $model->getEmailsByUserId($userId);
}
return $result;
}
public function getEmailDetails(int $apiKey): array {
$params = $this->f3->get('GET');
$id = $params['id'];
$model = new \Models\Email();
$details = $model->getEmailDetails($id, $apiKey);
$details['enrichable'] = $this->isEnrichable($apiKey);
$tsColumns = ['email_created', 'email_lastseen', 'domain_lastseen', 'domain_created'];
\Utils\TimeZones::localizeTimestampsForActiveOperator($tsColumns, $details);
return $details;
}
private function isEnrichable(int $apiKey): bool {
$model = new \Models\ApiKeys();
return $model->attributeIsEnrichable('email', $apiKey);
}
}

View File

@@ -0,0 +1,33 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\Emails;
class Navigation extends \Controllers\Base {
use \Traits\ApiKeys;
use \Traits\Navigation;
public function getList(): array {
$apiKey = $this->getCurrentOperatorApiKeyId();
return $apiKey ? (new Data())->getList($apiKey) : [];
}
public function getEmailDetails(): array {
$apiKey = $this->getCurrentOperatorApiKeyId();
return $apiKey ? (new Data())->getEmailDetails($apiKey) : [];
}
}

View File

@@ -0,0 +1,252 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\Enrichment;
class Data extends \Controllers\Base {
public function enrichEntity(string $type, ?string $search, ?int $entityId, int $apiKey, ?string $enrichmentKey): array {
if ($enrichmentKey === null) {
return ['ERROR_CODE' => \Utils\ErrorCodes::ENRICHMENT_API_KEY_DOES_NOT_EXIST];
}
set_error_handler([\Utils\ErrorHandler::class, 'exceptionErrorHandler']);
$search = $search !== null ? ['value' => $search] : null;
$result = $this->enrichEntityProcess($type, $search, $entityId, $apiKey, $enrichmentKey);
restore_error_handler();
return $result;
}
private function enrichEntityProcess(string $type, ?array $search, ?int $entityId, int $apiKey, ?string $enrichmentKey): array {
$processErrorMessage = ['ERROR_CODE' => \Utils\ErrorCodes::ENRICHMENT_API_UNKNOWN_ERROR];
if ($type === 'device') {
if ($entityId !== null) {
$model = new \Models\Device();
$device = $model->getFullDeviceInfoById($entityId, $apiKey);
if ($device !== []) {
$entityId = $device['ua_id'];
$type = 'ua';
} else {
return $processErrorMessage;
}
} else {
return $processErrorMessage;
}
}
$model = new \Models\ApiKeys();
$attributes = $model->enrichableAttributes($apiKey);
if (!array_key_exists($type, $attributes)) {
return ['ERROR_CODE' => \Utils\ErrorCodes::ENRICHMENT_API_ATTRIBUTE_IS_UNAVAILABLE];
}
$modelDb = null;
$modelResult = null;
$extraModel = null;
switch ($type) {
case 'ip':
$modelDb = new \Models\Ip();
$modelResult = new \Models\Enrichment\Ip();
$extraModel = new \Models\Enrichment\LocalhostIp();
break;
case 'email':
$modelDb = new \Models\Email();
$modelResult = new \Models\Enrichment\Email();
break;
case 'domain':
$modelDb = new \Models\Domain();
$modelResult = new \Models\Enrichment\DomainFound();
$extraModel = new \Models\Enrichment\DomainNotFound();
break;
case 'phone':
$modelDb = new \Models\Phone();
$modelResult = new \Models\Enrichment\PhoneValid();
$extraModel = new \Models\Enrichment\PhoneInvalid();
break;
case 'ua':
$modelDb = new \Models\Device();
$modelResult = new \Models\Enrichment\Device();
break;
}
if ($modelDb === null) {
return $processErrorMessage;
}
$value = $entityId !== null ? $modelDb->extractById($entityId, $apiKey) : $search;
if ($value === null || $value === []) {
return $processErrorMessage;
}
$apiError = null;
try {
[$statusCode, $response,] = $this->enrichEntityByValue($type, $value, $enrichmentKey);
$error = \Utils\ApiResponseFormats::getErrorResponseFormat();
$apiError = \Utils\ApiResponseFormats::matchResponse($response[$type] ?? [], $error) ? $response[$type]['error'] : null;
} catch (\ErrorException $e) {
return $processErrorMessage;
}
if ($statusCode === 403) {
return ['ERROR_CODE' => \Utils\ErrorCodes::ENRICHMENT_API_KEY_OVERUSE];
}
if ($type === 'ip') {
// do not raise on bogon ip
if ($apiError === \Utils\Constants::get('ENRICHMENT_IP_IS_NOT_FOUND')) {
return ['ERROR_CODE' => \Utils\ErrorCodes::ENRICHMENT_API_IP_NOT_FOUND];
} elseif ($apiError !== null && $apiError !== \Utils\Constants::get('ENRICHMENT_IP_IS_BOGON') || $statusCode !== 200 || $response[$type] === null) {
return $processErrorMessage;
}
} elseif ($apiError !== null || $statusCode !== 200 || $response[$type] === null) {
return $processErrorMessage;
}
try {
$modelResult->init($response[$type]);
} catch (\ErrorException $e) {
if ($extraModel === null) {
return $processErrorMessage;
}
try {
$extraModel->init($response[$type]);
$modelResult = $extraModel;
} catch (\ErrorException $e) {
return $processErrorMessage;
}
}
// change value in db only if $entityId was passed
if ($entityId !== null) {
try {
$modelResult->updateEntityInDb($entityId, $apiKey);
} catch (\ErrorException $e) {
return $processErrorMessage;
}
}
return [
$type => $response[$type],
'SUCCESS_MESSAGE' => $this->f3->get('AdminEnrichment_success_message'),
];
}
private function validateResponse(string $requestType, int $statusCode, ?array $result, string $errorMessage): bool|string|int {
if (!is_array($result)) {
return \Utils\ErrorCodes::ENRICHMENT_API_UNKNOWN_ERROR;
}
if ($statusCode === 200 && is_array($result) && is_array($result[$requestType])) {
return false;
}
$details = $result['detail'] ?? null;
if ($details) {
if (is_array($details)) {
$messages = array_map(function ($detail) {
if (isset($detail['msg']) && $detail['msg'] !== null && $detail['msg'] !== '') {
return $detail['msg'];
}
}, $details);
$messages = implode('; ', $messages);
} else {
$messages = $details;
}
}
if (strlen($errorMessage) > 0) {
\Utils\Logger::log('Enrichment API web error', $errorMessage);
}
if (!isset($messages) || strlen($messages) < 1) {
return \Utils\ErrorCodes::ENRICHMENT_API_UNKNOWN_ERROR;
}
return $messages;
}
private function enrichEntityByValue(string $type, array $value, string $enrichmentKey): array {
$apiUrl = \Utils\Variables::getEnrichtmentApi();
$postFields = [
$type => $value['value'],
];
$options = [
'method' => 'POST',
'header' => [
'Content-Type: application/json',
'Authorization: Bearer ' . $enrichmentKey,
'User-Agent: ' . $this->f3->get('USER_AGENT'),
],
'content' => \json_encode($postFields),
];
/** @var array{request: array<string>, body: string, headers: array<string>, engine: string, cached: bool, error: string} $result */
$result = \Web::instance()->request(
url: sprintf('%s/query', $apiUrl),
options: $options,
);
$matches = [];
preg_match('/^HTTP\/(\d+)(?:\.\d)? (\d{3})/', $result['headers'][0], $matches);
$jsonResponse = json_decode($result['body'], true);
$statusCode = (int) ($matches[2] ?? 0);
$errorMessages = $this->validateResponse($type, $statusCode, $jsonResponse, $result['error']);
return [$statusCode, $jsonResponse, $errorMessages];
}
public function getNotCheckedEntitiesCount(int $apiKey): array {
$model = new \Models\ApiKeys();
$models = $model->enrichableAttributes($apiKey);
$result = [];
foreach ($models as $type => $model) {
$result[$type] = (new $model())->countNotChecked($apiKey);
}
return $result;
}
public function getNotCheckedExists(int $apiKey): bool {
$model = new \Models\ApiKeys();
$models = $model->enrichableAttributes($apiKey);
foreach ($models as $model) {
if ((new $model())->notCheckedExists($apiKey)) {
return true;
}
}
return false;
}
public function getNotCheckedEntitiesByUserId(int $userId, int $apiKey): array {
$model = new \Models\ApiKeys();
$models = $model->enrichableAttributes($apiKey);
$result = [];
foreach ($models as $type => $model) {
$result[$type] = (new $model())->notCheckedForUserId($userId, $apiKey);
}
return $result;
}
}

View File

@@ -0,0 +1,39 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\Enrichment;
class Navigation extends \Controllers\Base {
use \Traits\ApiKeys;
use \Traits\Navigation;
public function enrichEntity(): array {
$dataController = new Data();
$apiKey = $this->getCurrentOperatorApiKeyId();
$enrichmentKey = $this->getCurrentOperatorEnrichmentKeyString();
$params = $this->f3->get('POST');
$type = $params['type'];
$search = $params['search'] ?? null;
$entityId = $params['entityId'] ?? null;
return $dataController->enrichEntity($type, $search, $entityId, $apiKey, $enrichmentKey);
}
public function getNotCheckedEntitiesCount(): array {
$apiKey = $this->getCurrentOperatorApiKeyId();
return $apiKey ? (new Data())->getNotCheckedEntitiesCount($apiKey) : [];
}
}

View File

@@ -0,0 +1,94 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\Events;
class Data extends \Controllers\Base {
public function getList(int $apiKey): array {
$result = [];
$model = new \Models\Grid\Events\Grid($apiKey);
$ipId = $this->f3->get('REQUEST.ipId');
$ispId = $this->f3->get('REQUEST.ispId');
$userId = $this->f3->get('REQUEST.userId');
$botId = $this->f3->get('REQUEST.botId');
$domainId = $this->f3->get('REQUEST.domainId');
$countryId = $this->f3->get('REQUEST.countryId');
$resourceId = $this->f3->get('REQUEST.resourceId');
if (isset($ipId) && is_numeric($ipId)) {
$result = $model->getEventsByIpId($ipId);
}
if (isset($ispId)) {
$result = $model->getEventsByIspId($ispId);
}
if (isset($domainId) && is_numeric($domainId)) {
$result = $model->getEventsByDomainId($domainId);
}
if (isset($userId) && is_numeric($userId)) {
$result = $model->getEventsByUserId($userId);
}
if (isset($countryId) && is_numeric($countryId)) {
$result = $model->getEventsByCountryId($countryId);
}
if (isset($resourceId) && is_numeric($resourceId)) {
$result = $model->getEventsByResourceId($resourceId);
}
if (isset($botId) && is_numeric($botId)) {
$result = $model->getEventsByDeviceId($botId);
}
if (!$result) {
$result = $model->getAllEvents();
}
return $result;
}
public function getEventDetails(int $apiKey): array {
$params = $this->f3->get('GET');
$id = $params['id'];
$model = new \Models\Event();
$result = $model->getEventDetails($id, $apiKey);
$tsColumns = ['device_created', 'latest_decision', 'added_to_review', 'score_updated_at', 'event_time'];
\Utils\TimeZones::localizeTimestampsForActiveOperator($tsColumns, $result);
if (isset($result['event_type_id']) && $result['event_type_id'] === \Utils\Constants::get('FIELD_EDIT_EVENT_TYPE_ID')) {
$model = new \Models\FieldAuditTrail();
$result['event_payload'] = json_encode($model->getByEventId($id, $apiKey));
}
return $result;
}
public function getAllEventTypes(): array {
$model = new \Models\EventType();
return $model->getAll();
}
public function getAllDeviceTypes(): array {
return \Utils\Constants::get('DEVICE_TYPES');
}
}

View File

@@ -0,0 +1,41 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\Events;
class Navigation extends \Controllers\Base {
use \Traits\ApiKeys;
use \Traits\Navigation;
public function showIndexPage(): void {
$this->redirectIfUnlogged();
$pageController = new Page();
$this->response = new \Views\Frontend();
$this->response->data = $pageController->getPageParams();
}
public function getList(): array {
$apiKey = $this->getCurrentOperatorApiKeyId();
return $apiKey ? (new Data())->getList($apiKey) : [];
}
public function getEventDetails(): array {
$apiKey = $this->getCurrentOperatorApiKeyId();
return $apiKey ? (new Data())->getEventDetails($apiKey) : [];
}
}

View File

@@ -0,0 +1,43 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\Events;
class Page extends \Controllers\Pages\Base {
public $page = 'AdminEvents';
public function getPageParams(): array {
$searchPlacholder = $this->f3->get('AdminEvents_search_placeholder');
$controller = new Data();
$apiKey = $this->getCurrentOperatorApiKeyId();
$rulesController = new \Controllers\Admin\Rules\Data();
$pageParams = [
'SEARCH_PLACEHOLDER' => $searchPlacholder,
'LOAD_ACCEPT_LANGUAGE_PARSER' => true,
'LOAD_UPLOT' => true,
'LOAD_DATATABLE' => true,
'LOAD_CHOICES' => true,
'LOAD_AUTOCOMPLETE' => true,
'HTML_FILE' => 'admin/events.html',
'JS' => 'admin_events.js',
'EVENT_TYPES' => $controller->getAllEventTypes(),
'DEVICE_TYPES' => $controller->getAllDeviceTypes(),
'RULES' => $rulesController->getAllRulesByApiKey($apiKey),
];
return parent::applyPageParams($pageParams);
}
}

View File

@@ -0,0 +1,94 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\Home;
class Data extends \Controllers\Base {
use \Traits\DateRange;
public function getChart(int $apiKey): array {
$request = $this->f3->get('REQUEST');
$mode = $request['mode'];
$modelMap = \Utils\Constants::get('CHART_MODEL_MAP');
$model = array_key_exists($mode, $modelMap) ? new $modelMap[$mode]() : null;
return $model ? $model->getData($apiKey) : [[], []];
}
public function getStat(int $apiKey): array {
$request = $this->f3->get('REQUEST');
$dateRange = $this->getDatesRange($request);
$mode = $request['mode'];
$model = new \Models\Dashboard();
$result = [
'total' => null,
'allTimeTotal' => null,
];
switch ($mode) {
case 'totalEvents':
$result['total'] = $model->getTotalEvents($dateRange, $apiKey);
$result['allTimeTotal'] = $model->getTotalEvents(null, $apiKey);
break;
case 'totalUsers':
$result['total'] = $model->getTotalUsers($dateRange, $apiKey);
$result['allTimeTotal'] = $model->getTotalUsers(null, $apiKey);
break;
case 'totalIps':
$result['total'] = $model->getTotalIps($dateRange, $apiKey);
$result['allTimeTotal'] = $model->getTotalIps(null, $apiKey);
break;
case 'totalCountries':
$result['total'] = $model->getTotalCountries($dateRange, $apiKey);
$result['allTimeTotal'] = $model->getTotalCountries(null, $apiKey);
break;
case 'totalUrls':
$result['total'] = $model->getTotalResources($dateRange, $apiKey);
$result['allTimeTotal'] = $model->getTotalResources(null, $apiKey);
break;
case 'totalUsersForReview':
$result['total'] = $model->getTotalUsersForReview($dateRange, $apiKey);
$result['allTimeTotal'] = $model->getTotalUsersForReview(null, $apiKey);
break;
case 'totalBlockedUsers':
$result['total'] = $model->getTotalBlockedUsers($dateRange, $apiKey);
$result['allTimeTotal'] = $model->getTotalBlockedUsers(null, $apiKey);
break;
}
return $result;
}
public function getTopTen(int $apiKey): array {
$params = $this->f3->get('GET');
$dateRange = $this->getDatesRange($params);
$mode = $params['mode'];
$modelMap = \Utils\Constants::get('TOP_TEN_MODELS_MAP');
$model = array_key_exists($mode, $modelMap) ? new $modelMap[$mode]() : null;
$data = $model ? $model->getList($apiKey, $dateRange) : [];
$total = count($data);
return [
'draw' => $params['draw'] ?? 1,
'recordsTotal' => $total,
'recordsFiltered' => $total,
'data' => $data,
];
}
}

View File

@@ -0,0 +1,47 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\Home;
class Navigation extends \Controllers\Base {
use \Traits\ApiKeys;
use \Traits\Navigation;
public function showIndexPage(): void {
$this->redirectIfUnlogged('/login');
$pageController = new Page();
$this->response = new \Views\Frontend();
$this->response->data = $pageController->getPageParams();
}
public function getDashboardStat(): array {
$apiKey = $this->getCurrentOperatorApiKeyId();
return $apiKey ? (new Data())->getStat($apiKey) : [];
}
public function getTopTen(): array {
$apiKey = $this->getCurrentOperatorApiKeyId();
return $apiKey ? (new Data())->getTopTen($apiKey) : [];
}
public function getChart(): array {
$apiKey = $this->getCurrentOperatorApiKeyId();
return $apiKey ? (new Data())->getChart($apiKey) : [];
}
}

View File

@@ -0,0 +1,31 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\Home;
class Page extends \Controllers\Pages\Base {
public $page = 'AdminHome';
public function getPageParams(): array {
$pageParams = [
'LOAD_DATATABLE' => true,
'LOAD_AUTOCOMPLETE' => true,
'HTML_FILE' => 'admin/home.html',
'JS' => 'admin_dashboard.js',
];
return parent::applyPageParams($pageParams);
}
}

View File

@@ -0,0 +1,79 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\IP;
class Data extends \Controllers\Base {
use \Traits\ApiKeys;
public function proceedPostRequest(array $params): array {
return match ($params['cmd']) {
'reenrichment' => $this->enrichEntity($params),
default => []
};
}
public function enrichEntity(array $params): array {
$dataController = new \Controllers\Admin\Enrichment\Data();
$apiKey = $this->getCurrentOperatorApiKeyId();
$enrichmentKey = $this->getCurrentOperatorEnrichmentKeyString();
$type = $params['type'];
$search = $params['search'] ?? null;
$entityId = isset($params['entityId']) ? (int) $params['entityId'] : null;
return $dataController->enrichEntity($type, $search, $entityId, $apiKey, $enrichmentKey);
}
public function checkIfOperatorHasAccess(int $ipId): bool {
$apiKey = $this->getCurrentOperatorApiKeyId();
$model = new \Models\Ip();
return $model->checkAccess($ipId, $apiKey);
}
public function getIpDetails(int $ipId): array {
$result = $this->getFullIpInfoById($ipId);
return [
'full_country' => $result['full_country'],
'country_id' => $result['country_id'],
'country_iso' => $result['country_iso'],
'asn' => $result['asn'],
'blocklist' => $result['blocklist'],
'fraud_detected' => $result['fraud_detected'],
'data_center' => $result['data_center'],
'vpn' => $result['vpn'],
'tor' => $result['tor'],
'relay' => $result['relay'],
'starlink' => $result['starlink'],
'ispid' => $result['ispid'],
];
}
public function getFullIpInfoById(int $ipId): array {
$model = new \Models\Ip();
$result = $model->getFullIpInfoById($ipId);
$result['lastseen'] = \Utils\ElapsedDate::short($result['lastseen']);
return $result;
}
public function isEnrichable(): bool {
$apiKey = $this->getCurrentOperatorApiKeyId();
$model = new \Models\ApiKeys();
return $model->attributeIsEnrichable('ip', $apiKey);
}
}

View File

@@ -0,0 +1,41 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\IP;
class Navigation extends \Controllers\Base {
use \Traits\ApiKeys;
use \Traits\Navigation;
public function showIndexPage(): void {
$this->redirectIfUnlogged();
$pageController = new Page();
$this->response = new \Views\Frontend();
$this->response->data = $pageController->getPageParams();
}
public function getIpDetails(): array {
$dataController = new Data();
$ipId = $this->f3->get('REQUEST.ipId');
$hasAccess = $dataController->checkIfOperatorHasAccess($ipId);
if (!$hasAccess) {
$this->f3->error(404);
}
return $dataController->getIpDetails($ipId);
}
}

View File

@@ -0,0 +1,58 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\IP;
class Page extends \Controllers\Pages\Base {
public $page = 'AdminIp';
public function getPageParams(): array {
$dataController = new Data();
$ipId = $this->integerParam($this->f3->get('PARAMS.ipId'));
$hasAccess = $dataController->checkIfOperatorHasAccess($ipId);
if (!$hasAccess) {
$this->f3->error(404);
}
$ip = $dataController->getFullIpInfoById($ipId);
$pageTitle = $this->getInternalPageTitleWithPostfix($ip['ip']);
$isEnrichable = $dataController->isEnrichable();
$pageParams = [
'LOAD_DATATABLE' => true,
'LOAD_AUTOCOMPLETE' => true,
'HTML_FILE' => 'admin/ip.html',
'PAGE_TITLE' => $pageTitle,
'IP' => $ip,
'LOAD_UPLOT' => true,
'LOAD_ACCEPT_LANGUAGE_PARSER' => true,
'JS' => 'admin_ip.js',
'IS_ENRICHABLE' => $isEnrichable,
];
if ($this->isPostRequest()) {
$params = $this->f3->get('POST');
$operationResponse = $dataController->proceedPostRequest($params);
$pageParams = array_merge($pageParams, $operationResponse);
$pageParams['CMD'] = $params['cmd'];
// recall ip data
$pageParams['IP'] = $dataController->getFullIpInfoById($ipId);
}
return parent::applyPageParams($pageParams);
}
}

View File

@@ -0,0 +1,67 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\IPs;
class Data extends \Controllers\Base {
public function getList(int $apiKey): array {
$result = [];
$model = new \Models\Grid\Ips\Grid($apiKey);
$ispId = $this->f3->get('REQUEST.ispId');
$userId = $this->f3->get('REQUEST.userId');
$botId = $this->f3->get('REQUEST.botId');
$domainId = $this->f3->get('REQUEST.domainId');
$countryId = $this->f3->get('REQUEST.countryId');
$resourceId = $this->f3->get('REQUEST.resourceId');
if (isset($userId) && is_numeric($userId)) {
$result = $model->getIpsByUserId($userId);
}
if (isset($ispId)) {
$result = $model->getIpsByIspId($ispId);
}
if (isset($domainId) && is_numeric($domainId)) {
$result = $model->getIpsByDomainId($domainId);
}
if (isset($countryId) && is_numeric($countryId)) {
$result = $model->getIpsByCountryId($countryId);
}
if (isset($botId) && is_numeric($botId)) {
$result = $model->getIpsByDeviceId($botId);
}
if (isset($resourceId) && is_numeric($resourceId)) {
$result = $model->getIpsByResourceId($resourceId);
}
if (!$result) {
$result = $model->getAllIps();
}
$ids = array_column($result['data'], 'id');
if ($ids) {
$model = new \Models\Ip();
$model->updateTotalsByEntityIds($ids, $apiKey);
$result['data'] = $model->refreshTotals($result['data'], $apiKey);
}
return $result;
}
}

View File

@@ -0,0 +1,35 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\IPs;
class Navigation extends \Controllers\Base {
use \Traits\ApiKeys;
use \Traits\Navigation;
public function showIndexPage(): void {
$this->redirectIfUnlogged();
$pageController = new Page();
$this->response = new \Views\Frontend();
$this->response->data = $pageController->getPageParams();
}
public function getList(): array {
$apiKey = $this->getCurrentOperatorApiKeyId();
return $apiKey ? (new Data())->getList($apiKey) : [];
}
}

View File

@@ -0,0 +1,37 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\IPs;
class Page extends \Controllers\Pages\Base {
public $page = 'AdminIps';
public function getPageParams(): array {
$searchPlacholder = $this->f3->get('AdminIps_search_placeholder');
$pageParams = [
'SEARCH_PLACEHOLDER' => $searchPlacholder,
'LOAD_UPLOT' => true,
'LOAD_DATATABLE' => true,
'LOAD_CHOICES' => true,
'LOAD_AUTOCOMPLETE' => true,
'HTML_FILE' => 'admin/ips.html',
'JS' => 'admin_ips.js',
'IP_TYPES' => \Utils\Constants::get('IP_TYPES'),
];
return parent::applyPageParams($pageParams);
}
}

View File

@@ -0,0 +1,60 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\ISP;
class Data extends \Controllers\Base {
use \Traits\ApiKeys;
public function checkIfOperatorHasAccess(int $ispId): bool {
$apiKey = $this->getCurrentOperatorApiKeyId();
$model = new \Models\Isp();
return $model->checkAccess($ispId, $apiKey);
}
public function getFullIspInfoById(int $ispId): array {
$apiKey = $this->getCurrentOperatorApiKeyId();
$model = new \Models\Isp();
$result = $model->getFullIspInfoById($ispId, $apiKey);
$result['lastseen'] = \Utils\ElapsedDate::short($result['lastseen']);
return $result;
}
private function getNumberOfIpsByIspId(int $ispId): int {
$apiKey = $this->getCurrentOperatorApiKeyId();
$model = new \Models\Isp();
return $model->getIpCountById($ispId, $apiKey);
}
public function getIspDetails(int $ispId): array {
$result = [];
$data = $this->getFullIspInfoById($ispId);
if (array_key_exists('asn', $data)) {
$result = [
'asn' => $data['asn'],
'total_fraud' => $data['total_fraud'],
'total_visit' => $data['total_visit'],
'total_account' => $data['total_account'],
'total_ip' => $this->getNumberOfIpsByIspId($ispId),
];
}
return $result;
}
}

View File

@@ -0,0 +1,41 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\ISP;
class Navigation extends \Controllers\Base {
use \Traits\ApiKeys;
use \Traits\Navigation;
public function showIndexPage(): void {
$this->redirectIfUnlogged();
$pageController = new Page();
$this->response = new \Views\Frontend();
$this->response->data = $pageController->getPageParams();
}
public function getIspDetails(): array {
$dataController = new Data();
$ispId = $this->f3->get('REQUEST.ispId');
$hasAccess = $dataController->checkIfOperatorHasAccess($ispId);
if (!$hasAccess) {
$this->f3->error(404);
}
return $dataController->getIspDetails($ispId);
}
}

View File

@@ -0,0 +1,47 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\ISP;
class Page extends \Controllers\Pages\Base {
public $page = 'AdminIsp';
public function getPageParams(): array {
$dataController = new Data();
$ispId = $this->integerParam($this->f3->get('PARAMS.ispId'));
$hasAccess = $dataController->checkIfOperatorHasAccess($ispId);
if (!$hasAccess) {
$this->f3->error(404);
}
$isp = $dataController->getFullIspInfoById($ispId);
$pageTitle = $this->getInternalPageTitleWithPostfix(strval($isp['asn']));
$pageParams = [
'LOAD_DATATABLE' => true,
'LOAD_JVECTORMAP' => true,
'LOAD_AUTOCOMPLETE' => true,
'HTML_FILE' => 'admin/isp.html',
'ISP' => $isp,
'PAGE_TITLE' => $pageTitle,
'LOAD_UPLOT' => true,
'LOAD_ACCEPT_LANGUAGE_PARSER' => true,
'JS' => 'admin_isp.js',
];
return parent::applyPageParams($pageParams);
}
}

View File

@@ -0,0 +1,56 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\ISPs;
class Data extends \Controllers\Base {
public function getList(int $apiKey): array {
$result = [];
$model = new \Models\Grid\Isps\Grid($apiKey);
$userId = $this->f3->get('REQUEST.userId');
$domainId = $this->f3->get('REQUEST.domainId');
$countryId = $this->f3->get('REQUEST.countryId');
$resourceId = $this->f3->get('REQUEST.resourceId');
if (isset($userId) && is_numeric($userId)) {
$result = $model->getIspsByUserId($userId);
}
if (isset($domainId) && is_numeric($domainId)) {
$result = $model->getIspsByDomainId($domainId);
}
if (isset($countryId) && is_numeric($countryId)) {
$result = $model->getIspsByCountryId($countryId);
}
if (isset($resourceId) && is_numeric($resourceId)) {
$result = $model->getIspsByResourceId($resourceId);
}
if (!$result) {
$result = $model->getAllIsps();
}
$ids = array_column($result['data'], 'id');
if ($ids) {
$model = new \Models\Isp();
$model->updateTotalsByEntityIds($ids, $apiKey);
$result['data'] = $model->refreshTotals($result['data'], $apiKey);
}
return $result;
}
}

View File

@@ -0,0 +1,35 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\ISPs;
class Navigation extends \Controllers\Base {
use \Traits\ApiKeys;
use \Traits\Navigation;
public function showIndexPage(): void {
$this->redirectIfUnlogged();
$pageController = new Page();
$this->response = new \Views\Frontend();
$this->response->data = $pageController->getPageParams();
}
public function getList(): array {
$apiKey = $this->getCurrentOperatorApiKeyId();
return $apiKey ? (new Data())->getList($apiKey) : [];
}
}

View File

@@ -0,0 +1,35 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\ISPs;
class Page extends \Controllers\Pages\Base {
public $page = 'AdminIsps';
public function getPageParams(): array {
$searchPlacholder = $this->f3->get('AdminIsps_search_placeholder');
$pageParams = [
'SEARCH_PLACEHOLDER' => $searchPlacholder,
'LOAD_UPLOT' => true,
'LOAD_DATATABLE' => true,
'LOAD_AUTOCOMPLETE' => true,
'HTML_FILE' => 'admin/isps.html',
'JS' => 'admin_isps.js',
];
return parent::applyPageParams($pageParams);
}
}

View File

@@ -0,0 +1,32 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\Logbook;
class Data extends \Controllers\Base {
public function getList(int $apiKey): array {
$model = new \Models\Grid\Logbook\Grid($apiKey);
return $model->getAllLogbookEvents();
}
public function getLogbookDetails(int $apiKey): array {
$params = $this->f3->get('GET');
$id = $params['id'];
$model = new \Models\Logbook();
return $model->getLogbookDetails($id, $apiKey);
}
}

View File

@@ -0,0 +1,42 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\Logbook;
class Navigation extends \Controllers\Base {
use \Traits\ApiKeys;
use \Traits\Navigation;
public function showIndexPage(): void {
$this->redirectIfUnlogged();
$pageController = new Page();
$this->response = new \Views\Frontend();
$this->response->data = $pageController->getPageParams();
}
// TODO: daterange ~= event_logbook.started?
public function getList(): array {
$apiKey = $this->getCurrentOperatorApiKeyId();
return $apiKey ? (new Data())->getList($apiKey) : [];
}
public function getLogbookDetails(): array {
$apiKey = $this->getCurrentOperatorApiKeyId();
return $apiKey ? (new Data())->getLogbookDetails($apiKey) : [];
}
}

View File

@@ -0,0 +1,35 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\Logbook;
class Page extends \Controllers\Pages\Base {
public $page = 'AdminLogbook';
public function getPageParams(): array {
$searchPlacholder = $this->f3->get('AdminLogbook_search_placeholder');
$pageParams = [
'SEARCH_PLACEHOLDER' => $searchPlacholder,
'LOAD_UPLOT' => true,
'LOAD_DATATABLE' => true,
'LOAD_AUTOCOMPLETE' => true,
'HTML_FILE' => 'admin/logbook.html',
'JS' => 'admin_logbook.js',
];
return parent::applyPageParams($pageParams);
}
}

View File

@@ -0,0 +1,108 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\ManualCheck;
class Data extends \Controllers\Base {
use \Traits\ApiKeys;
public function proceedPostRequest(array $params): array {
return $this->performSearch($params);
}
public function performSearch(array $params): array {
$pageParams = [
'SEARCH_VALUES' => $params,
];
$apiKey = $this->getCurrentOperatorApiKeyId();
$enrichmentKey = $this->getCurrentOperatorEnrichmentKeyString();
$errorCode = $this->validateSearch($params, $enrichmentKey);
if ($errorCode) {
$pageParams['ERROR_CODE'] = $errorCode;
return $pageParams;
}
$type = $params['type'];
$controller = new \Controllers\Admin\Enrichment\Data();
$result = $controller->enrichEntity($type, $params['search'], null, $apiKey, $enrichmentKey);
if (isset($result['ERROR_CODE'])) {
$pageParams['ERROR_CODE'] = $result['ERROR_CODE'];
return $pageParams;
}
$this->saveSearch($params);
// TODO: return alert_list back in next release
if (array_key_exists('alert_list', $result[$type])) {
unset($result[$type]['alert_list']);
}
if ($type === 'phone') {
unset($result[$type]['valid']);
unset($result[$type]['validation_error']);
}
if ($type === 'email') {
unset($result[$type]['data_breaches']);
}
$pageParams['RESULT'] = [$type => $result[$type]];
return $pageParams;
}
private function validateSearch(array $params, string $enrichmentKey): bool|int {
$errorCode = \Utils\Access::CSRFTokenValid($params, $this->f3);
if ($errorCode) {
return $errorCode;
}
$api = \Utils\Variables::getEnrichtmentApi();
if (!$enrichmentKey || !$api) {
return \Utils\ErrorCodes::ENRICHMENT_API_KEY_DOES_NOT_EXIST;
}
$type = $params['type'] ?? null;
$types = $this->f3->get('AdminManualCheck_form_types');
if (!$type || !array_key_exists($type, $types)) {
return \Utils\ErrorCodes::TYPE_DOES_NOT_EXIST;
}
$search = $params['search'] ?? null;
if (!$search || strlen($search) < 1) {
return \Utils\ErrorCodes::SEARCH_QUERY_DOES_NOT_EXIST;
}
return false;
}
private function saveSearch(array $params): void {
$history = new \Models\ManualCheckHistoryQuery();
$history->add($params);
}
public function getSearchHistory(int $operatorId): ?array {
$model = new \Models\ManualCheckHistory();
return $model->getRecentByOperator($operatorId);
}
}

View File

@@ -0,0 +1,29 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\ManualCheck;
class Navigation extends \Controllers\Base {
use \Traits\ApiKeys;
use \Traits\Navigation;
public function showIndexPage(): void {
$this->redirectIfUnlogged();
$pageController = new Page();
$this->response = new \Views\Frontend();
$this->response->data = $pageController->getPageParams();
}
}

View File

@@ -0,0 +1,60 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\ManualCheck;
class Page extends \Controllers\Pages\Base {
public $page = 'AdminManualCheck';
public function getPageParams(): array {
$dataController = new Data();
$pageParams = [
'LOAD_AUTOCOMPLETE' => true,
'LOAD_DATATABLE' => true,
'HTML_FILE' => 'admin/manualCheck.html',
'JS' => 'admin_manual_check.js',
];
$currentOperator = $this->f3->get('CURRENT_USER');
$operatorId = $currentOperator->id;
if ($this->isPostRequest()) {
$params = $this->f3->get('POST');
$params['operator'] = $operatorId;
$operationResponse = $dataController->proceedPostRequest($params);
$pageParams = array_merge($pageParams, $operationResponse);
}
$pageParams['HISTORY'] = $dataController->getSearchHistory($operatorId);
return parent::applyPageParams($pageParams);
}
public static function stylizeKey(string $key): string {
$f3 = \Base::instance();
$overwrites = $f3->get('AdminManualCheck_key_overwrites');
if (array_key_exists($key, $overwrites)) {
return $overwrites[$key];
}
if ($key === 'profiles' || $key === 'data_breach') {
$key = sprintf('no_%s', $key);
}
return ucfirst(str_replace('_', ' ', $key));
}
}

View File

@@ -0,0 +1,31 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\Payloads\FieldAuditTrail;
class Data extends \Controllers\Base {
public function getList(int $apiKey): array {
$result = [];
$model = new \Models\Grid\Payloads\FieldAuditTrail\Grid($apiKey);
$userId = $this->f3->get('REQUEST.userId');
if (isset($userId) && is_numeric($userId)) {
$result = $model->getDataByUserId($userId);
}
return $result;
}
}

View File

@@ -0,0 +1,27 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\Payloads\FieldAuditTrail;
class Navigation extends \Controllers\Base {
use \Traits\ApiKeys;
use \Traits\Navigation;
public function getList(): array {
$apiKey = $this->getCurrentOperatorApiKeyId();
return $apiKey ? (new Data())->getList($apiKey) : [];
}
}

View File

@@ -0,0 +1,58 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\Phones;
class Data extends \Controllers\Base {
public function getList(int $apiKey): array {
$result = [];
$model = new \Models\Grid\Phones\Grid($apiKey);
$userId = $this->f3->get('REQUEST.userId');
if (isset($userId) && is_numeric($userId)) {
$result = $model->getPhonesByUserId($userId);
}
$ids = array_column($result['data'], 'id');
if ($ids) {
$model = new \Models\Phone();
$model->updateTotalsByEntityIds($ids, $apiKey);
$result['data'] = $model->refreshTotals($result['data'], $apiKey);
}
return $result;
}
public function getPhoneDetails(int $apiKey): array {
$params = $this->f3->get('GET');
$id = $params['id'];
$model = new \Models\Phone();
$details = $model->getPhoneDetails($id, $apiKey);
$details['enrichable'] = $this->isEnrichable($apiKey);
$tsColumns = ['created', 'lastseen'];
\Utils\TimeZones::localizeTimestampsForActiveOperator($tsColumns, $details);
return $details;
}
private function isEnrichable(int $apiKey): bool {
$model = new \Models\ApiKeys();
return $model->attributeIsEnrichable('phone', $apiKey);
}
}

View File

@@ -0,0 +1,33 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\Phones;
class Navigation extends \Controllers\Base {
use \Traits\ApiKeys;
use \Traits\Navigation;
public function getList(): array {
$apiKey = $this->getCurrentOperatorApiKeyId();
return $apiKey ? (new Data())->getList($apiKey) : [];
}
public function getPhoneDetails(): array {
$apiKey = $this->getCurrentOperatorApiKeyId();
return $apiKey ? (new Data())->getPhoneDetails($apiKey) : [];
}
}

View File

@@ -0,0 +1,35 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\Resource;
class Data extends \Controllers\Base {
use \Traits\ApiKeys;
public function checkIfOperatorHasAccess(int $resourceId): bool {
$apiKey = $this->getCurrentOperatorApiKeyId();
$model = new \Models\Resource();
return $model->checkAccess($resourceId, $apiKey);
}
public function getResourceById(int $resourceId): array {
$model = new \Models\Resource();
$result = $model->getResourceById($resourceId);
$result['lastseen'] = \Utils\ElapsedDate::short($result['lastseen']);
return $result;
}
}

View File

@@ -0,0 +1,29 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\Resource;
class Navigation extends \Controllers\Base {
use \Traits\ApiKeys;
use \Traits\Navigation;
public function showIndexPage(): void {
$this->redirectIfUnlogged();
$pageController = new Page();
$this->response = new \Views\Frontend();
$this->response->data = $pageController->getPageParams();
}
}

View File

@@ -0,0 +1,53 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\Resource;
class Page extends \Controllers\Pages\Base {
public $page = 'AdminResource';
public function getPageParams(): array {
$dataController = new Data();
$resourceId = $this->integerParam($this->f3->get('PARAMS.resourceId'));
$hasAccess = $dataController->checkIfOperatorHasAccess($resourceId);
if (!$hasAccess) {
$this->f3->error(404);
}
$resource = $dataController->getResourceById($resourceId);
$pageTitle = $resource['url'];
if ($resource['title']) {
$pageTitle .= sprintf(' (%s)', $resource['title']);
}
$pageTitle = $this->getInternalPageTitleWithPostfix($pageTitle);
$pageParams = [
'LOAD_DATATABLE' => true,
'LOAD_JVECTORMAP' => true,
'LOAD_UPLOT' => true,
'LOAD_ACCEPT_LANGUAGE_PARSER' => true,
'LOAD_AUTOCOMPLETE' => true,
'HTML_FILE' => 'admin/resource.html',
'RESOURCE' => $resource,
'PAGE_TITLE' => $pageTitle,
'JS' => 'admin_resource.js',
];
return parent::applyPageParams($pageParams);
}
}

View File

@@ -0,0 +1,32 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\Resources;
class Data extends \Controllers\Base {
public function getList(int $apiKey): array {
$model = new \Models\Grid\Resources\Grid($apiKey);
$result = $model->getAllResources();
$ids = array_column($result['data'], 'id');
if ($ids) {
$model = new \Models\Resource();
$model->updateTotalsByEntityIds($ids, $apiKey);
$result['data'] = $model->refreshTotals($result['data'], $apiKey);
}
return $result;
}
}

View File

@@ -0,0 +1,35 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\Resources;
class Navigation extends \Controllers\Base {
use \Traits\ApiKeys;
use \Traits\Navigation;
public function showIndexPage(): void {
$this->redirectIfUnlogged();
$pageController = new Page();
$this->response = new \Views\Frontend();
$this->response->data = $pageController->getPageParams();
}
public function getList(): array {
$apiKey = $this->getCurrentOperatorApiKeyId();
return $apiKey ? (new Data())->getList($apiKey) : [];
}
}

View File

@@ -0,0 +1,35 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\Resources;
class Page extends \Controllers\Pages\Base {
public $page = 'AdminResources';
public function getPageParams(): array {
$searchPlacholder = $this->f3->get('AdminResources_search_placeholder');
$pageParams = [
'SEARCH_PLACEHOLDER' => $searchPlacholder,
'LOAD_UPLOT' => true,
'LOAD_DATATABLE' => true,
'LOAD_AUTOCOMPLETE' => true,
'HTML_FILE' => 'admin/resources.html',
'JS' => 'admin_resources.js',
];
return parent::applyPageParams($pageParams);
}
}

View File

@@ -0,0 +1,66 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\ReviewQueue;
class Data extends \Controllers\Base {
public function getList(int $apiKey): array {
$model = new \Models\Grid\ReviewQueue\Grid($apiKey);
return $model->getAllUnderReviewUsers() ?? [];
}
public function getNumberOfNotReviewedUsers(int $apiKey, bool $useCache = true, bool $overall = false): array {
$currentOperator = $this->f3->get('CURRENT_USER');
$takeFromCache = $this->canTakeNumberOfNotReviewedUsersFromCache($currentOperator);
$total = $currentOperator->review_queue_cnt;
if (!$useCache || !$takeFromCache) {
$model = new \Models\Grid\ReviewQueue\Grid($apiKey);
$total = !$overall ? $model->getTotalUnderReviewUsers() : $model->getTotalUnderReviewUsersOverall();
if ($total > 999) {
$total = 999;
}
$data = [
'id' => $currentOperator->id,
'review_queue_cnt' => $total,
];
$model = new \Models\Operator();
$model->updateReviewedQueueCnt($data);
}
return ['total' => $total];
}
private function canTakeNumberOfNotReviewedUsersFromCache(\Models\Operator $currentOperator): bool {
$diff = PHP_INT_MAX;
$currentTime = gmdate('Y-m-d H:i:s');
$updatedAt = $currentOperator->review_queue_updated_at;
if ($updatedAt) {
$dt1 = new \DateTime($currentTime);
$dt2 = new \DateTime($updatedAt);
$diff = $dt1->getTimestamp() - $dt2->getTimestamp();
}
$cacheTime = $this->f3->get('REVIEWED_QUEUE_CNT_CACHE_TIME');
return $cacheTime > $diff;
}
}

View File

@@ -0,0 +1,41 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\ReviewQueue;
class Navigation extends \Controllers\Base {
use \Traits\ApiKeys;
use \Traits\Navigation;
public function showIndexPage(): void {
$this->redirectIfUnlogged();
$pageController = new Page();
$this->response = new \Views\Frontend();
$this->response->data = $pageController->getPageParams();
}
public function getList(): array {
$apiKey = $this->getCurrentOperatorApiKeyId();
return $apiKey ? (new Data())->getList($apiKey) : [];
}
public function getNumberOfNotReviewedUsers(bool $useCache = true, bool $overall = false): array {
$apiKey = $this->getCurrentOperatorApiKeyId();
return $apiKey ? (new Data())->getNumberOfNotReviewedUsers($apiKey, $useCache, $overall) : [];
}
}

View File

@@ -0,0 +1,39 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\ReviewQueue;
class Page extends \Controllers\Pages\Base {
public $page = 'AdminReviewQueue';
public function getPageParams(): array {
$searchPlacholder = $this->f3->get('AdminReviewQueue_search_placeholder');
$apiKey = $this->getCurrentOperatorApiKeyId();
$rulesController = new \Controllers\Admin\Rules\Data();
$pageParams = [
'SEARCH_PLACEHOLDER' => $searchPlacholder,
'LOAD_UPLOT' => true,
'LOAD_DATATABLE' => true,
'LOAD_CHOICES' => true,
'LOAD_AUTOCOMPLETE' => true,
'HTML_FILE' => 'admin/reviewQueue.html',
'JS' => 'admin_review_queue.js',
'RULES' => $rulesController->getAllRulesByApiKey($apiKey),
];
return parent::applyPageParams($pageParams);
}
}

View File

@@ -0,0 +1,515 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\Rules;
class Data extends \Controllers\Base {
use \Traits\ApiKeys;
private \Controllers\Admin\Context\Data $contextController;
private \Controllers\Admin\User\Data $userController;
private \Models\OperatorsRules $rulesModel;
private array $totalModels;
private array $rulesMap;
public function proceedPostRequest(array $params): array {
return match ($params['cmd']) {
'changeThresholdValues' => $this->changeThresholdValues($params),
'refreshRules' => $this->refreshRules($params),
default => []
};
}
private function refreshRules(array $params): array {
$pageParams = [];
$errorCode = $this->validateRefreshRules($params);
if ($errorCode) {
$pageParams['ERROR_CODE'] = $errorCode;
} else {
$model = new \Models\Rules();
// get all rules from db by uid; will not return classes with filename mismatch or invalid classname
$currentRules = $model->getAll();
$sortedRules = [];
foreach ($currentRules as $rule) {
$sortedRules[$rule['uid']] = $rule;
}
$localClasses = \Utils\RulesClasses::getRulesClasses(false);
$mainClasses = \Utils\RulesClasses::getRulesClasses(true);
$iterates = [[], [], [], [], [], []];
$metUids = [];
$parentClass = \Controllers\Admin\Rules\Set\BaseRule::class;
$mtd = 'defineCondition';
// local classes first to keep ability to override default classes
$allClassesFromFiles = $localClasses['imported'] + $mainClasses['imported'];
foreach ($allClassesFromFiles as $uid => $cls) {
$valid = true;
$name = constant("$cls::NAME") ?? '';
$descr = constant("$cls::DESCRIPTION") ?? '';
$attr = constant("$cls::ATTRIBUTES") ?? [];
$obj = [
'uid' => $uid,
'name' => $name,
'descr' => $descr,
'attributes' => $attr,
];
// check constants
if (!is_string($name) || !is_string($descr) || !is_array($attr)) {
$valid = false;
$obj['name'] = '';
$obj['descr'] = '';
$obj['attributes'] = [];
// check if rule is child class of BaseRule and defineCondition() was implemented
} elseif (!is_subclass_of($cls, $parentClass) || (new \ReflectionMethod($cls, $mtd))->isAbstract()) {
$valid = false;
}
$status = $this->addRule($sortedRules, $obj, $valid, $model);
$iterates[($status === null ? 0 : 1 + intval($status)) * 2 + intval($valid)][] = $uid;
$metUids[] = $uid;
}
$flipMetUids = array_flip($metUids);
$newMissingRules = [];
$oldMissingCnt = 0;
foreach ($sortedRules as $uid => $rule) {
if (!array_key_exists($uid, $flipMetUids)) {
if (!$rule['missing']) {
$newMissingRules[$uid] = $rule;
$model->setMissingByUid($uid);
} else {
$oldMissingCnt += 1;
}
}
}
//$successCnt = count($iterates[5]) + count($iterates[3]);
//$warningCnt = count($iterates[4]) + count($iterates[2]);
$newValidCnt = count($iterates[5]);
$newInvalidCnt = count($iterates[4]);
$updValidCnt = count($iterates[3]);
$updInvalidCnt = count($iterates[2]);
$missingCnt = count($newMissingRules);
$messages = [];
$messages[] = $this->getStatusNotification($newValidCnt, 'Added %s rule%s: %s', $iterates[5]);
$messages[] = $this->getStatusNotification($updValidCnt, 'Updated %s rule%s: %s', $iterates[3]);
$msg = join(";\n", array_filter($messages));
if ($msg) {
$pageParams['SUCCESS_MESSAGE'] = $msg;
}
$messages = [];
$messages[] = $this->getStatusNotification($newInvalidCnt, 'Added %s invalid rule%s: %s', $iterates[4]);
$messages[] = $this->getStatusNotification($updInvalidCnt, 'Updated %s invalid rule%s: %s', $iterates[2]);
$messages[] = $this->getStatusNotification($missingCnt, 'Missing %s rule%s: %s', array_column($newMissingRules, 'uid'));
$msg = join(";\n", array_filter($messages));
if ($msg) {
$pageParams['ERROR_MESSAGE'] = $msg;
}
if (!array_key_exists('ERROR_MESSAGE', $pageParams) && !array_key_exists('SUCCESS_MESSAGE', $pageParams)) {
$activeCnt = count($iterates[1]);
$invalidCnt = count($iterates[0]);
$msg = sprintf('Rules refreshed (%s rule%s active', $activeCnt, ($activeCnt > 1 ? 's' : ''));
if ($invalidCnt) {
$msg .= sprintf(', %s invalid', $invalidCnt);
}
if ($oldMissingCnt) {
$msg .= sprintf(', %s missing', $oldMissingCnt);
}
$msg .= ')';
$pageParams['SUCCESS_MESSAGE'] = $msg;
}
}
return $pageParams;
}
private function getStatusNotification(int $cnt, string $template, array $data): ?string {
if (!$cnt) {
return null;
}
$s = join(', ', array_slice($data, 0, 10, true)) . ($cnt > 10 ? '&hellip;' : '.');
return sprintf($template, strval($cnt), ($cnt > 1 ? 's' : ''), $s);
}
private function addRule(array $existingArray, array $obj, bool $valid, \Models\Rules $model): ?bool {
$data = $existingArray[$obj['uid']] ?? null;
$r = null;
sort($obj['attributes']);
if ($data === null) {
$r = true;
} else {
$data['attributes'] = json_decode($data['attributes']);
sort($data['attributes']);
foreach ($obj as $key => $value) {
if ($value !== $data[$key]) {
$r = false;
break;
}
}
if ($r !== false && $data['validated'] !== $valid) {
$r = false;
}
}
if ($r !== null || $data['missing']) {
$model->addRule($obj['uid'], $obj['name'], $obj['descr'], $obj['attributes'], $valid);
}
return ($data !== null && $data['missing']) ? true : $r;
}
private function validateRefreshRules(array $params): int|false {
$errorCode = \Utils\Access::CSRFTokenValid($params, $this->f3);
if ($errorCode) {
return $errorCode;
}
return false;
}
public function changeThresholdValues(array $params): array {
$pageParams = [];
$errorCode = $this->validateThresholdValues($params);
if ($errorCode) {
$pageParams['ERROR_CODE'] = $errorCode;
} else {
$keyId = isset($params['keyId']) ? (int) $params['keyId'] : null;
$model = new \Models\ApiKeys();
$model->getKeyById($keyId);
$blacklistThreshold = (int) ($params['blacklist-threshold'] ?? -1);
$reviewQueueThreshold = (int) ($params['review-queue-threshold'] ?? 0);
$recalculateReviewQueueCnt = $model->review_queue_threshold !== $reviewQueueThreshold;
$model->updateBlacklistThreshold($blacklistThreshold);
$model->updateReviewQueueThreshold($reviewQueueThreshold);
if ($recalculateReviewQueueCnt) {
$controller = new \Controllers\Admin\ReviewQueue\Data();
$controller->getNumberOfNotReviewedUsers($keyId, false, true);
}
$pageParams['SUCCESS_MESSAGE'] = $this->f3->get('AdminThresholdValues_update_success_message');
}
return $pageParams;
}
private function validateThresholdValues(array $params): int|false {
$errorCode = \Utils\Access::CSRFTokenValid($params, $this->f3);
if ($errorCode) {
return $errorCode;
}
$keyId = isset($params['keyId']) ? (int) $params['keyId'] : null;
if (!$keyId) {
return \Utils\ErrorCodes::API_KEY_ID_DOESNT_EXIST;
}
if ($keyId !== $this->getCurrentOperatorApiKeyId()) {
return \Utils\ErrorCodes::API_KEY_WAS_CREATED_FOR_ANOTHER_USER;
}
$blacklistThreshold = (int) ($params['blacklist-threshold'] ?? -1);
if ($blacklistThreshold < -1 || $blacklistThreshold > 18) {
return \Utils\ErrorCodes::BLACKLIST_THRESHOLD_DOES_NOT_EXIST;
}
$reviewQueueThreshold = (int) ($params['review-queue-threshold'] ?? 0);
if ($reviewQueueThreshold < 0 || $reviewQueueThreshold > 100) {
return \Utils\ErrorCodes::REVIEW_QUEUE_THRESHOLD_DOES_NOT_EXIST;
}
if ($reviewQueueThreshold <= $blacklistThreshold) {
return \Utils\ErrorCodes::BLACKLIST_THRESHOLD_EXCEEDS_REVIEW_QUEUE_THRESHOLD;
}
return false;
}
public function getRulesForLoggedUser(): array {
$apiKey = $this->getCurrentOperatorApiKeyId();
return $this->getAllAttrFilteredRulesByApiKey($apiKey);
}
public function saveUserRule(string $ruleUid, int $score): void {
$apiKey = $this->getCurrentOperatorApiKeyId();
$model = new \Models\OperatorsRules();
$model->updateRule($ruleUid, $score, $apiKey);
}
public function saveRuleProportion(string $ruleUid, float $proportion): void {
$apiKey = $this->getCurrentOperatorApiKeyId();
$model = new \Models\OperatorsRules();
$model->updateRuleProportion($ruleUid, $proportion, $apiKey);
}
public function getRuleProportion(int $totalUsers, int $ruleUsers): float {
if ($ruleUsers === 0 || $totalUsers === 0) {
return 0.0;
}
$proportion = (float) (100 * $ruleUsers) / (float) $totalUsers;
// if number is too small make it a bit greater so it will be written in db as 0 < n < 1
return abs($proportion) < 0.001 ? 0.001 : $proportion;
}
// return array of uids on each account of triggered rules
private function evaluateRules(array $accountIds, array $rules, int $apiKey): array {
$result = array_fill_keys($accountIds, []);
$context = [];
$record = [];
foreach (array_chunk($accountIds, \Utils\Variables::getRuleUsersBatchSize()) as $batch) {
$context = $this->contextController->getContextByAccountIds($batch, $apiKey);
foreach ($batch as $user) {
$record = $context[$user] ?? null;
if ($record) {
foreach ($rules as $rule) {
if ($this->executeRule($rule, $record)) {
$result[$user][] = $rule->uid;
}
}
}
}
}
return $result;
}
private function executeRule(Set\BaseRule $rule, array $params): bool {
$executed = false;
try {
$rule->updateParams($params);
$executed = $rule->execute();
} catch (\Throwable $e) {
if (defined($rule->uid)) {
$model = new \Models\Rules();
$model->setInvalidByUid($rule->uid);
}
error_log('Failed to execute rule class ' . $rule->uid . ': ' . $e->getMessage());
}
return $executed;
}
public function checkRule(string $ruleUid): array {
$apiKey = $this->getCurrentOperatorApiKeyId();
$model = new \Models\Users();
$users = $model->getAllUsersIdsOrdered($apiKey);
$accounts = [];
foreach ($users as $user) {
$accounts[$user['accountid']] = $user;
}
$accountIds = array_keys($accounts);
$this->buildEvaluationModels($ruleUid);
$targetRule = $this->rulesModel->getRuleWithOperatorValue($ruleUid, $apiKey);
if ($targetRule === [] || !array_key_exists($ruleUid, $this->rulesMap)) {
return [0, []];
}
$results = $this->evaluateRules($accountIds, [$this->rulesMap[$ruleUid]], $apiKey);
$matchingAccountIds = array_keys(array_filter($results, static function ($value): bool {
return $value !== [];
}));
$result = [];
foreach ($matchingAccountIds as $id) {
if (array_key_exists($id, $accounts)) {
$result[$id] = $accounts[$id];
}
}
return [count($accountIds), $result];
}
public function evaluateUser(int $accountId, int $apiKey, bool $preparedModels = false): void {
if (!$preparedModels || !$this->rulesModel) {
$this->buildEvaluationModels();
}
foreach ($this->totalModels as $model) {
$model->updateTotalsByAccountIds([$accountId], $apiKey);
}
$operatorRules = $this->getAllRulesWithOperatorValues($this->rulesModel, $apiKey);
$rules = array_intersect_key($this->rulesMap, $operatorRules);
$result = $this->evaluateRules([$accountId], $rules, $apiKey);
$uids = $result[$accountId];
$details = [];
foreach ($uids as $uid) {
$details[] = ['uid' => $uid, 'score' => $operatorRules[$uid]['value']];
}
$data = [
'score' => $this->normalizeScore($details),
'details' => json_encode($details),
];
$this->userController->updateUserStatus($accountId, $data, $apiKey);
}
public function buildEvaluationModels(?string $uid = null): void {
$this->totalModels = [];
foreach (\Utils\Constants::get('RULES_TOTALS_MODELS') as $className) {
$this->totalModels[] = new $className();
}
$this->contextController = new \Controllers\Admin\Context\Data();
$this->userController = new \Controllers\Admin\User\Data();
$this->rulesModel = new \Models\OperatorsRules();
$rb = new \Ruler\RuleBuilder();
if ($uid) {
$ruleObj = \Utils\RulesClasses::getSingleRuleObject($uid, $rb);
$this->rulesMap = $ruleObj ? [$uid => $ruleObj] : [];
} else {
$this->rulesMap = \Utils\RulesClasses::getAllRulesObjects($rb);
}
}
private function normalizeScore(array $data): int {
$scores = array_column($data, 'score');
$totalScore = max(array_sum($scores), 0);
$filterScores = array_filter($scores, function ($value) {
return $value > 0;
});
$matches = count($filterScores);
return max((int) (99 - ($totalScore * (pow($matches, 1.1) - $matches + 1))), 0);
}
// only valid, not missing, with fitting attributes, returning associative array
private function getAllRulesWithOperatorValues(\Models\OperatorsRules $rulesModel, int $apiKey): array {
$model = new \Models\ApiKeys();
$skipAttributes = $model->getSkipEnrichingAttributes($apiKey);
$rules = $rulesModel->getAllValidRulesByOperator($apiKey);
$results = $this->filterRulesByAttributesAddTypes($rules, $skipAttributes);
return $results;
}
// with fitting attributes and sorted, returning as regular array
private function getAllAttrFilteredRulesByApiKey(int $apiKey): array {
$model = new \Models\ApiKeys();
$skipAttributes = $model->getSkipEnrichingAttributes($apiKey);
$model = new \Models\OperatorsRules();
$rules = $model->getAllRulesByOperator($apiKey);
$results = $this->filterRulesByAttributesAddTypes($rules, $skipAttributes);
usort($results, static function ($a, $b): int {
if ($a['validated'] !== $b['validated']) {
return ($b['validated'] <=> $a['validated']);
}
if ((int) ($a['missing'] === true) !== (int) ($b['missing'] === true)) {
return ((int) $a['missing'] <=> (int) $b['missing']);
}
return $a['uid'] <=> $b['uid'];
});
return $results;
}
// do not filter by attributes if data is needed only for rendering info
public function getAllRulesByApiKey(int $apiKey): array {
$model = new \Models\OperatorsRules();
$rules = $model->getAllRulesByOperator($apiKey);
$results = [];
foreach ($rules as $rule) {
$rule['type'] = \Utils\RulesClasses::getRuleTypeByUid($rule['uid']);
$results[] = $rule;
}
usort($results, static function ($a, $b): int {
if ($a['validated'] !== $b['validated']) {
return ($b['validated'] <=> $a['validated']);
}
if ((int) ($a['missing'] === true) !== (int) ($b['missing'] === true)) {
return ((int) $a['missing'] <=> (int) $b['missing']);
}
return $a['uid'] <=> $b['uid'];
});
return $results;
}
private function filterRulesByAttributesAddTypes(array $rules, array $skipAttributes): array {
$results = [];
foreach ($rules as $id => $row) {
if (!count(array_intersect(json_decode($row['attributes']), $skipAttributes))) {
$row['type'] = \Utils\RulesClasses::getRuleTypeByUid($row['uid']);
$results[$id] = $row;
}
}
return $results;
}
}

View File

@@ -0,0 +1,61 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\Rules;
class Navigation extends \Controllers\Base {
use \Traits\ApiKeys;
use \Traits\Navigation;
public function showIndexPage(): void {
$this->redirectIfUnlogged();
$pageController = new Page();
$this->response = new \Views\Frontend();
$this->response->data = $pageController->getPageParams();
}
public function saveRule(): array {
$params = $this->f3->get('POST');
$key = explode('_', $params['rule']);
$ruleUid = end($key);
$score = $params['value'];
$dataController = new Data();
$dataController->saveUserRule($ruleUid, $score);
return ['success' => true];
}
public function checkRule(): array {
set_time_limit(0);
ini_set('max_execution_time', 0);
$params = $this->f3->get('GET');
$ruleUid = $params['ruleUid'];
$dataController = new Data();
[$allUsersCnt, $users] = $dataController->checkRule($ruleUid);
$proportion = $dataController->getRuleProportion($allUsersCnt, count($users));
$dataController->saveRuleProportion($ruleUid, $proportion);
return [
'users' => array_slice($users, 0, \Utils\Constants::get('RULE_CHECK_USERS_PASSED_TO_CLIENT')),
'count' => count($users),
'proportion' => $proportion,
'proportion_updated_at' => date('Y-m-d H:i:s'),
];
}
}

View File

@@ -0,0 +1,67 @@
<?php
/**
* Tirreno ~ Open source user analytics
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.tirreno.com Tirreno(tm)
*/
namespace Controllers\Admin\Rules;
class Page extends \Controllers\Pages\Base {
use \Traits\ApiKeys;
public $page = 'AdminRules';
public function getPageParams(): array {
$dataController = new Data();
$rules = $dataController->getRulesForLoggedUser();
$searchPlacholder = $this->f3->get('AdminRules_search_placeholder');
$currentOperator = $this->f3->get('CURRENT_USER');
$operatorId = $currentOperator->id;
$ruleValues = [
['value' => -20, 'text' => $this->f3->get('AdminRules_weight_minus20')],
['value' => 0, 'text' => $this->f3->get('AdminRules_weight_0')],
['value' => 10, 'text' => $this->f3->get('AdminRules_weight_10')],
['value' => 20, 'text' => $this->f3->get('AdminRules_weight_20')],
['value' => 70, 'text' => $this->f3->get('AdminRules_weight_70')],
];
$pageParams = [
'LOAD_DATATABLE' => true,
'LOAD_AUTOCOMPLETE' => true,
'HTML_FILE' => 'admin/rules.html',
'JS' => 'admin_rules.js',
'RULE_VALUES' => $ruleValues,
'RULES' => $rules,
'SEARCH_PLACEHOLDER' => $searchPlacholder,
];
if ($this->isPostRequest()) {
$params = $this->f3->get('POST');
$params['id'] = $operatorId;
$operationResponse = $dataController->proceedPostRequest($params);
$pageParams = array_merge($pageParams, $operationResponse);
$pageParams['CMD'] = $params['cmd'];
$pageParams['RULES'] = $dataController->getRulesForLoggedUser();
}
// set api_keys param after proccessing POST request
[$isOwner, $apiKeys] = $dataController->getOperatorApiKeys($operatorId);
$pageParams['IS_OWNER'] = $isOwner;
$pageParams['API_KEYS'] = $apiKeys;
return parent::applyPageParams($pageParams);
}
}

Some files were not shown because too many files have changed in this diff Show More