feat(cloudron): add tirreno package artifacts
- Add CloudronStack/output/CloudronPackages-Artifacts/tirreno/ directory and its contents - Includes package manifest, Dockerfile, source code, documentation, and build artifacts - Add tirreno-1761840148.tar.gz as a build artifact - Add tirreno-cloudron-package-1761841304.tar.gz as the Cloudron package - Include all necessary files for the tirreno Cloudron package This adds the complete tirreno Cloudron package artifacts to the repository.
This commit is contained in:
@@ -0,0 +1,311 @@
|
||||
<?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;
|
||||
|
||||
class SessionStat extends \Models\BaseSql {
|
||||
protected $DB_TABLE_NAME = 'event_session_stat';
|
||||
|
||||
public function updateTotalsByAccountIds(array $ids, int $apiKey): ?int {
|
||||
if (!count($ids)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$cnt = 0;
|
||||
$batchSize = 100;
|
||||
|
||||
foreach (array_chunk($ids, $batchSize) as $accounts) {
|
||||
[$params, $flatIds] = $this->getArrayPlaceholders($accounts);
|
||||
$params[':key'] = $apiKey;
|
||||
|
||||
$query = ("
|
||||
SELECT
|
||||
event_session.id
|
||||
|
||||
FROM
|
||||
event_session
|
||||
|
||||
LEFT JOIN event_session_stat
|
||||
ON event_session.id = event_session_stat.session_id
|
||||
|
||||
WHERE
|
||||
(event_session_stat.completed IS NULL OR
|
||||
event_session_stat.completed IS FALSE) AND
|
||||
event_session.account_id IN ({$flatIds}) AND
|
||||
event_session.key = :key
|
||||
");
|
||||
|
||||
|
||||
$results = $this->execQuery($query, $params);
|
||||
|
||||
if (!count($results)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$sessionIds = array_column($results, 'id');
|
||||
$result = $this->updateStatsByIds($sessionIds, $apiKey);
|
||||
|
||||
$cnt += $result ? $result : 0;
|
||||
}
|
||||
|
||||
return $cnt;
|
||||
}
|
||||
|
||||
public function updateStats(int $apiKey): ?int {
|
||||
$params = [
|
||||
':key' => $apiKey,
|
||||
];
|
||||
|
||||
|
||||
// select only that sessions which events have not went under retention
|
||||
$query = ('
|
||||
SELECT
|
||||
COUNT(DISTINCT event.session_id) AS cnt
|
||||
FROM
|
||||
event
|
||||
|
||||
LEFT JOIN event_session
|
||||
ON event_session.id = event.session_id
|
||||
|
||||
LEFT JOIN event_session_stat
|
||||
ON event_session.id = event_session_stat.session_id
|
||||
|
||||
WHERE
|
||||
(event_session_stat.completed IS NULL OR
|
||||
event_session_stat.completed IS FALSE) AND
|
||||
event_session.key = :key');
|
||||
|
||||
$results = $this->execQuery($query, $params);
|
||||
|
||||
$total = $results[0] ?? [];
|
||||
$total = $total['cnt'] ?? 0;
|
||||
|
||||
if (!$total) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$query = ('
|
||||
SELECT
|
||||
DISTINCT event.session_id AS id
|
||||
FROM event
|
||||
|
||||
LEFT JOIN event_session
|
||||
ON event_session.id = event.session_id
|
||||
|
||||
LEFT JOIN event_session_stat
|
||||
ON event_session.id = event_session_stat.session_id
|
||||
|
||||
WHERE
|
||||
(event_session_stat.completed IS NULL OR
|
||||
event_session_stat.completed IS FALSE) AND
|
||||
event_session.key = :key
|
||||
|
||||
ORDER BY event.session_id DESC
|
||||
LIMIT :length OFFSET :offset
|
||||
');
|
||||
|
||||
$cnt = 0;
|
||||
$limit = 5000;
|
||||
|
||||
for ($offset = 0; $offset < $total; $offset += $limit) {
|
||||
$params[':length'] = $limit;
|
||||
$params[':offset'] = $offset;
|
||||
$results = $this->execQuery($query, $params);
|
||||
if (!count($results)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$sessionIds = array_column($results, 'id');
|
||||
$results = $this->updateStatsByIds($sessionIds, $apiKey);
|
||||
$cnt += $results ? $results : 0;
|
||||
}
|
||||
|
||||
return $cnt;
|
||||
}
|
||||
|
||||
public function updateStatsByIds(array $sessionIds, int $apiKey): ?int {
|
||||
$batchSize = 5000;
|
||||
|
||||
$stats = [];
|
||||
$plcArr = [];
|
||||
$results = null;
|
||||
$params = [];
|
||||
$arrPlaceholders = [];
|
||||
|
||||
foreach (array_chunk($sessionIds, $batchSize) as $ids) {
|
||||
$stats = [];
|
||||
$plcArr = [];
|
||||
$params = [
|
||||
':key' => $apiKey,
|
||||
];
|
||||
|
||||
foreach ($ids as $id) {
|
||||
$plcArr[] = ':id_' . strval($id);
|
||||
$params[':id_' . strval($id)] = $id;
|
||||
}
|
||||
$idsStr = '(' . implode(', ', $plcArr) . ')';
|
||||
|
||||
$results = $this->getBaseSessionsData($idsStr, $params);
|
||||
|
||||
if (!count($results)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($results as $result) {
|
||||
$id = $result['id'];
|
||||
$stats[$id] = [
|
||||
':key_' . strval($id) => $apiKey,
|
||||
':session_id_' . strval($id) => $result['id'],
|
||||
':duration_' . strval($id) => $result['duration'],
|
||||
':completed_' . strval($id) => $result['completed'],
|
||||
':event_count_' . strval($id) => $result['event_count'],
|
||||
':device_count_' . strval($id) => $result['device_count'],
|
||||
':ip_count_' . strval($id) => $result['ip_count'],
|
||||
':country_count_' . strval($id) => $result['country_count'],
|
||||
':new_device_count_' . strval($id) => $result['new_device_count'],
|
||||
':new_ip_count_' . strval($id) => $result['new_ip_count'],
|
||||
];
|
||||
}
|
||||
|
||||
$this->eventColumnStats('type', $idsStr, $params, $stats, ':event_types_');
|
||||
$this->eventColumnStats('http_code', $idsStr, $params, $stats);
|
||||
$this->eventColumnStats('http_method', $idsStr, $params, $stats);
|
||||
|
||||
$arrPlaceholders = [];
|
||||
$params = [];
|
||||
|
||||
foreach ($stats as $id => $item) {
|
||||
ksort($item);
|
||||
$arrPlaceholders[] = '(' . implode(', ', array_keys($item)) . ')';
|
||||
foreach ($item as $key => $val) {
|
||||
$params[$key] = $val;
|
||||
}
|
||||
}
|
||||
|
||||
$strPlaceholders = implode(', ', $arrPlaceholders);
|
||||
|
||||
// column names sorted asc
|
||||
$query = ("
|
||||
INSERT INTO event_session_stat (
|
||||
completed, country_count, device_count, duration, event_count, event_types,
|
||||
http_codes, http_methods, ip_count, key, new_device_count, new_ip_count, session_id
|
||||
) VALUES {$strPlaceholders}
|
||||
ON CONFLICT (session_id) DO UPDATE SET
|
||||
updated = NOW(), ip_count = EXCLUDED.ip_count, device_count = EXCLUDED.device_count,
|
||||
event_count = EXCLUDED.event_count, country_count = EXCLUDED.country_count,
|
||||
new_ip_count = EXCLUDED.new_ip_count, new_device_count = EXCLUDED.new_device_count,
|
||||
http_codes = EXCLUDED.http_codes, http_methods = EXCLUDED.http_methods,
|
||||
event_types = EXCLUDED.event_types, completed = EXCLUDED.completed
|
||||
");
|
||||
|
||||
$this->execQuery($query, $params);
|
||||
}
|
||||
|
||||
return count($sessionIds);
|
||||
}
|
||||
|
||||
private function getBaseSessionsData(string $idsPlaceholder, array &$params): array {
|
||||
$query = ("
|
||||
SELECT
|
||||
event_session.id AS id,
|
||||
EXTRACT(EPOCH FROM (event_session.lastseen - event_session.created))::integer AS duration,
|
||||
(
|
||||
EXTRACT(EPOCH FROM(event_session.lastseen - event_session.created))::integer > 14400 OR
|
||||
EXTRACT(EPOCH FROM(CURRENT_TIMESTAMP))::integer - 3600 > EXTRACT(EPOCH FROM(event_session.lastseen))::integer
|
||||
)::boolean AS completed,
|
||||
COUNT(event.id) AS event_count,
|
||||
COUNT(DISTINCT event.device) AS device_count,
|
||||
COUNT(DISTINCT event.ip) AS ip_count,
|
||||
COUNT(DISTINCT event_ip.country) AS country_count,
|
||||
COUNT(DISTINCT CASE WHEN
|
||||
event_device.created <= event_session.lastseen AND
|
||||
event_device.created >= event_session.created
|
||||
THEN event.device END) AS new_device_count,
|
||||
COUNT(DISTINCT CASE WHEN
|
||||
event_ip.created <= event_session.lastseen AND
|
||||
event_ip.created >= event_session.created
|
||||
THEN event.ip END) AS new_ip_count
|
||||
|
||||
FROM event_session
|
||||
|
||||
LEFT JOIN event
|
||||
ON event_session.id = event.session_id
|
||||
|
||||
LEFT JOIN event_device
|
||||
ON event.device = event_device.id
|
||||
|
||||
LEFT JOIN event_ip
|
||||
ON event.ip = event_ip.id
|
||||
|
||||
WHERE
|
||||
event_session.id IN {$idsPlaceholder} AND
|
||||
event.key = :key
|
||||
|
||||
GROUP BY
|
||||
event_session.id,
|
||||
event_session.lastseen,
|
||||
event_session.created
|
||||
");
|
||||
|
||||
return $this->execQuery($query, $params);
|
||||
}
|
||||
|
||||
private function eventColumnStats(string $column, string $idsPlaceholder, array &$params, array &$stats, ?string $alias = null): void {
|
||||
if (!in_array($column, ['http_code', 'http_method', 'type'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$alias) {
|
||||
$alias = ':' . $column . 's_';
|
||||
}
|
||||
|
||||
$query = ("
|
||||
SELECT
|
||||
event.session_id AS id,
|
||||
event.{$column} AS value,
|
||||
COUNT(*) AS cnt
|
||||
FROM
|
||||
event
|
||||
|
||||
WHERE
|
||||
event.session_id IN {$idsPlaceholder} AND
|
||||
event.key = :key
|
||||
|
||||
GROUP BY
|
||||
event.session_id,
|
||||
event.{$column}
|
||||
");
|
||||
|
||||
$results = $this->execQuery($query, $params);
|
||||
|
||||
$data = [];
|
||||
foreach ($results as $result) {
|
||||
if ($result['value'] !== null) {
|
||||
if (!array_key_exists($result['id'], $data)) {
|
||||
$data[$result['id']] = [];
|
||||
}
|
||||
$data[$result['id']][$result['value']] = $result['cnt'];
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($stats as $id => $item) {
|
||||
if (array_key_exists($id, $data)) {
|
||||
$stats[$id][$alias . strval($id)] = json_encode($data[$id], JSON_FORCE_OBJECT | JSON_UNESCAPED_UNICODE);
|
||||
} else {
|
||||
$stats[$id][$alias . strval($id)] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user