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:
@@ -0,0 +1,307 @@
|
||||
<?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\User;
|
||||
|
||||
class Data extends \Controllers\Base {
|
||||
use \Traits\ApiKeys;
|
||||
|
||||
public function proceedPostRequest(array $params): array {
|
||||
return match ($params['cmd']) {
|
||||
'riskScore' => $this->recalculateRiskScore($params),
|
||||
'reenrichment' => $this->enrichEntity($params),
|
||||
'delete' => $this->deleteUser($params),
|
||||
default => []
|
||||
};
|
||||
}
|
||||
|
||||
public function recalculateRiskScore(array $params): array {
|
||||
$result = [];
|
||||
set_error_handler([\Utils\ErrorHandler::class, 'exceptionErrorHandler']);
|
||||
|
||||
try {
|
||||
$apiKey = $this->getCurrentOperatorApiKeyId();
|
||||
$userId = (int) $params['accountid'];
|
||||
|
||||
[$score, $rules] = $this->getUserScore($userId, $apiKey);
|
||||
$result = [
|
||||
'SUCCESS_MESSAGE' => $this->f3->get('AdminUser_recalculate_risk_score_success_message'),
|
||||
'score' => $score,
|
||||
'rules' => $rules,
|
||||
];
|
||||
} catch (\ErrorException $e) {
|
||||
$result = ['ERROR_CODE' => \Utils\ErrorCodes::RISK_SCORE_UPDATE_UNKNOWN_ERROR];
|
||||
}
|
||||
|
||||
restore_error_handler();
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
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 deleteUser(array $params): void {
|
||||
$apiKey = $this->getCurrentOperatorApiKeyId();
|
||||
|
||||
if ($apiKey) {
|
||||
$accountId = (int) $params['accountid'];
|
||||
$actionType = new \Type\QueueAccountOperationActionType(\Type\QueueAccountOperationActionType::DELETE);
|
||||
$accountOpQueueModel = new \Models\Queue\AccountOperationQueue($actionType);
|
||||
|
||||
$code = \Utils\ErrorCodes::REST_API_USER_ALREADY_SCHEDULED_FOR_DELETION;
|
||||
if (!$accountOpQueueModel->isInQueue($accountId, $apiKey)) {
|
||||
$code = \Utils\ErrorCodes::REST_API_USER_SUCCESSFULLY_ADDED_FOR_DELETION;
|
||||
$accountOpQueueModel->add($accountId, $apiKey);
|
||||
}
|
||||
|
||||
$this->f3->set('SESSION.extra_message_code', $code);
|
||||
$this->f3->reroute('/id');
|
||||
}
|
||||
}
|
||||
|
||||
public function getUserScoreDetails(int $userId, int $apiKey): array {
|
||||
$model = new \Models\User();
|
||||
$user = $model->getUser($userId, $apiKey);
|
||||
|
||||
return [
|
||||
'score_details' => $model->getApplicableRulesByAccountId($userId, $apiKey, true),
|
||||
'score_calculated' => $user !== [] ? $user['score'] !== null : false,
|
||||
];
|
||||
}
|
||||
|
||||
public function getUserById(int $accountId): array {
|
||||
$apiKey = $this->getCurrentOperatorApiKeyId();
|
||||
|
||||
$model = new \Models\User();
|
||||
$user = $model->getUser($accountId, $apiKey);
|
||||
|
||||
$model = new \Models\Rules();
|
||||
$rules = $model->getAll();
|
||||
|
||||
$details = [];
|
||||
if ($user['score_details']) {
|
||||
$scoreDetails = json_decode($user['score_details'], true);
|
||||
|
||||
foreach ($scoreDetails as $detail) {
|
||||
$score = $detail['score'] ?? null;
|
||||
$ruleUid = $detail['uid'] ?? null;
|
||||
if ($score !== 0 && isset($rules[$ruleUid])) {
|
||||
$item = $rules[$ruleUid];
|
||||
$item['score'] = $score;
|
||||
$details[] = $item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
usort($details, static function ($a, $b): int {
|
||||
return $b['score'] <=> $a['score'];
|
||||
});
|
||||
|
||||
$user['score_details'] = $details;
|
||||
|
||||
$pageTitle = $user['userid'];
|
||||
if ($user['firstname'] !== null && $user['firstname'] !== '') {
|
||||
$pageTitle .= sprintf(' (%s)', $user['firstname']);
|
||||
}
|
||||
if ($user['lastname'] !== null && $user['lastname'] !== '') {
|
||||
$pageTitle .= sprintf(' (%s)', $user['lastname']);
|
||||
}
|
||||
$user['page_title'] = $pageTitle;
|
||||
|
||||
$tsColumns = ['created', 'lastseen', 'score_updated_at', 'latest_decision', 'updated', 'added_to_review'];
|
||||
\Utils\TimeZones::localizeTimestampsForActiveOperator($tsColumns, $user);
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
public function checkIfOperatorHasAccess(int $userId): bool {
|
||||
$apiKey = $this->getCurrentOperatorApiKeyId();
|
||||
$userModel = new \Models\User();
|
||||
|
||||
return $userModel->checkAccess($userId, $apiKey);
|
||||
}
|
||||
|
||||
public function checkEnrichmentAvailability(): bool {
|
||||
return $this->getCurrentOperatorEnrichmentKeyString() !== null;
|
||||
}
|
||||
|
||||
public function addToWatchlist(int $accountId, int $apiKey): void {
|
||||
$model = new \Models\Watchlist();
|
||||
$model->add($accountId, $apiKey);
|
||||
}
|
||||
|
||||
public function removeFromWatchlist(int $accountId, int $apiKey): void {
|
||||
$model = new \Models\Watchlist();
|
||||
$model->remove($accountId, $apiKey);
|
||||
}
|
||||
|
||||
public function addToBlacklistQueue(int $accountId, bool $fraud, int $apiKey): void {
|
||||
$actionType = new \Type\QueueAccountOperationActionType(\Type\QueueAccountOperationActionType::BLACKLIST);
|
||||
$accountOpQueueModel = new \Models\Queue\AccountOperationQueue($actionType);
|
||||
$inQueue = $accountOpQueueModel->isInQueue($accountId, $apiKey);
|
||||
|
||||
if (!$fraud) {
|
||||
$this->setFraudFlag($accountId, false, $apiKey); // Directly remove blacklisted items
|
||||
|
||||
if ($inQueue) {
|
||||
$accountOpQueueModel->removeFromQueue(); // Cancel queued operation
|
||||
}
|
||||
}
|
||||
|
||||
if (!$inQueue && $fraud) {
|
||||
$accountOpQueueModel->add($accountId, $apiKey);
|
||||
}
|
||||
|
||||
$model = new \Models\User();
|
||||
$model->updateFraudFlag([$accountId], $apiKey, $fraud);
|
||||
}
|
||||
|
||||
public function addToCalulcateRiskScoreQueue(int $accountId): void {
|
||||
$apiKey = $this->getCurrentOperatorApiKeyObject();
|
||||
$actionType = new \Type\QueueAccountOperationActionType(\Type\QueueAccountOperationActionType::CALCULATE_RISK_SCORE);
|
||||
$accountOpQueueModel = new \Models\Queue\AccountOperationQueue($actionType);
|
||||
$inQueue = $accountOpQueueModel->isInQueue($accountId, $apiKey->id);
|
||||
|
||||
if (!$inQueue) {
|
||||
$accountOpQueueModel->add($accountId, $apiKey->id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array{accountId: int, key: int}[] $accounts
|
||||
*/
|
||||
public function addBatchToCalulcateRiskScoreQueue(array $accounts): void {
|
||||
$actionType = new \Type\QueueAccountOperationActionType(\Type\QueueAccountOperationActionType::CALCULATE_RISK_SCORE);
|
||||
$accountOpQueueModel = new \Models\Queue\AccountOperationQueue($actionType);
|
||||
|
||||
$accountOpQueueModel->addBatch($accounts);
|
||||
}
|
||||
|
||||
public function setReviewedFlag(int $accountId, bool $reviewed, int $apiKey): void {
|
||||
$model = new \Models\User();
|
||||
$model->updateReviewedFlag($accountId, $apiKey, $reviewed);
|
||||
}
|
||||
|
||||
public function getUserScore(int $accountId, int $apiKey): array {
|
||||
$total = 0;
|
||||
$rules = [];
|
||||
|
||||
$rulesController = new \Controllers\Admin\Rules\Data();
|
||||
$rulesController->evaluateUser($accountId, $apiKey);
|
||||
|
||||
$model = new \Models\User();
|
||||
$rules = $model->getApplicableRulesByAccountId($accountId, $apiKey);
|
||||
|
||||
$total = $rules[0]['total_score'] ?? 0;
|
||||
array_walk($rules, function (&$rule): void {
|
||||
unset($rule['total_score']);
|
||||
}, $rules);
|
||||
|
||||
return [$total, $rules];
|
||||
}
|
||||
|
||||
public function validate(int $accountId, array $params): int|false {
|
||||
$errorCode = \Utils\Access::CSRFTokenValid($params, $this->f3);
|
||||
if ($errorCode) {
|
||||
return $errorCode;
|
||||
}
|
||||
|
||||
$userHasAccess = $this->checkIfOperatorHasAccess($accountId);
|
||||
|
||||
return !$userHasAccess ? \Utils\ErrorCodes::OPERATOR_DOES_NOT_HAVE_ACCESS_TO_ACCOUNT : false;
|
||||
}
|
||||
|
||||
public function getScheduledForDeletion(int $userId): array {
|
||||
$apiKey = $this->getCurrentOperatorApiKeyId();
|
||||
$actionType = new \Type\QueueAccountOperationActionType(\Type\QueueAccountOperationActionType::DELETE);
|
||||
$accountOpQueueModel = new \Models\Queue\AccountOperationQueue($actionType);
|
||||
|
||||
[$scheduled, $status] = $accountOpQueueModel->isInQueueStatus($userId, $apiKey);
|
||||
|
||||
return [$scheduled, ($status === \Type\QueueAccountOperationStatusType::FAILED) ? \Utils\ErrorCodes::USER_DELETION_FAILED : null];
|
||||
}
|
||||
|
||||
public function getScheduledForBlacklist(int $userId): array {
|
||||
$apiKey = $this->getCurrentOperatorApiKeyId();
|
||||
$actionType = new \Type\QueueAccountOperationActionType(\Type\QueueAccountOperationActionType::BLACKLIST);
|
||||
$accountOpQueueModel = new \Models\Queue\AccountOperationQueue($actionType);
|
||||
|
||||
[$scheduled, $status] = $accountOpQueueModel->isInQueueStatus($userId, $apiKey);
|
||||
|
||||
return [$scheduled, ($status === \Type\QueueAccountOperationStatusType::FAILED) ? \Utils\ErrorCodes::USER_BLACKLISTING_FAILED : null];
|
||||
}
|
||||
|
||||
public function setFraudFlag(int $accountId, bool $fraud, int $apiKey): array {
|
||||
$blacklistItemsModel = new \Models\BlacklistItems();
|
||||
|
||||
$ips = $blacklistItemsModel->getIpsRelatedToAccountWithinOperator($accountId, $apiKey);
|
||||
$emails = $blacklistItemsModel->getEmailsRelatedToAccountWithinOperator($accountId, $apiKey);
|
||||
$phones = $blacklistItemsModel->getPhonesRelatedToAccountWithinOperator($accountId, $apiKey);
|
||||
|
||||
$relatedIpsIds = array_column($ips, 'id');
|
||||
$relatedEmailsIds = array_column($emails, 'id');
|
||||
$relatedPhonesIds = array_column($phones, 'id');
|
||||
|
||||
$ips = $blacklistItemsModel->getIpsRelatedToAccountWithinOperator($accountId, $apiKey);
|
||||
$relatedIpsIds = array_column($ips, 'id');
|
||||
if (count($relatedIpsIds) !== 0) {
|
||||
$model = new \Models\Ip();
|
||||
$model->updateFraudFlag($relatedIpsIds, $fraud, $apiKey);
|
||||
}
|
||||
|
||||
$emails = $blacklistItemsModel->getEmailsRelatedToAccountWithinOperator($accountId, $apiKey);
|
||||
$relatedEmailsIds = array_column($emails, 'id');
|
||||
if (count($relatedEmailsIds) !== 0) {
|
||||
$model = new \Models\Email();
|
||||
$model->updateFraudFlag($relatedEmailsIds, $fraud, $apiKey);
|
||||
}
|
||||
|
||||
$phones = $blacklistItemsModel->getPhonesRelatedToAccountWithinOperator($accountId, $apiKey);
|
||||
$relatedPhonesIds = array_column($phones, 'id');
|
||||
if (count($relatedPhonesIds) !== 0) {
|
||||
$model = new \Models\Phone();
|
||||
$model->updateFraudFlag($relatedPhonesIds, $fraud, $apiKey);
|
||||
}
|
||||
|
||||
return array_merge($ips, $emails, $phones);
|
||||
}
|
||||
|
||||
public function updateUserStatus(int $accountId, array $scoreData, int $apiKey): void {
|
||||
$scoreData['addToReview'] = false;
|
||||
|
||||
$keyModel = new \Models\ApiKeys();
|
||||
$keyModel->getKeyById($apiKey);
|
||||
|
||||
$userModel = new \Models\User();
|
||||
|
||||
if ($scoreData['score'] <= $keyModel->blacklist_threshold) {
|
||||
$this->addToBlacklistQueue($accountId, true, $apiKey);
|
||||
} elseif ($scoreData['score'] <= $keyModel->review_queue_threshold) {
|
||||
$data = $userModel->getUser($accountId, $apiKey);
|
||||
$scoreData['addToReview'] = $data['added_to_review'] === null && $data['fraud'] === null;
|
||||
}
|
||||
|
||||
$userModel->updateUserStatus($accountId, $scoreData, $apiKey);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
<?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\User;
|
||||
|
||||
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 manageUser(): array {
|
||||
$params = $this->f3->get('POST');
|
||||
$accountId = $params['userId'] ?? null;
|
||||
|
||||
$dataController = new Data();
|
||||
$errorCode = $dataController->validate($accountId, $params);
|
||||
$successCode = false;
|
||||
|
||||
if (!$errorCode) {
|
||||
$cmd = $params['type'] ?? null;
|
||||
$apiKey = $this->getCurrentOperatorApiKeyId();
|
||||
switch ($cmd) {
|
||||
case 'add':
|
||||
$dataController->addToWatchlist($accountId, $apiKey);
|
||||
$successCode = \Utils\ErrorCodes::USER_HAS_BEEN_SUCCESSFULLY_ADDED_TO_WATCH_LIST;
|
||||
break;
|
||||
|
||||
case 'remove':
|
||||
$dataController->removeFromWatchlist($accountId, $apiKey);
|
||||
$successCode = \Utils\ErrorCodes::USER_HAS_BEEN_SUCCESSFULLY_REMOVED_FROM_WATCH_LIST;
|
||||
break;
|
||||
|
||||
case 'fraud':
|
||||
$dataController->addToBlacklistQueue($accountId, true, $apiKey);
|
||||
$successCode = \Utils\ErrorCodes::USER_FRAUD_FLAG_HAS_BEEN_SET;
|
||||
break;
|
||||
|
||||
case 'legit':
|
||||
$dataController->addToBlacklistQueue($accountId, false, $apiKey);
|
||||
$successCode = \Utils\ErrorCodes::USER_FRAUD_FLAG_HAS_BEEN_UNSET;
|
||||
break;
|
||||
|
||||
case 'reviewed':
|
||||
$dataController->setReviewedFlag($accountId, true, $apiKey);
|
||||
$successCode = \Utils\ErrorCodes::USER_REVIEWED_FLAG_HAS_BEEN_SET;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ['success' => $successCode];
|
||||
}
|
||||
|
||||
public function getUserScoreDetails(): array {
|
||||
$apiKey = $this->getCurrentOperatorApiKeyId();
|
||||
$params = $this->f3->get('GET');
|
||||
$userId = $params['userId'];
|
||||
|
||||
$dataController = new Data();
|
||||
|
||||
return $dataController->getUserScoreDetails($userId, $apiKey);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
<?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\User;
|
||||
|
||||
class Page extends \Controllers\Pages\Base {
|
||||
use \Traits\ApiKeys;
|
||||
|
||||
public $page = 'AdminUser';
|
||||
|
||||
public function getPageParams(): array {
|
||||
$dataController = new Data();
|
||||
$userId = $this->integerParam($this->f3->get('PARAMS.userId'));
|
||||
$hasAccess = $dataController->checkIfOperatorHasAccess($userId);
|
||||
|
||||
if (!$hasAccess) {
|
||||
$this->f3->error(404);
|
||||
}
|
||||
|
||||
[$scheduledForDeletion, $errorCode] = $dataController->getScheduledForDeletion($userId);
|
||||
$user = $dataController->getUserById($userId);
|
||||
|
||||
$pageTitle = $this->getInternalPageTitleWithPostfix($user['page_title']);
|
||||
$enrichmentOn = $dataController->checkEnrichmentAvailability();
|
||||
|
||||
$pageParams = [
|
||||
'LOAD_DATATABLE' => true,
|
||||
'LOAD_JVECTORMAP' => true,
|
||||
'LOAD_ACCEPT_LANGUAGE_PARSER' => true,
|
||||
'HTML_FILE' => 'admin/user.html',
|
||||
'LOAD_UPLOT' => true,
|
||||
'LOAD_AUTOCOMPLETE' => true,
|
||||
'USER' => $user,
|
||||
'SCHEDULED_FOR_DELETION' => $scheduledForDeletion,
|
||||
'PAGE_TITLE' => $pageTitle,
|
||||
'ENRICHMENT' => $enrichmentOn,
|
||||
'JS' => 'admin_user.js',
|
||||
'ERROR_CODE' => $errorCode,
|
||||
];
|
||||
|
||||
if ($this->isPostRequest()) {
|
||||
$params = $this->f3->get('POST');
|
||||
$operationResponse = $dataController->proceedPostRequest($params);
|
||||
|
||||
$pageParams = array_merge($pageParams, $operationResponse);
|
||||
$pageParams['CMD'] = $params['cmd'];
|
||||
// recall user data
|
||||
$pageParams['USER'] = $dataController->getUserById($userId);
|
||||
}
|
||||
|
||||
[$scheduledForBlacklist, $errorCode] = $dataController->getScheduledForBlacklist($userId);
|
||||
if ($scheduledForBlacklist) {
|
||||
$this->f3->set('SESSION.extra_message_code', $errorCode ?? \Utils\ErrorCodes::USER_BLACKLISTING_QUEUED);
|
||||
}
|
||||
|
||||
return parent::applyPageParams($pageParams);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
<?php
|
||||
|
||||
//
|
||||
Reference in New Issue
Block a user