
<center><h2><strong>Ubuntu</strong></h2>
­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­
<!DOCTYPE html>
<html>
<?php

/**
 * Matomo - free/libre analytics platform
 *
 * @link    https://matomo.org
 * @license https://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
 */
declare (strict_types=1);
namespace Piwik\Plugins\BotTracking;

use Piwik\Date;
use Piwik\Plugin;
use Piwik\Plugins\BotTracking\Dao\BotRequestsDao;
use Piwik\Plugins\SitesManager\API;
use Piwik\Plugins\BotTracking\Metrics as BotMetrics;
use Piwik\Tracker\Request;
/**
 * BotTracking Plugin
 *
 * Tracks AI assistant and bot interactions without creating visits.
 * Stores telemetry data in dedicated tables for analysis of bot behavior
 * and system performance.
 */
class BotTracking extends Plugin
{
    /**
     * @return bool
     */
    public function isTrackerPlugin()
    {
        return \true;
    }
    /**
     * @return array<string, string>
     */
    public function registerEvents() : array
    {
        return ['AssetManager.getStylesheetFiles' => 'getStylesheetFiles', 'PrivacyManager.deleteLogsOlderThan' => 'deleteLogsOlderThan', 'PrivacyManager.deleteDataSubjectsForDeletedSites' => 'deleteDataSubjectsForDeletedSites', 'Tracker.isBotRequest' => 'isBotRequest', 'Translate.getClientSideTranslationKeys' => 'getClientSideTranslationKeys', 'Metrics.getEvolutionUnit' => 'getEvolutionUnit', 'Metrics.getDefaultMetricTranslations' => 'addMetricTranslations', 'Metrics.getDefaultMetricDocumentationTranslations' => 'addMetricDocumentationTranslations', 'Metrics.getDefaultMetricSemanticTypes' => 'addMetricSemanticTypes'];
    }
    /**
     * @return void
     */
    public function install()
    {
        (new BotRequestsDao())->createTable();
    }
    /**
     * @return void
     */
    public function uninstall()
    {
        (new BotRequestsDao())->dropTable();
    }
    public function deleteLogsOlderThan(Date $dateUpperLimit) : void
    {
        (new BotRequestsDao())->deleteOldRecords($dateUpperLimit);
    }
    /**
     * @param array<string, int> $result
     */
    public function deleteDataSubjectsForDeletedSites(array &$result) : void
    {
        $allExistingIdSites = API::getInstance()->getAllSitesId();
        $allExistingIdSites = array_map('intval', $allExistingIdSites);
        $maxIdSite = max($allExistingIdSites);
        if (empty($maxIdSite)) {
            return;
        }
        $dao = new BotRequestsDao();
        $idSitesInTable = $dao->getDistinctIdSitesInTable($maxIdSite);
        $idSitesNoLongerExisting = array_diff($idSitesInTable, $allExistingIdSites);
        if (count($idSitesNoLongerExisting) > 0) {
            $result[$dao::getTableName()] = $dao->deleteRecordsForIdSites($idSitesNoLongerExisting);
        }
    }
    /**
     * @todo Remove, once Device Detector is able to detect all known ai bots
     */
    public function isBotRequest(bool &$isBot, Request $request) : void
    {
        $botDetector = new \Piwik\Plugins\BotTracking\BotDetector($request->getUserAgent());
        if ($botDetector->isBot()) {
            $isBot = \true;
        }
    }
    public function getEvolutionUnit(?string &$unit, string $column) : void
    {
        if ($column === \Piwik\Plugins\BotTracking\Metrics::METRIC_AI_CHATBOTS_CLICK_THROUGH_RATE) {
            $unit = '%';
        }
    }
    /**
     * @param array<string, string> $translations
     */
    public function addMetricTranslations(array &$translations) : void
    {
        $translations = array_merge($translations, BotMetrics::getMetricTranslations());
    }
    /**
     * @param array<string, string> $translations
     */
    public function addMetricDocumentationTranslations(array &$translations) : void
    {
        $translations = array_merge($translations, BotMetrics::getMetricDocumentation());
    }
    /**
     * @param array<string|int, string> $types
     */
    public function addMetricSemanticTypes(array &$types) : void
    {
        $types = array_merge($types, BotMetrics::getMetricSemanticTypes());
    }
    public function getClientSideTranslationKeys(&$translationKeys)
    {
        $translationKeys[] = 'BotTracking_DetectingYourSite';
        $translationKeys[] = 'BotTracking_SiteWithoutDataBackToMatomo';
        $translationKeys[] = 'BotTracking_SiteWithoutDataChooseTrackingMethod';
        $translationKeys[] = 'BotTracking_SiteWithoutDataChooseTrackingMethodPreamble1';
        $translationKeys[] = 'BotTracking_SiteWithoutDataChooseTrackingMethodPreamble2';
        $translationKeys[] = 'BotTracking_SiteWithoutDataInstallWithX';
        $translationKeys[] = 'BotTracking_SiteWithoutDataNotYetReady';
        $translationKeys[] = 'BotTracking_SiteWithoutDataOtherInstallMethods';
        $translationKeys[] = 'BotTracking_SiteWithoutDataOtherInstallMethodsIntro';
        $translationKeys[] = 'BotTracking_SiteWithoutDataInstallWithXRecommendation';
        $translationKeys[] = 'BotTracking_SiteWithoutDataRecommendationText';
        $translationKeys[] = 'General_ErrorRequest';
        $translationKeys[] = 'General_Refresh';
        $translationKeys[] = 'Mobile_NavigationBack';
    }
    public function getStylesheetFiles(&$stylesheets)
    {
        $stylesheets[] = "plugins/BotTracking/stylesheets/BotTracking.less";
    }
}
