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,78 @@
<?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 Models\Grid\Base;
class Grid extends \Models\BaseSql {
use \Traits\Enrichment\TimeZones;
use \Traits\DateRange;
protected $DB_TABLE_NAME = 'event';
protected $idsModel = null;
protected $apiKey = null;
protected $query = null;
protected function getGrid(?string $ids = null, array $idsParams = []): array {
$this->setIds($ids, $idsParams);
$draw = $this->f3->get('REQUEST.draw');
$draw = $draw ?? 1;
$data = $this->getData();
$total = $this->getTotal();
$params = $this->f3->get('GET');
$dateRange = $this->getDatesRange($params);
return [
'data' => $data,
'draw' => $draw,
'recordsTotal' => $total,
'recordsFiltered' => $total,
'dateRange' => $dateRange,
];
}
public function setIds(?string $ids, array $idsParams): void {
$this->query->setIds($ids, $idsParams);
}
protected function getData(): array {
[$query, $params] = $this->query->getData();
$results = $this->execQuery($query, $params);
$this->convertTimeToUserTimezone($results);
$this->calculateCustomParams($results);
return $results;
}
protected function getTotal(): int {
[$query, $params] = $this->query->getTotal();
$results = $this->execQuery($query, $params);
return $results[0]['count'];
}
protected function convertTimeToUserTimezone(array &$result): void {
$this->translateTimeZones($result);
}
protected function calculateCustomParams(array &$result): void {
}
}

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 Models\Grid\Base;
class Ids extends \Models\BaseSql {
protected $DB_TABLE_NAME = 'event';
private $apiKey = null;
public function __construct(int $apiKey) {
parent::__construct();
$this->apiKey = $apiKey;
}
public function execute(string $query, array $params): array {
$params[':api_key'] = $this->apiKey;
$data = $this->execQuery($query, $params);
$results = array_column($data, 'itemid');
return count($results) ? $results : [-1];
}
}

View File

@@ -0,0 +1,127 @@
<?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 Models\Grid\Base;
class Query {
use \Traits\Debug;
use \Traits\DateRange;
protected $f3 = null;
protected $apiKey = null;
protected $ids = null;
protected $idsParams = [];
protected $itemKey = null;
protected $itemId = null;
protected $defaultOrder = null;
protected $dateRangeField = 'event_country.lastseen';
protected $allowedColumns = [];
public function __construct(int $apiKey) {
$this->f3 = \Base::instance();
$this->apiKey = $apiKey;
}
public function setIds(?string $ids, array $idsParams): void {
$this->ids = $ids;
$this->idsParams = $idsParams;
if (count($this->idsParams)) {
$this->itemKey = array_keys($this->idsParams)[0];
$this->itemId = $this->idsParams[$this->itemKey];
}
}
protected function applyOrder(string &$query): void {
$request = $this->f3->get('REQUEST');
$order = $request['order'] ?? [];
$columns = $request['columns'] ?? [];
$orderCondition = $this->defaultOrder;
if (count($order) && count($columns)) {
$orderClauses = [];
foreach ($order as $orderData) {
$sortDirection = $orderData['dir'] === 'asc' ? 'ASC' : 'DESC';
$columnIndex = $orderData['column'];
$sortColumn = $columns[$columnIndex]['data'];
if (in_array($sortColumn, $this->allowedColumns)) {
$orderClauses[] = sprintf('%s %s', $sortColumn, $sortDirection);
}
}
if (count($orderClauses)) {
$orderCondition = implode(', ', $orderClauses);
}
}
if ($orderCondition) {
$query .= sprintf(' ORDER BY %s', $orderCondition);
}
}
protected function applyDateRange(string &$query, array &$queryParams): void {
$params = $this->f3->get('GET');
$dateRange = $this->getDatesRange($params);
if ($dateRange) {
$searchConditions = (
"AND {$this->dateRangeField} >= :start_time
AND {$this->dateRangeField} <= :end_time
%s"
);
$query = sprintf($query, $searchConditions);
$queryParams[':end_time'] = $dateRange['endDate'];
$queryParams[':start_time'] = $dateRange['startDate'];
}
}
protected function applyLimit(string &$query, array &$queryParams): void {
$request = $this->f3->get('REQUEST');
$start = $request['start'] ?? null;
$length = $request['length'] ?? null;
if (isset($start) && isset($length)) {
$query .= ' LIMIT :length OFFSET :start';
$queryParams[':start'] = $start;
$queryParams[':length'] = $length;
}
}
protected function getQueryParams(): array {
return [':api_key' => $this->apiKey];
}
public function injectIdQuery(string $field, &$params): string {
$idsQuery = $this->ids;
if ($idsQuery === null || $idsQuery === '') {
return '';
}
$idsParams = $this->idsParams;
foreach ($idsParams as $key => $value) {
if (!array_key_exists($key, $params) || $params[$key] === null) {
$params[$key] = $value;
}
}
return " AND $field IN ($idsQuery)";
}
}

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 Models\Grid\Blacklist;
class Grid extends \Models\Grid\Base\Grid {
public function __construct(int $apiKey) {
parent::__construct();
$this->apiKey = $apiKey;
$this->idsModel = new Ids($apiKey);
$this->query = new Query($apiKey);
}
public function getAllBlacklistedItems(): array {
return $this->getGrid();
}
protected function convertTimeToUserTimezone(array &$result): void {
$fields = ['created', 'score_updated_at'];
$this->translateTimeZones($result, $fields);
}
}

View File

@@ -0,0 +1,19 @@
<?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 Models\Grid\Blacklist;
class Ids extends \Models\Grid\Base\Ids {
}

View File

@@ -0,0 +1,234 @@
<?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 Models\Grid\Blacklist;
class Query extends \Models\Grid\Base\Query {
protected $defaultOrder = 'created DESC, type ASC, value ASC';
protected $dateRangeField = 'blacklist.created';
protected $allowedColumns = ['score', 'created', 'type', 'value'];
public function getData(): array {
$queryParams = $this->getQueryParams();
$query = ("
SELECT DISTINCT
blacklist.is_important,
blacklist.accountid,
blacklist.accounttitle,
blacklist.created,
blacklist.score_updated_at,
blacklist.score,
blacklist.account_email AS email,
extra.type,
TRUE AS fraud,
CASE extra.type
WHEN 'ip' THEN blacklist.ip
WHEN 'email' THEN blacklist.email
WHEN 'phone' THEN blacklist.phone
END AS value,
CASE extra.type
WHEN 'ip' THEN blacklist.ip_id
WHEN 'email' THEN blacklist.email_id
WHEN 'phone' THEN blacklist.phone_id
END AS entity_id
FROM
(
SELECT
event_account.is_important,
event_account.id AS accountid,
event_account.userid AS accounttitle,
event_account.latest_decision AS created,
event_account.score_updated_at,
event_account.score,
account_email.email AS account_email,
CASE WHEN event_ip.fraud_detected THEN split_part(event_ip.ip::text, '/', 1) ELSE NULL END AS ip,
CASE WHEN event_ip.fraud_detected THEN event_ip.id ELSE NULL END AS ip_id,
event_ip.fraud_detected AS ip_fraud,
CASE WHEN event_email.fraud_detected THEN event_email.email ELSE NULL END AS email,
CASE WHEN event_email.fraud_detected THEN event_email.id ELSE NULL END AS email_id,
event_email.fraud_detected AS email_fraud,
CASE WHEN event_phone.fraud_detected THEN event_phone.phone_number ELSE NULL END AS phone,
CASE WHEN event_phone.fraud_detected THEN event_phone.id ELSE NULL END AS phone_id,
event_phone.fraud_detected AS phone_fraud
FROM event
LEFT JOIN event_account
ON event_account.id = event.account
LEFT JOIN event_email AS account_email
ON event_account.lastemail = account_email.id
LEFT JOIN event_ip
ON event_ip.id = event.ip
LEFT JOIN event_email
ON event_email.id = event.email
LEFT JOIN event_phone
ON event_phone.id = event.phone
WHERE
event_account.key = :api_key AND
event_account.fraud IS TRUE AND
(
event_email.fraud_detected IS TRUE OR
event_ip.fraud_detected IS TRUE OR
event_phone.fraud_detected IS TRUE
)
) AS blacklist,
LATERAL (
VALUES
(CASE WHEN ip_fraud = true THEN 'ip' END),
(CASE WHEN email_fraud = true THEN 'email' END),
(CASE WHEN phone_fraud = true THEN 'phone' END)
) AS extra(type)
WHERE
extra.type IS NOT NULL
%s
");
$this->applySearch($query, $queryParams);
$this->applyEntityTypes($query, $queryParams);
$this->applyOrder($query);
$this->applyLimit($query, $queryParams);
return [$query, $queryParams];
}
public function getTotal(): array {
$queryParams = $this->getQueryParams();
$query = ("
SELECT COUNT(*)
FROM (
SELECT DISTINCT
blacklist.accountid,
blacklist.accounttitle,
blacklist.created,
extra.type,
CASE extra.type
WHEN 'ip' THEN blacklist.ip
WHEN 'email' THEN blacklist.email
WHEN 'phone' THEN blacklist.phone
END AS value
FROM
(
SELECT
event_account.id AS accountid,
event_account.userid AS accounttitle,
event_account.latest_decision AS created,
CASE WHEN event_ip.fraud_detected THEN split_part(event_ip.ip::text, '/', 1) ELSE NULL END AS ip,
event_ip.fraud_detected AS ip_fraud,
CASE WHEN event_email.fraud_detected THEN event_email.email ELSE NULL END AS email,
event_email.fraud_detected AS email_fraud,
CASE WHEN event_phone.fraud_detected THEN event_phone.phone_number ELSE NULL END AS phone,
event_phone.fraud_detected AS phone_fraud
FROM event
LEFT JOIN event_account
ON event_account.id = event.account
LEFT JOIN event_ip
ON event_ip.id = event.ip
LEFT JOIN event_email
ON event_email.id = event.email
LEFT JOIN event_phone
ON event_phone.id = event.phone
WHERE
event_account.key = :api_key AND
event_account.fraud IS TRUE AND
(
event_email.fraud_detected IS TRUE OR
event_ip.fraud_detected IS TRUE OR
event_phone.fraud_detected IS TRUE
)
) AS blacklist,
LATERAL (
VALUES
(CASE WHEN ip_fraud = true THEN 'ip' END),
(CASE WHEN email_fraud = true THEN 'email' END),
(CASE WHEN phone_fraud = true THEN 'phone' END)
) AS extra(type)
WHERE
extra.type IS NOT NULL
%s
) AS tbl
");
$this->applySearch($query, $queryParams);
$this->applyEntityTypes($query, $queryParams);
return [$query, $queryParams];
}
private function applySearch(string &$query, array &$queryParams): void {
$this->applyDateRange($query, $queryParams);
$searchConditions = '';
$search = $this->f3->get('REQUEST.search');
if (is_array($search) && isset($search['value']) && is_string($search['value']) && $search['value'] !== '') {
$searchConditions .= (
" AND (
LOWER(blacklist.accounttitle) LIKE LOWER(:search_value) OR
LOWER(extra.type) LIKE LOWER(:search_value) OR
LOWER(CASE extra.type
WHEN 'ip' THEN blacklist.ip
WHEN 'email' THEN blacklist.email
WHEN 'phone' THEN blacklist.phone
END) LIKE LOWER(:search_value) OR
TO_CHAR(blacklist.created::timestamp without time zone, 'dd/mm/yyyy hh24:mi:ss') LIKE :search_value
)"
);
$queryParams[':search_value'] = '%' . $search['value'] . '%';
}
//Add search into request
$query = sprintf($query, $searchConditions . ' %s');
}
private function applyEntityTypes(string &$query, array &$queryParams): void {
$searchCondition = '';
$entityTypeIds = $this->f3->get('REQUEST.entityTypeIds');
if ($entityTypeIds !== null && count($entityTypeIds)) {
$clauses = [];
foreach ($entityTypeIds as $key => $entityTypeId) {
$clauses[] = 'extra.type = :entity_type_' . $key;
$queryParams[':entity_type_' . $key] = strtolower(\Utils\Constants::get('ENTITY_TYPES')[$entityTypeId]);
}
$searchCondition = ' AND (' . implode(' OR ', $clauses) . ')';
}
$query = sprintf($query, $searchCondition);
}
}

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 Models\Grid\Bots;
class Grid extends \Models\Grid\Base\Grid {
use \Traits\Enrichment\Devices;
public function __construct(int $apiKey) {
parent::__construct();
$this->apiKey = $apiKey;
$this->idsModel = new Ids($apiKey);
$this->query = new Query($apiKey);
}
public function getAllBots(): array {
return $this->getGrid();
}
protected function calculateCustomParams(array &$result): void {
$this->applyDeviceParams($result);
}
protected function convertTimeToUserTimezone(array &$result): void {
$fields = ['lastseen'];
$this->translateTimeZones($result, $fields);
}
}

View File

@@ -0,0 +1,19 @@
<?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 Models\Grid\Bots;
class Ids extends \Models\Grid\Base\Ids {
}

View File

@@ -0,0 +1,119 @@
<?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 Models\Grid\Bots;
class Query extends \Models\Grid\Base\Query {
protected $defaultOrder = 'ed.lastseen DESC';
protected $dateRangeField = 'ed.lastseen';
protected $allowedColumns = ['id', 'device', 'os_name', 'modified'];
public function getData(): array {
$queryParams = $this->getQueryParams();
$query = (
'SELECT
event_ua_parsed.id,
event_ua_parsed.device,
event_ua_parsed.browser_name,
event_ua_parsed.browser_version,
event_ua_parsed.os_name,
event_ua_parsed.os_version,
event_ua_parsed.ua,
event_ua_parsed.modified,
ed.lastseen
FROM
event_ua_parsed
LEFT JOIN (
SELECT
user_agent,
MAX(lastseen) AS lastseen
FROM event_device
WHERE key = :api_key
GROUP BY user_agent
) AS ed
ON event_ua_parsed.id = ed.user_agent
WHERE
event_ua_parsed.key = :api_key AND
event_ua_parsed.modified IS TRUE
%s'
);
$this->applySearch($query, $queryParams);
$this->applyOrder($query);
$this->applyLimit($query, $queryParams);
return [$query, $queryParams];
}
public function getTotal(): array {
$queryParams = $this->getQueryParams();
$query = (
'SELECT
COUNT(*)
FROM
event_ua_parsed
LEFT JOIN (
SELECT
user_agent,
MAX(lastseen) AS lastseen
FROM event_device
WHERE key = :api_key
GROUP BY user_agent
) AS ed
ON event_ua_parsed.id = ed.user_agent
WHERE
event_ua_parsed.key = :api_key AND
event_ua_parsed.modified IS TRUE
%s'
);
$this->applySearch($query, $queryParams);
return [$query, $queryParams];
}
private function applySearch(string &$query, array &$queryParams): void {
$this->applyDateRange($query, $queryParams);
$searchConditions = '';
$search = $this->f3->get('REQUEST.search');
if (is_array($search) && isset($search['value']) && is_string($search['value']) && $search['value'] !== '') {
$searchConditions = (
' AND
(
event_ua_parsed.device LIKE LOWER(:search_value) OR
event_ua_parsed.browser_name LIKE LOWER(:search_value) OR
event_ua_parsed.os_name LIKE LOWER(:search_value) OR
event_ua_parsed.ua LIKE LOWER(:search_value)
)'
);
$queryParams[':search_value'] = '%' . $search['value'] . '%';
}
//Add search into request
$query = sprintf($query, $searchConditions);
}
}

View File

@@ -0,0 +1,30 @@
<?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 Models\Grid\Countries;
class Grid extends \Models\Grid\Base\Grid {
public function __construct(int $apiKey) {
parent::__construct();
$this->apiKey = $apiKey;
$this->idsModel = new Ids($apiKey);
$this->query = new Query($apiKey);
}
public function getAllCountries(): array {
return $this->getGrid();
}
}

View File

@@ -0,0 +1,19 @@
<?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 Models\Grid\Countries;
class Ids extends \Models\Grid\Base\Ids {
}

View File

@@ -0,0 +1,100 @@
<?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 Models\Grid\Countries;
class Query extends \Models\Grid\Base\Query {
protected $defaultOrder = null;
protected $dateRangeField = 'event_country.lastseen';
protected $allowedColumns = ['full_country', 'country', 'total_account', 'total_visit', 'total_ip', 'id'];
public function getData(): array {
$queryParams = $this->getQueryParams();
$query = (
'SELECT
countries.iso AS country_iso,
countries.id AS country_id,
countries.value AS full_country,
countries.id,
event_country.total_visit,
event_country.total_account,
event_country.total_ip
FROM
event_country
LEFT JOIN countries
ON event_country.country = countries.id
WHERE
event_country.key = :api_key
%s'
);
$this->applySearch($query, $queryParams);
$this->applyOrder($query);
return [$query, $queryParams];
}
public function getTotal(): array {
$queryParams = $this->getQueryParams();
$query = (
'SELECT
COUNT(event_country.id)
FROM
event_country
INNER JOIN countries
ON event_country.country = countries.id
WHERE
event_country.key = :api_key
%s'
);
$this->applySearch($query, $queryParams);
return [$query, $queryParams];
}
private function applySearch(string &$query, array &$queryParams): void {
//Add dates into request
$this->applyDateRange($query, $queryParams);
$search = $this->f3->get('REQUEST.search');
$searchConditions = '';
if (is_array($search) && isset($search['value']) && is_string($search['value']) && $search['value'] !== '') {
$searchConditions .= (
' AND
(
LOWER(countries.value) LIKE LOWER(:search_value)
OR LOWER(countries.iso) LIKE LOWER(:search_value)
)'
);
$queryParams[':search_value'] = '%' . $search['value'] . '%';
}
//Add search and ids into request
$query = sprintf($query, $searchConditions);
}
}

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 Models\Grid\Devices;
class Grid extends \Models\Grid\Base\Grid {
use \Traits\Enrichment\Devices;
public function __construct(int $apiKey) {
parent::__construct();
$this->apiKey = $apiKey;
$this->idsModel = new Ids($apiKey);
$this->query = new Query($apiKey);
}
public function getDevicesByIpId(int $ipId): array {
$params = [':ip_id' => $ipId];
return $this->getGrid($this->idsModel->getDevicesIdsByIpId(), $params);
}
public function getDevicesByUserId(int $userId): array {
$params = [':account_id' => $userId];
return $this->getGrid($this->idsModel->getDevicesIdsByUserId(), $params);
}
public function getDevicesByResourceId(int $resourceId): array {
$params = [':resource_id' => $resourceId];
return $this->getGrid($this->idsModel->getDevicesIdsByResourceId(), $params);
}
public function getAllDevices(): array {
return $this->getGrid();
}
protected function calculateCustomParams(array &$result): void {
$this->applyDeviceParams($result);
}
protected function convertTimeToUserTimezone(array &$result): void {
$fields = ['created'];
$this->translateTimeZones($result, $fields);
}
}

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 Models\Grid\Devices;
class Ids extends \Models\Grid\Base\Ids {
public function getDevicesIdsByIpId(): string {
return (
'SELECT DISTINCT
event.device AS itemid
FROM event
WHERE
event.ip = :ip_id AND
event.key = :api_key'
);
}
public function getDevicesIdsByUserId(): string {
return (
'SELECT DISTINCT
event_device.id AS itemid
FROM event_device
WHERE
event_device.account_id = :account_id AND
event_device.key = :api_key'
);
}
public function getDevicesIdsByResourceId(): string {
return (
'SELECT DISTINCT
event.device AS itemid
FROM event
WHERE
event.url = :resource_id AND
event.key = :api_key'
);
}
}

View File

@@ -0,0 +1,83 @@
<?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 Models\Grid\Devices;
class Query extends \Models\Grid\Base\Query {
protected $defaultOrder = 'event_device.created DESC';
protected $dateRangeField = 'event_device.lastseen';
protected $allowedColumns = ['created', 'device', 'os_name', 'browser_name', 'lang', 'modified', 'id'];
public function getData(): array {
$queryParams = $this->getQueryParams();
$query = (
'SELECT
event_device.id,
event_device.lang,
event_device.created,
event_ua_parsed.device,
event_ua_parsed.browser_name,
event_ua_parsed.browser_version,
event_ua_parsed.os_name,
event_ua_parsed.os_version,
event_ua_parsed.ua,
event_ua_parsed.modified
FROM
event_device
LEFT JOIN event_ua_parsed
ON (event_device.user_agent = event_ua_parsed.id)
WHERE
event_device.key = :api_key
%s'
);
$this->applySearch($query, $queryParams);
$this->applyOrder($query);
$this->applyLimit($query, $queryParams);
return [$query, $queryParams];
}
public function getTotal(): array {
$queryParams = $this->getQueryParams();
$query = (
'SELECT
COUNT(DISTINCT event_device.id)
FROM
event_device
WHERE
event_device.key = :api_key
%s'
);
$this->applySearch($query, $queryParams);
return [$query, $queryParams];
}
private function applySearch(string &$query, array &$queryParams): void {
//$search = $this->f3->get('REQUEST.search');
$searchConditions = $this->injectIdQuery('event_device.id', $queryParams);
//Add ids into request
$query = sprintf($query, $searchConditions);
}
}

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 Models\Grid\Domains;
class Grid extends \Models\Grid\Base\Grid {
public function __construct(int $apiKey) {
parent::__construct();
$this->apiKey = $apiKey;
$this->idsModel = new Ids($apiKey);
$this->query = new Query($apiKey);
}
public function getDomainsBySameIpDomainId(int $domainId): array {
$params = [':domain_id' => $domainId];
return $this->getGrid($this->idsModel->getDomainsIdsBySameIpDomainId(), $params);
}
public function getAllDomains(): array {
return $this->getGrid();
}
}

View File

@@ -0,0 +1,38 @@
<?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 Models\Grid\Domains;
class Ids extends \Models\Grid\Base\Ids {
public function getDomainsIdsBySameIpDomainId(): string {
return (
'SELECT DISTINCT
event_domain.id AS itemid
FROM event_domain
WHERE
event_domain.key = :api_key
AND event_domain.ip = (
SELECT
ip
FROM event_domain
WHERE
event_domain.key = :api_key
AND event_domain.id = :domain_id
LIMIT 1
)
AND event_domain.id != :domain_id'
);
}
}

View File

@@ -0,0 +1,107 @@
<?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 Models\Grid\Domains;
class Query extends \Models\Grid\Base\Query {
protected $defaultOrder = 'event_domain.id DESC';
protected $dateRangeField = 'event_domain.lastseen';
protected $allowedColumns = ['domain', 'free_email_provider', 'tranco_rank',
'disabled', 'disposable_domains', 'creation_date', 'total_account', 'fraud', 'id'];
public function getData(): array {
$queryParams = $this->getQueryParams();
$query = (
'SELECT
event_domain.id,
event_domain.domain,
event_domain.ip,
event_domain.total_account,
event_domain.total_visit,
event_domain.disposable_domains,
event_domain.creation_date,
event_domain.disabled,
event_domain.free_email_provider,
event_domain.tranco_rank,
(
SELECT COUNT(*)
FROM event_email
WHERE
event_email.domain = event_domain.id AND
event_email.key = :api_key AND
event_email.fraud_detected IS TRUE
) AS fraud
FROM
event_domain
WHERE
event_domain.key = :api_key
%s
GROUP BY
event_domain.id'
);
$this->applySearch($query, $queryParams);
$this->applyOrder($query);
$this->applyLimit($query, $queryParams);
return [$query, $queryParams];
}
public function getTotal(): array {
$queryParams = $this->getQueryParams();
$query = (
'SELECT
COUNT (event_domain.id)
FROM
event_domain
WHERE
event_domain.key = :api_key
%s'
);
$this->applySearch($query, $queryParams);
return [$query, $queryParams];
}
private function applySearch(string &$query, array &$queryParams): void {
$this->applyDateRange($query, $queryParams);
$search = $this->f3->get('REQUEST.search');
$searchConditions = $this->injectIdQuery('event_domain.id', $queryParams);
if (isset($search) && $search['value'] !== null) {
$searchConditions .= (
' AND (
LOWER(event_domain.domain) LIKE LOWER(:search_value)
OR TEXT(event_domain.creation_date) LIKE LOWER(:search_value)
)'
);
$queryParams[':search_value'] = '%' . $search['value'] . '%';
}
//Add search and ids into request
$query = sprintf($query, $searchConditions);
}
}

View File

@@ -0,0 +1,44 @@
<?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 Models\Grid\Emails;
class Grid extends \Models\Grid\Base\Grid {
use \Traits\Enrichment\Emails;
public function __construct(int $apiKey) {
parent::__construct();
$this->apiKey = $apiKey;
$this->idsModel = new Ids($apiKey);
$this->query = new Query($apiKey);
}
public function getEmailsByUserId(int $userId): array {
$params = [':account_id' => $userId];
return $this->getGrid($this->idsModel->getEmailsIdsByUserId(), $params);
}
protected function calculateCustomParams(array &$result): void {
$this->calculateEmailReputation($result);
}
protected function convertTimeToUserTimezone(array &$result): void {
$fields = ['lastseen'];
$this->translateTimeZones($result, $fields);
}
}

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 Models\Grid\Emails;
class Ids extends \Models\Grid\Base\Ids {
public function getEmailsIdsByUserId(): string {
return (
'SELECT DISTINCT
event_email.id AS itemid
FROM event_email
WHERE
event_email.key = :api_key AND
event_email.account_id = :account_id'
);
}
}

View File

@@ -0,0 +1,102 @@
<?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 Models\Grid\Emails;
class Query extends \Models\Grid\Base\Query {
protected $defaultOrder = 'event_email.lastseen DESC';
protected $dateRangeField = 'event_email.lastseen';
protected $allowedColumns = ['email', 'reputation', 'free_email_provider', 'data_breach',
'data_breaches', 'disposable_domains', 'blockemails', 'fraud_detected'];
public function getData(): array {
$queryParams = $this->getQueryParams();
$query = (
'SELECT
event_email.id,
event_email.email,
event_email.data_breach,
event_email.data_breaches,
event_email.fraud_detected,
-- event_email.profiles,
event_email.blockemails,
event_email.lastseen,
event_email.alert_list,
event_domain.domain,
event_domain.id AS domain_id,
event_domain.free_email_provider,
event_domain.disposable_domains
FROM
event_email
LEFT JOIN event_domain
ON (event_email.domain = event_domain.id)
WHERE
event_email.key = :api_key
%s'
);
$this->applySearch($query, $queryParams);
$this->applyOrder($query);
$this->applyLimit($query, $queryParams);
return [$query, $queryParams];
}
public function getTotal(): array {
$queryParams = $this->getQueryParams();
$query = (
'SELECT
COUNT(*)
FROM
event_email
WHERE
event_email.key = :api_key
%s'
);
$this->applySearch($query, $queryParams);
return [$query, $queryParams];
}
private function applySearch(string &$query, array &$queryParams): void {
$search = $this->f3->get('REQUEST.search');
$searchConditions = $this->injectIdQuery('event_email.id', $queryParams);
if (is_array($search) && isset($search['value']) && is_string($search['value']) && $search['value'] !== '') {
$searchConditions .= (
' AND
(
event_email.email LIKE :search_value
OR TEXT(event_email.lastseen) LIKE :search_value
)'
);
$queryParams[':search_value'] = '%' . $search['value'] . '%';
}
//Add search and ids into request
$query = sprintf($query, $searchConditions);
}
}

View File

@@ -0,0 +1,86 @@
<?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 Models\Grid\Events;
class Grid extends \Models\Grid\Base\Grid {
use \Traits\Enrichment\Ips;
use \Traits\Enrichment\Devices;
public function __construct(int $apiKey) {
parent::__construct();
$this->apiKey = $apiKey;
$this->idsModel = new Ids($apiKey);
$this->query = new Query($apiKey);
}
public function getEventsByUserId(int $userId): array {
$ids = ['userId' => $userId];
return $this->getGrid(null, $ids);
}
public function getEventsByIspId(int $ispId): array {
$ids = ['ispId' => $ispId];
return $this->getGrid(null, $ids);
}
public function getEventsByDomainId(int $domainId): array {
$ids = ['domainId' => $domainId];
return $this->getGrid(null, $ids);
}
public function getEventsByDeviceId(int $deviceId): array {
$ids = ['deviceId' => $deviceId];
return $this->getGrid(null, $ids);
}
public function getEventsByResourceId(int $resourceId): array {
$ids = ['resourceId' => $resourceId];
return $this->getGrid(null, $ids);
}
public function getEventsByCountryId(int $countryId): array {
$ids = ['countryId' => $countryId];
return $this->getGrid(null, $ids);
}
public function getEventsByIpId(int $ipId): array {
$ids = ['ipId' => $ipId];
return $this->getGrid(null, $ids);
}
public function getAllEvents() {
return $this->getGrid();
}
protected function calculateCustomParams(array &$result): void {
$this->calculateIpType($result);
$this->applyDeviceParams($result);
}
protected function convertTimeToUserTimezone(array &$result): void {
$fields = ['time', 'lastseen', 'session_max_t', 'session_min_t', 'score_updated_at'];
$this->translateTimeZones($result, $fields);
}
}

View File

@@ -0,0 +1,19 @@
<?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 Models\Grid\Events;
class Ids extends \Models\Grid\Base\Ids {
}

View File

@@ -0,0 +1,365 @@
<?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 Models\Grid\Events;
class Query extends \Models\Grid\Base\Query {
protected $defaultOrder = 'event.time DESC, event.id DESC';
protected $dateRangeField = 'event.time';
protected $allowedColumns = ['userid', 'time', 'type', 'ip', 'ip_type', 'device', 'session_id', 'time', 'id'];
public function getData(): array {
$queryParams = $this->getQueryParams();
$query = (
'SELECT
event.id,
event.time,
event_type.value AS event_type,
event_type.name AS event_type_name,
event_account.is_important,
event_account.id AS accountid,
event_account.userid AS accounttitle,
event_account.score_updated_at,
event_account.score,
event_account.fraud,
event_url.url,
event_url.id as url_id,
event_url_query.query,
event_url.title,
event_ip.ip,
event_ip.data_center,
event_ip.vpn,
event_ip.tor,
event_ip.relay,
event_ip.starlink,
event_ip.blocklist,
event_ip.fraud_detected,
event_ip.checked,
event_isp.name AS isp_name,
countries.iso AS country_iso,
countries.id AS country_id,
countries.value AS full_country,
event_ua_parsed.ua,
event_ua_parsed.device,
event_ua_parsed.os_name,
event_email.email,
event.http_code,
event.session_id,
event_session.total_visit AS session_cnt,
event_session.lastseen AS session_max_t,
event_session.created AS session_min_t,
event_session.lastseen - event_session.created AS session_duration
FROM
event
INNER JOIN event_account
ON (event.account = event_account.id)
INNER JOIN event_url
ON (event.url = event_url.id)
FULL OUTER JOIN event_url_query
ON (event.query = event_url_query.id)
LEFT JOIN event_device
ON (event.device = event_device.id)
LEFT JOIN event_type
ON (event.type = event_type.id)
LEFT JOIN event_ua_parsed
ON (event_device.user_agent = event_ua_parsed.id)
LEFT JOIN event_ip
ON (event.ip = event_ip.id)
LEFT JOIN event_isp
ON (event_ip.isp = event_isp.id)
INNER JOIN countries
ON (event_ip.country = countries.id)
LEFT JOIN event_email
ON (event.email = event_email.id)
LEFT JOIN event_session
ON (event.time = event_session.lastseen AND event.session_id = event_session.id)
WHERE
event.key = :api_key
%s'
);
$this->applySearch($query, $queryParams);
$this->applyEventTypes($query, $queryParams);
$this->applyDeviceTypes($query, $queryParams);
$this->applyRules($query, $queryParams);
$this->applyOrder($query);
$this->applyLimit($query, $queryParams);
return [$query, $queryParams];
}
public function getTotal(): array {
$query = null;
$queryParams = $this->getQueryParams();
if ($this->itemId !== null) {
switch ($this->itemKey) {
case 'userId':
$query = 'SELECT total_visit AS count FROM event_account WHERE key = :api_key AND id = :item_id';
break;
case 'ispId':
$query = 'SELECT total_visit AS count FROM event_isp WHERE key = :api_key AND id = :item_id';
break;
case 'domainId':
$query = 'SELECT total_visit AS count FROM event_domain WHERE key = :api_key AND id = :item_id';
break;
case 'resourceId':
$query = 'SELECT total_visit AS count FROM event_url WHERE key = :api_key AND id = :item_id';
break;
case 'countryId':
$query = 'SELECT total_visit AS count FROM event_country WHERE key = :api_key AND country = :item_id';
break;
case 'ipId':
$query = 'SELECT total_visit AS count FROM event_ip WHERE key = :api_key AND id = :item_id';
break;
case 'deviceId':
$query = (
'SELECT
COUNT(event.id) AS count
FROM event
INNER JOIN event_device
ON (event.device = event_device.id)
WHERE
event_device.key = :api_key AND
event_device.user_agent = :item_id'
);
break;
}
}
if (!$query) {
$query = (
'SELECT
COUNT(event.id) AS count
FROM
event
INNER JOIN event_account
ON (event.account = event_account.id)
INNER JOIN event_url
ON (event.url = event_url.id)
INNER JOIN event_ip
ON (event.ip = event_ip.id)
INNER JOIN countries
ON (event_ip.country = countries.id)
LEFT JOIN event_email
ON (event.email = event_email.id)
LEFT JOIN event_device
ON (event.device = event_device.id)
LEFT JOIN event_type
ON (event.type = event_type.id)
LEFT JOIN event_ua_parsed
ON (event_device.user_agent = event_ua_parsed.id)
WHERE
event.key = :api_key
%s'
);
$this->applySearch($query, $queryParams);
$this->applyEventTypes($query, $queryParams);
$this->applyDeviceTypes($query, $queryParams);
$this->applyRules($query, $queryParams);
}
return [$query, $queryParams];
}
private function applySearch(string &$query, array &$queryParams): void {
//Add dates into request
$this->applyDateRange($query, $queryParams);
//Apply itemId into request
$this->applyRelatedToIdSearchConitions($query);
$searchConditions = '';
$search = $this->f3->get('REQUEST.search');
if (is_array($search) && isset($search['value']) && is_string($search['value']) && $search['value'] !== '') {
//TODO: user isIp function here
if (filter_var($search['value'], FILTER_VALIDATE_IP) !== false) {
$searchConditions .= (
' AND
(
event_ip.ip = :search_value
)'
);
$queryParams[':search_value'] = $search['value'];
} else {
// https://stackoverflow.com/a/63701098
$searchConditions .= (
" AND
(
LOWER(event_email.email) LIKE LOWER(:search_value) OR
LOWER(event_account.userid) LIKE LOWER(:search_value) OR
event.http_code::text LIKE LOWER(:search_value) OR
CASE WHEN event.http_code >= 400 THEN
CONCAT('error ', event.http_code)
ELSE
'' END LIKE LOWER(:search_value) OR
TO_CHAR(event.time::timestamp without time zone, 'dd/mm/yyyy hh24:mi:ss') LIKE :search_value
)"
);
$queryParams[':search_value'] = '%' . $search['value'] . '%';
}
}
//Add search and ids into request
$query = sprintf($query, $searchConditions);
}
protected function getQueryParams(): array {
$params = [':api_key' => $this->apiKey];
if ($this->itemId !== null) {
$params[':item_id'] = $this->itemId;
}
return $params;
}
private function applyRelatedToIdSearchConitions(string &$query): void {
$searchConditions = null;
if ($this->itemId !== null) {
switch ($this->itemKey) {
case 'userId':
$searchConditions = ' AND event.account = :item_id %s';
break;
case 'ispId':
$searchConditions = ' AND event_isp.id = :item_id %s';
break;
case 'domainId':
$searchConditions = ' AND event_email.domain = :item_id %s';
break;
case 'resourceId':
$searchConditions = ' AND event.url = :item_id %s';
break;
case 'countryId':
$searchConditions = ' AND countries.id = :item_id %s';
break;
case 'ipId':
$searchConditions = ' AND event_ip.id = :item_id %s';
break;
case 'deviceId':
$searchConditions = ' AND event_ua_parsed.id = :item_id %s';
break;
}
}
//Add search and ids into request
if ($searchConditions !== null) {
$query = sprintf($query, $searchConditions);
}
}
private function applyEventTypes(string &$query, array &$queryParams): void {
$eventTypeIds = $this->f3->get('REQUEST.eventTypeIds');
if ($eventTypeIds === null || !count($eventTypeIds)) {
return;
}
$clauses = [];
foreach ($eventTypeIds as $key => $eventTypeId) {
$clauses[] = 'event.type = :event_type_id_' . $key;
$queryParams[':event_type_id_' . $key] = $eventTypeId;
}
$query .= ' AND (' . implode(' OR ', $clauses) . ')';
}
private function applyDeviceTypes(string &$query, array &$queryParams): void {
$deviceTypes = $this->f3->get('REQUEST.deviceTypes');
if ($deviceTypes === null || !count($deviceTypes)) {
return;
}
$clauses = [];
foreach ($deviceTypes as $key => $deviceType) {
if ($deviceType === 'other') {
$placeholders = [];
foreach (\Utils\Constants::get('DEVICE_TYPES') as $device) {
if ($device !== 'unknown' && $device !== 'other') {
$param = ':device_exclude_' . $device;
$placeholders[] = $param;
$queryParams[$param] = $device;
}
}
$params = implode(', ', $placeholders);
$clauses[] = '(event_ua_parsed.device NOT IN (' . $params . ') AND event_ua_parsed.device IS NOT NULL)';
} elseif ($deviceType === 'unknown') {
$clauses[] = 'event_ua_parsed.device IS NULL';
} else {
$param = ':device_' . $key;
$clauses[] = 'event_ua_parsed.device = ' . $param;
$queryParams[$param] = $deviceType;
}
}
$query .= ' AND (' . implode(' OR ', $clauses) . ')';
}
private function applyRules(string &$query, array &$queryParams): void {
$ruleUids = $this->f3->get('REQUEST.ruleUids');
if ($ruleUids === null) {
return;
}
$uids = [];
foreach ($ruleUids as $ruleUid) {
$uids[] = ['uid' => $ruleUid];
}
$query .= ' AND score_details @> :rules_uids::jsonb';
$queryParams[':rules_uids'] = json_encode($uids);
}
}

View File

@@ -0,0 +1,72 @@
<?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 Models\Grid\Ips;
class Grid extends \Models\Grid\Base\Grid {
use \Traits\Enrichment\Ips;
public function __construct(int $apiKey) {
parent::__construct();
$this->apiKey = $apiKey;
$this->idsModel = new Ids($apiKey);
$this->query = new Query($apiKey);
}
public function getIpsByUserId(int $userId): array {
$params = [':account_id' => $userId];
return $this->getGrid($this->idsModel->getIpsIdsByUserId(), $params);
}
public function getIpsByIspId(int $ispId): array {
$params = [':isp_id' => $ispId];
return $this->getGrid($this->idsModel->getIpsIdsByIspId(), $params);
}
public function getIpsByDomainId($domainId) {
$params = [':domain_id' => $domainId];
return $this->getGrid($this->idsModel->getIpsIdsByDomainId(), $params);
}
public function getIpsByCountryId(int $countryId): array {
$params = [':country_id' => $countryId];
return $this->getGrid($this->idsModel->getIpsIdsByCountryId(), $params);
}
public function getIpsByDeviceId(int $deviceId): array {
$params = [':device_id' => $deviceId];
return $this->getGrid($this->idsModel->getIpsIdsByDeviceId(), $params);
}
public function getIpsByResourceId(int $resourceId): array {
$params = [':resource_id' => $resourceId];
return $this->getGrid($this->idsModel->getIpsIdsByResourceId(), $params);
}
public function getAllIps() {
return $this->getGrid();
}
protected function calculateCustomParams(array &$result): void {
$this->calculateIpType($result);
}
}

View File

@@ -0,0 +1,88 @@
<?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 Models\Grid\Ips;
class Ids extends \Models\Grid\Base\Ids {
public function getIpsIdsByUserId(): string {
return (
'SELECT DISTINCT
event.ip AS itemid
FROM event
WHERE
event.key = :api_key
AND event.account = :account_id'
);
}
public function getIpsIdsByIspId(): string {
return (
'SELECT DISTINCT
event_ip.id AS itemid
FROM event_ip
WHERE
event_ip.key = :api_key
AND event_ip.isp = :isp_id'
);
}
public function getIpsIdsByDomainId(): string {
return (
'SELECT DISTINCT
event.ip AS itemid
FROM event
LEFT JOIN event_email
ON (event.email = event_email.id)
WHERE
event_email.key = :api_key
AND event_email.domain = :domain_id'
);
}
public function getIpsIdsByCountryId(): string {
return (
'SELECT DISTINCT
event_ip.id AS itemid
FROM event_ip
WHERE
event_ip.key = :api_key AND
event_ip.country = :country_id'
);
}
public function getIpsIdsByDeviceId(): string {
return (
'SELECT DISTINCT
event.ip AS itemid
FROM event
INNER JOIN event_device
ON (event.device = event_device.id)
WHERE
event_device.user_agent = :device_id AND
event_device.key = :api_key'
);
}
public function getIpsIdsByResourceId(): string {
return (
'SELECT DISTINCT
event.ip AS itemid
FROM event
WHERE
event.url = :resource_id AND
event.key = :api_key'
);
}
}

View File

@@ -0,0 +1,168 @@
<?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 Models\Grid\Ips;
class Query extends \Models\Grid\Base\Query {
protected $defaultOrder = 'event_ip.lastseen DESC';
protected $dateRangeField = 'event_ip.lastseen';
protected $allowedColumns = ['ip', 'full_country', 'asn', 'netname', 'ip_type', 'total_visit', 'total_account', 'lastseen', 'id'];
public function getData(): array {
$queryParams = $this->getQueryParams();
$query = (
'SELECT
event_ip.id,
event_ip.ip,
event_ip.fraud_detected,
event_ip.alert_list,
event_ip.data_center,
event_ip.vpn,
event_ip.tor,
event_ip.relay,
event_ip.blocklist,
event_ip.starlink,
event_ip.shared AS total_account,
event_ip.total_visit,
event_ip.checked,
event_ip.lastseen AS lastseen,
event_isp.name AS netname,
event_isp.description,
event_isp.asn,
countries.id AS country_id,
countries.iso AS country_iso,
countries.value AS full_country
FROM
event_ip
LEFT JOIN countries
ON (event_ip.country = countries.id)
LEFT JOIN event_isp
ON (event_ip.isp = event_isp.id)
WHERE
event_ip.key = :api_key
%s'
);
$this->applySearch($query, $queryParams);
$this->applyIpTypes($query);
$this->applyOrder($query);
$this->applyLimit($query, $queryParams);
return [$query, $queryParams];
}
public function getTotal(): array {
$queryParams = $this->getQueryParams();
$query = (
'SELECT
COUNT (DISTINCT event_ip.ip)
FROM
event_ip
LEFT JOIN countries
ON (event_ip.country = countries.id)
LEFT JOIN event_isp
ON (event_ip.isp = event_isp.id)
WHERE
event_ip.key = :api_key
%s'
);
$this->applySearch($query, $queryParams);
$this->applyIpTypes($query);
return [$query, $queryParams];
}
private function applySearch(string &$query, array &$queryParams): void {
$this->applyDateRange($query, $queryParams);
$search = $this->f3->get('REQUEST.search');
$searchConditions = $this->injectIdQuery('event_ip.id', $queryParams);
if (is_array($search) && isset($search['value']) && is_string($search['value']) && $search['value'] !== '') {
$searchConditions .= (
' AND
(
TEXT(event_ip.ip) LIKE LOWER(:search_value)
OR LOWER(event_isp.asn::text) LIKE LOWER(:search_value)
OR LOWER(event_isp.name) LIKE LOWER(:search_value)
OR LOWER(countries.value) LIKE LOWER(:search_value)
OR LOWER(countries.iso) LIKE LOWER(:search_value)
)'
);
$queryParams[':search_value'] = '%' . $search['value'] . '%';
}
//Add search and ids into request
$query = sprintf($query, $searchConditions);
}
private function applyIpTypes(string &$query): void {
$ipTypeIds = $this->f3->get('REQUEST.ipTypeIds');
if ($ipTypeIds === null) {
return;
}
foreach ($ipTypeIds as $ipTypeId) {
switch ($ipTypeId) {
case 0:
$query .= ' AND fraud_detected IS TRUE ';
break;
case 1:
$query .= ' AND blocklist IS TRUE ';
break;
case 2:
$query .= ' AND countries.id = 0 AND event_ip.checked IS TRUE ';
break;
case 3:
$query .= ' AND tor IS TRUE ';
break;
case 4:
$query .= ' AND starlink IS TRUE ';
break;
case 5:
$query .= ' AND relay IS TRUE ';
break;
case 6:
$query .= ' AND vpn IS TRUE ';
break;
case 7:
$query .= ' AND data_center IS TRUE ';
break;
case 8:
$query .= ' AND (event_ip.checked IS FALSE OR event_ip.checked IS NULL) ';
break;
case 9:
$query .= ' AND (tor IS FALSE AND vpn IS FALSE AND relay IS FALSE AND data_center IS FALSE AND event_ip.checked IS TRUE) ';
break;
}
}
}
}

View File

@@ -0,0 +1,54 @@
<?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 Models\Grid\Isps;
class Grid extends \Models\Grid\Base\Grid {
public function __construct(int $apiKey) {
parent::__construct();
$this->apiKey = $apiKey;
$this->idsModel = new Ids($apiKey);
$this->query = new Query($apiKey);
}
public function getIspsByUserId(int $userId): array {
$params = [':account_id' => $userId];
return $this->getGrid($this->idsModel->getIspsIdsByUserId(), $params);
}
public function getIspsByDomainId(int $domainId): array {
$params = [':domain_id' => $domainId];
return $this->getGrid($this->idsModel->getIspsIdsByDomainId(), $params);
}
public function getIspsByCountryId(int $countryId): array {
$params = [':country_id' => $countryId];
return $this->getGrid($this->idsModel->getIspsIdsByCountryId(), $params);
}
public function getIspsByResourceId(int $resourceId): array {
$params = [':resource_id' => $resourceId];
return $this->getGrid($this->idsModel->getIspsIdsByResourceId(), $params);
}
public function getAllIsps(): array {
return $this->getGrid();
}
}

View File

@@ -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 Models\Grid\Isps;
class Ids extends \Models\Grid\Base\Ids {
public function getIspsIdsByUserId(): string {
return (
'SELECT DISTINCT
event_ip.isp AS itemid
FROM event_ip
INNER JOIN event
ON (event_ip.id = event.ip)
WHERE
event_ip.key = :api_key AND
event.account = :account_id'
);
}
public function getIspsIdsByDomainId(): string {
return (
'SELECT DISTINCT
event_ip.isp AS itemid
FROM event
INNER JOIN event_ip
ON (event.ip = event_ip.id)
LEFT JOIN event_email
ON (event.email = event_email.id)
WHERE
event_email.key = :api_key AND
event_email.domain = :domain_id'
);
}
public function getIspsIdsByCountryId(): string {
return (
'SELECT DISTINCT
event_ip.isp AS itemid
FROM event_ip
WHERE
event_ip.key = :api_key AND
event_ip.country = :country_id'
);
}
public function getIspsIdsByResourceId(): string {
return (
'SELECT DISTINCT
event_ip.isp AS itemid
FROM event
INNER JOIN event_ip
ON (event.ip = event_ip.id)
WHERE
event.url = :resource_id AND
event.key = :api_key'
);
}
}

View File

@@ -0,0 +1,118 @@
<?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 Models\Grid\Isps;
class Query extends \Models\Grid\Base\Query {
protected $defaultOrder = 'event_isp.id DESC';
protected $dateRangeField = 'event_isp.lastseen';
protected $allowedColumns = ['asn', 'name', 'total_visit', 'total_ip', 'total_account', 'fraud', 'id'];
public function getData(): array {
$queryParams = $this->getQueryParams();
$query = (
'SELECT
event_isp.id,
event_isp.asn,
event_isp.name,
-- event_isp.description,
event_isp.total_visit,
event_isp.total_account,
(
SELECT COUNT(DISTINCT event.account)
FROM event
LEFT JOIN event_ip ON event.ip = event_ip.id
LEFT JOIN event_account ON event.account = event_account.id
WHERE
event_ip.isp = event_isp.id AND
event.key = :api_key AND
event_account.fraud IS TRUE
) AS fraud,
(
SELECT
COUNT ( DISTINCT eip.ip )
FROM
event_ip AS eip
WHERE
eip.isp = event_isp.id
AND eip.key = event_isp.key
AND eip.isp IS NOT NULL
) AS total_ip
FROM
event_isp
WHERE
event_isp.key = :api_key
%s
GROUP BY
event_isp.id'
);
$this->applySearch($query, $queryParams);
$this->applyOrder($query);
$this->applyLimit($query, $queryParams);
return [$query, $queryParams];
}
public function getTotal(): array {
$queryParams = $this->getQueryParams();
$query = (
'SELECT
COUNT (event_isp.id)
FROM
event_isp
WHERE
event_isp.key = :api_key
%s'
);
$this->applySearch($query, $queryParams);
return [$query, $queryParams];
}
private function applySearch(string &$query, array &$queryParams): void {
$this->applyDateRange($query, $queryParams);
$search = $this->f3->get('REQUEST.search');
$searchConditions = $this->injectIdQuery('event_isp.id', $queryParams);
if (is_array($search) && isset($search['value']) && is_string($search['value']) && $search['value'] !== '') {
$searchConditions .= (
' AND
(
LOWER(event_isp.asn::text) LIKE LOWER(:search_value)
OR LOWER(event_isp.name) LIKE LOWER(:search_value)
OR LOWER(event_isp.description) LIKE LOWER(:search_value)
)'
);
$queryParams[':search_value'] = '%' . $search['value'] . '%';
}
//Add search and ids into request
$query = sprintf($query, $searchConditions);
}
}

View File

@@ -0,0 +1,30 @@
<?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 Models\Grid\Logbook;
class Grid extends \Models\Grid\Base\Grid {
public function __construct(int $apiKey) {
parent::__construct();
$this->apiKey = $apiKey;
$this->idsModel = new Ids($apiKey);
$this->query = new Query($apiKey);
}
public function getAllLogbookEvents() {
return $this->getGrid();
}
}

View File

@@ -0,0 +1,19 @@
<?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 Models\Grid\Logbook;
class Ids extends \Models\Grid\Base\Ids {
}

View File

@@ -0,0 +1,110 @@
<?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 Models\Grid\Logbook;
class Query extends \Models\Grid\Base\Query {
protected $defaultOrder = 'event_logbook.error_type DESC, event_logbook.id DESC';
protected $dateRangeField = 'event_logbook.started';
protected $allowedColumns = ['ip', 'started', 'error_type', 'error_text'];
public function getData(): array {
$queryParams = $this->getQueryParams();
$query = (
'SELECT
event_logbook.id,
event_logbook.ip,
event_logbook.error_type,
event_logbook.error_text,
event_logbook.raw,
event_logbook.started,
event_error_type.name AS error_name,
event_error_type.value AS error_value
FROM
event_logbook
LEFT JOIN event_error_type
ON (event_logbook.error_type = event_error_type.id)
WHERE
event_logbook.key = :api_key
%s'
);
$this->applySearch($query, $queryParams);
$this->applyOrder($query);
$this->applyLimit($query, $queryParams);
return [$query, $queryParams];
}
public function getTotal(): array {
$queryParams = $this->getQueryParams();
$query = (
'SELECT
COUNT(event_logbook.id) AS count
FROM
event_logbook
LEFT JOIN event_error_type
ON (event_logbook.error_type = event_error_type.id)
WHERE
event_logbook.key = :api_key
%s'
);
$this->applySearch($query, $queryParams);
return [$query, $queryParams];
}
private function applySearch(string &$query, array &$queryParams): void {
//Add dates into request
$this->applyDateRange($query, $queryParams);
$search = $this->f3->get('REQUEST.search');
$searchConditions = '';
if (is_array($search) && isset($search['value']) && is_string($search['value']) && $search['value'] !== '') {
$extra = '';
//TODO: use isIp function here
if (filter_var($search['value'], FILTER_VALIDATE_IP) !== false) {
$extra = ' event_logbook.ip = :search_ip_value OR ';
$queryParams[':search_ip_value'] = $search['value'];
}
$searchConditions .= (
" AND
(
$extra
LOWER(event_logbook.raw::text) LIKE LOWER(:search_value) OR
LOWER(event_logbook.error_text) LIKE LOWER(:search_value) OR
LOWER(event_error_type.name) LIKE LOWER(:search_value)
)"
);
$queryParams[':search_value'] = '%' . $search['value'] . '%';
}
//Add search and ids into request
$query = sprintf($query, $searchConditions);
}
}

View File

@@ -0,0 +1,38 @@
<?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 Models\Grid\Payloads\FieldAuditTrail;
class Grid extends \Models\Grid\Base\Grid {
public function __construct(int $apiKey) {
parent::__construct();
$this->apiKey = $apiKey;
$this->idsModel = new Ids($apiKey);
$this->query = new Query($apiKey);
}
public function getDataByUserId(int $userId): array {
$params = [':account_id' => $userId];
return $this->getGrid($this->idsModel->getDataIdsByUserId(), $params);
}
protected function convertTimeToUserTimezone(array &$result): void {
$fields = ['created'];
$this->translateTimeZones($result, $fields);
}
}

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 Models\Grid\Payloads\FieldAuditTrail;
class Ids extends \Models\Grid\Base\Ids {
public function getDataIdsByUserId(): string {
return (
'SELECT
event_field_audit_trail.id AS itemid
FROM event_field_audit_trail
WHERE
event_field_audit_trail.key = :api_key AND
event_field_audit_trail.account_id = :account_id'
);
}
}

View File

@@ -0,0 +1,80 @@
<?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 Models\Grid\Payloads\FieldAuditTrail;
class Query extends \Models\Grid\Base\Query {
protected $defaultOrder = 'event_field_audit_trail.id DESC';
protected $dateRangeField = 'event_field_audit_trail.created';
protected $allowedColumns = ['id', 'created'];
public function getData(): array {
$queryParams = $this->getQueryParams();
$query = (
'SELECT
event_field_audit_trail.id,
event_field_audit_trail.created,
event_field_audit_trail.event_id,
event_field_audit_trail.field_id,
event_field_audit_trail.field_name,
event_field_audit_trail.old_value,
event_field_audit_trail.new_value,
event_field_audit_trail.parent_id,
event_field_audit_trail.parent_name
FROM
event_field_audit_trail
WHERE
event_field_audit_trail.key = :api_key
%s'
);
$this->applySearch($query, $queryParams);
$this->applyOrder($query);
$this->applyLimit($query, $queryParams);
return [$query, $queryParams];
}
public function getTotal(): array {
$queryParams = $this->getQueryParams();
$query = (
'SELECT
COUNT(*)
FROM
event_field_audit_trail
WHERE
event_field_audit_trail.key = :api_key
%s'
);
$this->applySearch($query, $queryParams);
return [$query, $queryParams];
}
private function applySearch(string &$query, array &$queryParams): void {
$searchConditions = $this->injectIdQuery('event_field_audit_trail.id', $queryParams);
//Add ids into request
$query = sprintf($query, $searchConditions);
}
}

View File

@@ -0,0 +1,38 @@
<?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 Models\Grid\Phones;
class Grid extends \Models\Grid\Base\Grid {
public function __construct(int $apiKey) {
parent::__construct();
$this->apiKey = $apiKey;
$this->idsModel = new Ids($apiKey);
$this->query = new Query($apiKey);
}
public function getPhonesByUserId(int $userId): array {
$params = [':account_id' => $userId];
return $this->getGrid($this->idsModel->getPhonesIdsByUserId(), $params);
}
protected function convertTimeToUserTimezone(array &$result): void {
$fields = ['lastseen'];
$this->translateTimeZones($result, $fields);
}
}

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 Models\Grid\Phones;
class Ids extends \Models\Grid\Base\Ids {
public function getPhonesIdsByUserId(): string {
return (
'SELECT DISTINCT
event_phone.id AS itemid
FROM event_phone
WHERE
event_phone.key = :api_key AND
event_phone.account_id = :account_id'
);
}
}

View File

@@ -0,0 +1,100 @@
<?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 Models\Grid\Phones;
class Query extends \Models\Grid\Base\Query {
protected $defaultOrder = 'event_phone.lastseen DESC';
protected $dateRangeField = 'event_phone.lastseen';
protected $allowedColumns = ['phonenumber', 'invalid', 'full_country', 'carrier_name', 'type', 'shared', 'fraud_detected'];
public function getData(): array {
$queryParams = $this->getQueryParams();
$query = (
'SELECT
event_phone.id,
event_phone.phone_number as phonenumber,
event_phone.type,
event_phone.carrier_name,
event_phone.lastseen,
event_phone.invalid,
event_phone.shared,
event_phone.alert_list,
event_phone.fraud_detected,
countries.id AS country_id,
countries.iso AS country_iso,
countries.value AS full_country
FROM
event_phone
LEFT JOIN countries
ON (event_phone.country_code = countries.id)
WHERE
event_phone.key = :api_key
%s'
);
$this->applySearch($query, $queryParams);
$this->applyOrder($query);
$this->applyLimit($query, $queryParams);
return [$query, $queryParams];
}
public function getTotal(): array {
$queryParams = $this->getQueryParams();
$query = (
'SELECT
COUNT(*)
FROM
event_phone
WHERE
event_phone.key = :api_key
%s'
);
$this->applySearch($query, $queryParams);
return [$query, $queryParams];
}
private function applySearch(string &$query, array &$queryParams): void {
$search = $this->f3->get('REQUEST.search');
$searchConditions = $this->injectIdQuery('event_phone.id', $queryParams);
if (is_array($search) && isset($search['value']) && is_string($search['value']) && $search['value'] !== '') {
$searchConditions .= (
' AND
(
event_phone.phone_number LIKE :search_value
OR TEXT(event_phone.lastseen) LIKE :search_value
)'
);
$queryParams[':search_value'] = '%' . $search['value'] . '%';
}
//Add search and ids into request
$query = sprintf($query, $searchConditions);
}
}

View File

@@ -0,0 +1,57 @@
<?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 Models\Grid\Resources;
class Grid extends \Models\Grid\Base\Grid {
public function __construct(int $apiKey) {
parent::__construct();
$this->apiKey = $apiKey;
$this->idsModel = new Ids($apiKey);
$this->query = new Query($apiKey);
}
public function getAllResources(): array {
$data = $this->getGrid();
if (isset($data['data'])) {
$data['data'] = $this->extendWithSuspiciousUrl($data['data']);
}
return $data;
}
private function extendWithSuspiciousUrl(array $result): array {
if (is_array($result) && count($result)) {
$suspiciousUrlWords = \Utils\WordsLists\Url::getWords();
foreach ($result as &$record) {
$record['suspicious'] = $this->isUrlSuspicious($suspiciousUrlWords, $record['url']);
}
unset($record);
}
return $result;
}
private function isUrlSuspicious(array $substrings, string $url): bool {
foreach ($substrings as $sub) {
if (stripos($url, $sub) !== false) {
return true;
}
}
return false;
}
}

View File

@@ -0,0 +1,19 @@
<?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 Models\Grid\Resources;
class Ids extends \Models\Grid\Base\Ids {
}

View File

@@ -0,0 +1,96 @@
<?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 Models\Grid\Resources;
class Query extends \Models\Grid\Base\Query {
protected $defaultOrder = 'event_url.id DESC';
protected $dateRangeField = 'event_url.lastseen';
protected $allowedColumns = ['title', 'http_code', 'total_account', 'total_country', 'total_ip', 'total_visit', 'id'];
public function getData(): array {
$queryParams = $this->getQueryParams();
$query = (
'SELECT
event_url.id,
event_url.id AS url_id,
event_url.key,
event_url.url,
event_url.title,
event_url.http_code,
event_url.total_visit,
event_url.total_ip,
event_url.total_account,
event_url.total_country
FROM
event_url
WHERE
event_url.key = :api_key
%s'
);
$this->applySearch($query, $queryParams);
$this->applyOrder($query);
$this->applyLimit($query, $queryParams);
return [$query, $queryParams];
}
public function getTotal(): array {
$queryParams = $this->getQueryParams();
$query = (
'SELECT
COUNT(event_url.id)
FROM
event_url
WHERE
event_url.key = :api_key
%s'
);
$this->applySearch($query, $queryParams);
return [$query, $queryParams];
}
private function applySearch(string &$query, array &$queryParams): void {
$this->applyDateRange($query, $queryParams);
$search = $this->f3->get('REQUEST.search');
$searchConditions = $this->injectIdQuery('event_url.id', $queryParams);
if (is_array($search) && isset($search['value']) && is_string($search['value']) && $search['value'] !== '') {
$searchConditions .= (
' AND
(
LOWER(event_url.title) LIKE LOWER(:search_value)
OR LOWER(event_url.url) LIKE LOWER(:search_value)
)'
);
$queryParams[':search_value'] = '%' . $search['value'] . '%';
}
//Add search and ids into request
$query = sprintf($query, $searchConditions);
}
}

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 Models\Grid\ReviewQueue;
class Grid extends \Models\Grid\Base\Grid {
public function __construct(int $apiKey) {
parent::__construct();
$this->apiKey = $apiKey;
$this->idsModel = new Ids($apiKey);
$this->query = new Query($apiKey);
}
public function getAllUnderReviewUsers(): array {
return $this->getGrid();
}
public function getTotalUnderReviewUsers(): int {
return $this->getTotal();
}
public function getTotalUnderReviewUsersOverall(): int {
[$query, $params] = $this->query->getTotalOverall();
$results = $this->execQuery($query, $params);
return $results[0]['count'];
}
protected function convertTimeToUserTimezone(array &$result): void {
$fields = ['lastseen', 'created', 'score_updated_at', 'added_to_review'];
$this->translateTimeZones($result, $fields);
}
}

View File

@@ -0,0 +1,19 @@
<?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 Models\Grid\ReviewQueue;
class Ids extends \Models\Grid\Base\Ids {
}

View File

@@ -0,0 +1,152 @@
<?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 Models\Grid\ReviewQueue;
class Query extends \Models\Grid\Base\Query {
protected $defaultOrder = null;
protected $dateRangeField = 'event_account.added_to_review';
protected $allowedColumns = ['score', 'lastseen', 'firstname', 'lastname', 'created', 'added_to_review'];
public function getData(): array {
$queryParams = $this->getQueryParams();
$query = (
'SELECT
event_account.id AS accountid,
event_account.userid AS accounttitle,
event_account.created AS created,
event_account.is_important,
event_account.score_updated_at,
event_account.score,
event_account.firstname,
event_account.lastname,
event_account.lastseen,
event_account.added_to_review,
event_email.email
FROM
event_account
LEFT JOIN event_email
ON (event_account.lastemail = event_email.id)
WHERE
event_account.key = :api_key AND
event_account.fraud IS NULL AND
event_account.added_to_review IS NOT NULL
%s'
);
$this->applySearch($query, $queryParams);
$this->applyRules($query, $queryParams);
$this->applyOrder($query);
$this->applyLimit($query, $queryParams);
return [$query, $queryParams];
}
public function getTotal(): array {
$queryParams = $this->getQueryParams();
$query = (
'SELECT
COUNT (event_account.id)
FROM
event_account
LEFT JOIN event_email
ON (event_account.lastemail = event_email.id)
WHERE
event_account.key = :api_key AND
event_account.fraud IS NULL AND
event_account.added_to_review IS NOT NULL
%s'
);
$this->applySearch($query, $queryParams);
$this->applyRules($query, $queryParams);
return [$query, $queryParams];
}
public function getTotalOverall(): array {
$queryParams = $this->getQueryParams();
$query = (
'SELECT
COUNT(event_account.id) AS count
FROM
event_account
WHERE
event_account.key = :api_key AND
event_account.fraud IS NULL AND
event_account.added_to_review IS NOT NULL'
);
return [$query, $queryParams];
}
private function applySearch(string &$query, array &$queryParams): void {
$this->applyDateRange($query, $queryParams);
$searchConditions = '';
$search = $this->f3->get('REQUEST.search');
if (is_array($search) && isset($search['value']) && is_string($search['value']) && $search['value'] !== '') {
$searchConditions .= (
" AND
(
LOWER(REPLACE(
COALESCE(event_account.firstname, '') ||
COALESCE(event_account.lastname, '') ||
COALESCE(event_account.firstname, ''),
' ', '')) LIKE LOWER(REPLACE(:search_value, ' ', '')) OR
LOWER(event_email.email) LIKE LOWER(:search_value) OR
LOWER(event_account.userid) LIKE LOWER(:search_value) OR
TO_CHAR(event_account.lastseen::timestamp without time zone, 'dd/mm/yyyy hh24:mi:ss') LIKE :search_value OR
TO_CHAR(event_account.created::timestamp without time zone, 'dd/mm/yyyy hh24:mi:ss') LIKE :search_value
)"
);
$queryParams[':search_value'] = '%' . $search['value'] . '%';
}
//Add search and ids into request
$query = sprintf($query, $searchConditions);
}
private function applyRules(string &$query, array &$queryParams): void {
$ruleUids = $this->f3->get('REQUEST.ruleUids');
if ($ruleUids === null) {
return;
}
$uids = [];
foreach ($ruleUids as $ruleUid) {
$uids[] = ['uid' => $ruleUid];
}
$query .= ' AND score_details @> :rules_uids::jsonb';
$queryParams[':rules_uids'] = json_encode($uids);
}
}

View File

@@ -0,0 +1,72 @@
<?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 Models\Grid\Users;
class Grid extends \Models\Grid\Base\Grid {
public function __construct(int $apiKey) {
parent::__construct();
$this->apiKey = $apiKey;
$this->idsModel = new Ids($apiKey);
$this->query = new Query($apiKey);
}
public function getUsersByIpId(int $ipId): array {
$params = [':ip_id' => $ipId];
return $this->getGrid($this->idsModel->getUsersIdsByIpId(), $params);
}
public function getUsersByIspId(int $ispId): array {
$params = [':isp_id' => $ispId];
return $this->getGrid($this->idsModel->getUsersIdsByIspId(), $params);
}
public function getUsersByDomainId(int $domainId): array {
$params = [':domain_id' => $domainId];
return $this->getGrid($this->idsModel->getUsersIdsByDomainId(), $params);
}
public function getUsersByCountryId(int $countryId): array {
$params = [':country_id' => $countryId];
return $this->getGrid($this->idsModel->getUsersIdsByCountryId(), $params);
}
public function getUsersByDeviceId(int $deviceId): array {
$params = [':device_id' => $deviceId];
return $this->getGrid($this->idsModel->getUsersIdsByDeviceId(), $params);
}
public function getUsersByResourceId(int $resourceId): array {
$params = [':resource_id' => $resourceId];
return $this->getGrid($this->idsModel->getUsersIdsByResourceId(), $params);
}
public function getAllUsers(): array {
return $this->getGrid();
}
protected function convertTimeToUserTimezone(array &$result): void {
$fields = ['time', 'lastseen', 'latest_decision', 'created', 'score_updated_at'];
$this->translateTimeZones($result, $fields);
}
}

View File

@@ -0,0 +1,92 @@
<?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 Models\Grid\Users;
class Ids extends \Models\Grid\Base\Ids {
public function getUsersIdsByIpId(): string {
return (
'SELECT DISTINCT
event.account AS itemid
FROM event
WHERE
event.ip = :ip_id AND
event.key = :api_key'
);
}
public function getUsersIdsByIspId(): string {
return (
'SELECT DISTINCT
event.account AS itemid
FROM event_ip
INNER JOIN event
ON (event_ip.id = event.ip)
WHERE
event_ip.isp = :isp_id AND
event_ip.key = :api_key'
);
}
public function getUsersIdsByDomainId(): string {
return (
'SELECT DISTINCT
event_email.account_id AS itemid
FROM event_domain
INNER JOIN event_email
ON event_domain.id = event_email.domain
WHERE
event_domain.id = :domain_id AND
event_domain.key = :api_key'
);
}
public function getUsersIdsByCountryId(): string {
return (
'SELECT DISTINCT
event.account AS itemid
FROM event_ip
INNER JOIN event
ON (event_ip.id = event.ip)
WHERE
event_ip.country = :country_id AND
event_ip.key = :api_key'
);
}
public function getUsersIdsByDeviceId(): string {
return (
'SELECT DISTINCT
event.account AS itemid
FROM event
INNER JOIN event_device
ON (event_device.id = event.device)
WHERE
event_device.user_agent = :device_id AND
event.key = :api_key'
);
}
public function getUsersIdsByResourceId(): string {
return (
'SELECT DISTINCT
event.account AS itemid
FROM event
WHERE
event.url = :resource_id AND
event.key = :api_key'
);
}
}

View File

@@ -0,0 +1,156 @@
<?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 Models\Grid\Users;
class Query extends \Models\Grid\Base\Query {
protected $defaultOrder = 'event_account.id DESC';
protected $dateRangeField = 'event_account.lastseen';
protected $allowedColumns = ['score', 'accounttitle', 'firstname', 'lastname', 'created', 'lastseen', 'fraud', 'id'];
public function getData(): array {
$queryParams = $this->getQueryParams();
$query = (
"SELECT
TEXT(date_trunc('day', event_account.created)::date) AS created_day,
event_account.id,
event_account.is_important,
event_account.id AS accountid,
event_account.userid AS accounttitle,
event_account.score,
event_account.score_updated_at,
event_account.created,
event_account.fraud,
event_account.reviewed,
event_account.firstname,
event_account.lastname,
event_account.lastseen,
event_account.total_visit,
event_account.total_ip,
event_account.total_device,
event_account.total_country,
event_account.latest_decision,
event_account.added_to_review,
event_email.email,
event_email.blockemails
FROM
event_account
LEFT JOIN event_email
ON (event_account.lastemail = event_email.id)
WHERE
event_account.key = :api_key
%s"
);
$this->applySearch($query, $queryParams);
$this->applyRules($query, $queryParams);
$this->applyScore($query, $queryParams);
$this->applyOrder($query);
$this->applyLimit($query, $queryParams);
return [$query, $queryParams];
}
public function getTotal(): array {
$queryParams = $this->getQueryParams();
$query = (
'SELECT
COUNT (event_account.id)
FROM
event_account
LEFT JOIN event_email
ON (event_account.lastemail = event_email.id)
WHERE
event_account.key = :api_key
%s'
);
$this->applySearch($query, $queryParams);
$this->applyRules($query, $queryParams);
$this->applyScore($query, $queryParams);
return [$query, $queryParams];
}
private function applySearch(string &$query, array &$queryParams): void {
$this->applyDateRange($query, $queryParams);
$search = $this->f3->get('REQUEST.search');
$searchConditions = $this->injectIdQuery('event_account.id', $queryParams);
if (is_array($search) && isset($search['value']) && is_string($search['value']) && $search['value'] !== '') {
$searchConditions .= (
" AND
(
LOWER(REPLACE(
COALESCE(event_account.firstname, '') ||
COALESCE(event_account.lastname, '') ||
COALESCE(event_account.firstname, ''),
' ', '')) LIKE LOWER(REPLACE(:search_value, ' ', '')) OR
LOWER(event_email.email) LIKE LOWER(:search_value) OR
LOWER(event_account.userid) LIKE LOWER(:search_value) OR
TO_CHAR(event_account.created::timestamp without time zone, 'dd/mm/yyyy hh24:mi:ss') LIKE :search_value
)"
);
$queryParams[':search_value'] = '%' . $search['value'] . '%';
}
//Add search and ids into request
$query = sprintf($query, $searchConditions);
}
private function applyRules(string &$query, array &$queryParams): void {
$ruleUids = $this->f3->get('REQUEST.ruleUids');
if ($ruleUids === null) {
return;
}
$uids = [];
foreach ($ruleUids as $ruleUid) {
$uids[] = ['uid' => $ruleUid];
}
$query .= ' AND score_details @> (:rules_uids)::jsonb';
$queryParams[':rules_uids'] = json_encode($uids);
}
private function applyScore(string &$query, array &$queryParams): void {
$scoresRanges = $this->f3->get('REQUEST.scoresRange');
if ($scoresRanges === null) {
return;
}
$clauses = [];
foreach ($scoresRanges as $key => $scoreBase) {
$clauses[] = sprintf('event_account.score >= :score_base_%s AND event_account.score <= :score_base_%s + 10', $key, $key);
$queryParams[':score_base_' . $key] = intval($scoreBase);
}
$query .= ' AND (' . implode(' OR ', $clauses) . ')';
}
}