Skip to content
Snippets Groups Projects
Commit ec92e65a authored by Benjamin Bellamy's avatar Benjamin Bellamy :speech_balloon: Committed by Yassine Doghri
Browse files

feat: add analytics and unknown useragents

parent 4651d01a
No related branches found
No related tags found
No related merge requests found
Showing
with 885 additions and 0 deletions
...@@ -46,6 +46,13 @@ $routes->group('(:podcastSlug)', function ($routes) { ...@@ -46,6 +46,13 @@ $routes->group('(:podcastSlug)', function ($routes) {
]); ]);
}); });
// Route for podcast audio file analytics (/stats/podcast_id/episode_id/podcast_folder/filename.mp3)
$routes->add('/stats/(:num)/(:num)/(:any)', 'Analytics::hit/$1/$2/$3');
// Show the Unknown UserAgents
$routes->add('/.well-known/unknown-useragents', 'UnknownUserAgents');
$routes->add('/.well-known/unknown-useragents/(:num)', 'UnknownUserAgents/$1');
/** /**
* -------------------------------------------------------------------- * --------------------------------------------------------------------
* Additional Routing * Additional Routing
......
<?php namespace App\Controllers;
/**
* Class Analytics
* Creates Analytics controller
* @copyright 2020 Podlibre
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
* @link https://castopod.org/
*/
use CodeIgniter\Controller;
class Analytics extends Controller
{
function __construct()
{
$session = \Config\Services::session();
$session->start();
$db = \Config\Database::connect();
$country = 'N/A';
// Finds country:
if (!$session->has('country')) {
try {
$reader = new \GeoIp2\Database\Reader(
WRITEPATH . 'uploads/GeoLite2-Country/GeoLite2-Country.mmdb'
);
$geoip = $reader->country($_SERVER['REMOTE_ADDR']);
$country = $geoip->country->isoCode;
} catch (\Exception $e) {
// If things go wrong the show must go on and the user must be able to download the file
}
$session->set('country', $country);
}
// Finds player:
if (!$session->has('player')) {
$playerName = '-unknown-';
$error = '';
try {
$useragent = $_SERVER['HTTP_USER_AGENT'];
$jsonUserAgents = json_decode(
file_get_contents(
WRITEPATH . 'uploads/user-agents/src/user-agents.json'
),
true
);
//Search for current HTTP_USER_AGENT in json file:
foreach ($jsonUserAgents as $player) {
foreach ($player['user_agents'] as $useragentsRegexp) {
//Does the HTTP_USER_AGENT match this regexp:
if (preg_match("#{$useragentsRegexp}#", $useragent)) {
if (isset($player['bot'])) {
//It’s a bot!
$playerName = '-bot-';
} else {
//It isn’t a bot, we store device/os/app:
$playerName =
(isset($player['device'])
? $player['device'] . '/'
: '') .
(isset($player['os'])
? $player['os'] . '/'
: '') .
(isset($player['app'])
? $player['app']
: '?');
}
//We found it!
break 2;
}
}
}
} catch (\Exception $e) {
// If things go wrong the show must go on and the user must be able to download the file
}
if ($playerName == '-unknown-') {
// Add to unknown list
try {
$procedureNameAUU = $db->prefixTable(
'analytics_unknown_useragents'
);
$db->query("CALL $procedureNameAUU(?)", [$useragent]);
} catch (\Exception $e) {
// If things go wrong the show must go on and the user must be able to download the file
}
}
$session->set('player', $playerName);
}
}
// Add one hit to this episode:
public function hit($p_podcast_id, $p_episode_id, ...$filename)
{
$session = \Config\Services::session();
$db = \Config\Database::connect();
$procedureName = $db->prefixTable('analytics_podcasts');
$p_country_code = $session->get('country');
$p_player = $session->get('player');
try {
$db->query("CALL $procedureName(?,?,?,?);", [
$p_podcast_id,
$p_episode_id,
$p_country_code,
$p_player,
]);
} catch (\Exception $e) {
// If things go wrong the show must go on and the user must be able to download the file
}
return redirect()->to(media_url(implode('/', $filename)));
}
}
...@@ -44,5 +44,56 @@ class BaseController extends Controller ...@@ -44,5 +44,56 @@ class BaseController extends Controller
//-------------------------------------------------------------------- //--------------------------------------------------------------------
// E.g.: // E.g.:
// $this->session = \Config\Services::session(); // $this->session = \Config\Services::session();
$session = \Config\Services::session();
$session->start();
// Defines country
if (!$session->has('country')) {
try {
$reader = new \GeoIp2\Database\Reader(
WRITEPATH . 'uploads/GeoLite2-Country/GeoLite2-Country.mmdb'
);
$geoip = $reader->country($_SERVER['REMOTE_ADDR']);
$session->set('country', $geoip->country->isoCode);
} catch (\Exception $e) {
$session->set('country', 'N/A');
}
}
// Defines browser
if (!$session->has('browser')) {
try {
$whichbrowser = new \WhichBrowser\Parser(getallheaders());
$session->set('browser', $whichbrowser->browser->name);
} catch (\Exception $e) {
$session->set('browser', 'Other');
}
}
// Defines referrer
$newreferer = isset($_SERVER['HTTP_REFERER'])
? parse_url($_SERVER['HTTP_REFERER'], PHP_URL_HOST)
: '- Direct -';
$newreferer =
$newreferer == parse_url(current_url(false), PHP_URL_HOST)
? '- Direct -'
: $newreferer;
if (!$session->has('referer') or $newreferer != '- Direct -') {
$session->set('referer', $newreferer);
}
}
protected function stats($postcast_id)
{
$session = \Config\Services::session();
$session->start();
$db = \Config\Database::connect();
$procedureName = $db->prefixTable('analytics_website');
$db->query("call $procedureName(?,?,?,?)", [
$postcast_id,
$session->get('country'),
$session->get('browser'),
$session->get('referer'),
]);
} }
} }
...@@ -125,6 +125,7 @@ class Episodes extends BaseController ...@@ -125,6 +125,7 @@ class Episodes extends BaseController
->first(), ->first(),
'episode' => $episode_model->where('slug', $episode_slug)->first(), 'episode' => $episode_model->where('slug', $episode_slug)->first(),
]; ];
self::stats($data['podcast']->id);
return view('episodes/view.php', $data); return view('episodes/view.php', $data);
} }
......
...@@ -96,6 +96,7 @@ class Podcasts extends BaseController ...@@ -96,6 +96,7 @@ class Podcasts extends BaseController
->where('podcast_id', $podcast->id) ->where('podcast_id', $podcast->id)
->findAll(), ->findAll(),
]; ];
self::stats($podcast->id);
return view('podcasts/view', $data); return view('podcasts/view', $data);
} }
......
<?php namespace App\Controllers;
use CodeIgniter\Controller;
class UnknownUserAgents extends Controller
{
public function index($p_id = 0)
{
$model = new \App\Models\UnknownUserAgentsModel();
$data = [
'useragents' => $model->getUserAgents($p_id),
];
$this->response->setContentType('application/json');
$this->response->setStatusCode(\CodeIgniter\HTTP\Response::HTTP_OK);
echo view('json/unknownuseragents', $data);
}
}
<?php
/**
* Class AddAnalyticsEpisodesByCountry
* Creates analytics_episodes_by_country table in database
* @copyright 2020 Podlibre
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
* @link https://castopod.org/
*/
namespace App\Database\Migrations;
use CodeIgniter\Database\Migration;
class AddAnalyticsEpisodesByCountry extends Migration
{
public function up()
{
$this->forge->addField([
'id' => [
'type' => 'BIGINT',
'constraint' => 20,
'unsigned' => true,
'auto_increment' => true,
'comment' => 'The line ID',
],
'podcast_id' => [
'type' => 'BIGINT',
'constraint' => 20,
'unsigned' => true,
'comment' => 'The podcast ID',
],
'episode_id' => [
'type' => 'BIGINT',
'constraint' => 20,
'unsigned' => true,
'comment' => 'The episode ID',
],
'country_code' => [
'type' => 'VARCHAR',
'constraint' => 3,
'comment' => 'ISO 3166-1 code.',
],
'date' => [
'type' => 'date',
'comment' => 'Line date.',
],
'hits' => [
'type' => 'INT',
'constraint' => 10,
'default' => 1,
'comment' => 'Number of hits.',
],
]);
$this->forge->addKey('id', true);
$this->forge->addUniqueKey([
'podcast_id',
'episode_id',
'country_code',
'date',
]);
$this->forge->addField(
'`created_at` timestamp NOT NULL DEFAULT current_timestamp()'
);
$this->forge->addField(
'`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()'
);
$this->forge->addForeignKey('podcast_id', 'podcasts', 'id');
$this->forge->addForeignKey('episode_id', 'episodes', 'id');
$this->forge->createTable('analytics_episodes_by_country');
}
public function down()
{
$this->forge->dropTable('analytics_episodes_by_country');
}
}
<?php
/**
* Class AddAnalyticsEpisodesByPlayer
* Creates analytics_episodes_by_player table in database
* @copyright 2020 Podlibre
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
* @link https://castopod.org/
*/
namespace App\Database\Migrations;
use CodeIgniter\Database\Migration;
class AddAnalyticsEpisodesByPlayer extends Migration
{
public function up()
{
$this->forge->addField([
'id' => [
'type' => 'BIGINT',
'constraint' => 20,
'unsigned' => true,
'auto_increment' => true,
'comment' => 'The line ID',
],
'podcast_id' => [
'type' => 'BIGINT',
'constraint' => 20,
'unsigned' => true,
'comment' => 'The podcast ID',
],
'episode_id' => [
'type' => 'BIGINT',
'constraint' => 20,
'unsigned' => true,
'comment' => 'The episode ID',
],
'player' => [
'type' => 'VARCHAR',
'constraint' => 191,
'comment' => 'Podcast player name.',
],
'date' => [
'type' => 'date',
'comment' => 'Line date.',
],
'hits' => [
'type' => 'INT',
'constraint' => 10,
'default' => 1,
'comment' => 'Number of hits.',
],
]);
$this->forge->addKey('id', true);
$this->forge->addUniqueKey([
'podcast_id',
'episode_id',
'player',
'date',
]);
$this->forge->addField(
'`created_at` timestamp NOT NULL DEFAULT current_timestamp()'
);
$this->forge->addField(
'`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()'
);
$this->forge->addForeignKey('podcast_id', 'podcasts', 'id');
$this->forge->addForeignKey('episode_id', 'episodes', 'id');
$this->forge->createTable('analytics_episodes_by_player');
}
public function down()
{
$this->forge->dropTable('analytics_episodes_by_player');
}
}
<?php
/**
* Class AddAnalyticsPodcastsByCountry
* Creates analytics_podcasts_by_country table in database
* @copyright 2020 Podlibre
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
* @link https://castopod.org/
*/
namespace App\Database\Migrations;
use CodeIgniter\Database\Migration;
class AddAnalyticsPodcastsByCountry extends Migration
{
public function up()
{
$this->forge->addField([
'id' => [
'type' => 'BIGINT',
'constraint' => 20,
'unsigned' => true,
'auto_increment' => true,
'comment' => 'The line ID',
],
'podcast_id' => [
'type' => 'BIGINT',
'constraint' => 20,
'unsigned' => true,
'comment' => 'The podcast ID',
],
'country_code' => [
'type' => 'VARCHAR',
'constraint' => 3,
'comment' => 'ISO 3166-1 code.',
],
'date' => [
'type' => 'date',
'comment' => 'Line date.',
],
'hits' => [
'type' => 'INT',
'constraint' => 10,
'default' => 1,
'comment' => 'Number of hits.',
],
]);
$this->forge->addKey('id', true);
$this->forge->addUniqueKey(['podcast_id', 'country_code', 'date']);
$this->forge->addField(
'`created_at` timestamp NOT NULL DEFAULT current_timestamp()'
);
$this->forge->addField(
'`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()'
);
$this->forge->addForeignKey('podcast_id', 'podcasts', 'id');
$this->forge->createTable('analytics_podcasts_by_country');
}
public function down()
{
$this->forge->dropTable('analytics_podcasts_by_country');
}
}
<?php
/**
* Class AddAnalyticsPodcastsByPlayer
* Creates analytics_podcasts_by_player table in database
* @copyright 2020 Podlibre
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
* @link https://castopod.org/
*/
namespace App\Database\Migrations;
use CodeIgniter\Database\Migration;
class AddAnalyticsPodcastsByPlayer extends Migration
{
public function up()
{
$this->forge->addField([
'id' => [
'type' => 'BIGINT',
'constraint' => 20,
'unsigned' => true,
'auto_increment' => true,
'comment' => 'The line ID',
],
'podcast_id' => [
'type' => 'BIGINT',
'constraint' => 20,
'unsigned' => true,
'comment' => 'The podcast ID',
],
'player' => [
'type' => 'VARCHAR',
'constraint' => 191,
'comment' => 'Podcast player name.',
],
'date' => [
'type' => 'date',
'comment' => 'Line date.',
],
'hits' => [
'type' => 'INT',
'constraint' => 10,
'default' => 1,
'comment' => 'Number of hits.',
],
]);
$this->forge->addKey('id', true);
$this->forge->addUniqueKey(['podcast_id', 'player', 'date']);
$this->forge->addField(
'`created_at` timestamp NOT NULL DEFAULT current_timestamp()'
);
$this->forge->addField(
'`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()'
);
$this->forge->addForeignKey('podcast_id', 'podcasts', 'id');
$this->forge->createTable('analytics_podcasts_by_player');
}
public function down()
{
$this->forge->dropTable('analytics_podcasts_by_player');
}
}
<?php
/**
* Class AddAnalyticsUnknownUseragents
* Creates analytics_unknown_useragents table in database
* @copyright 2020 Podlibre
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
* @link https://castopod.org/
*/
namespace App\Database\Migrations;
use CodeIgniter\Database\Migration;
class AddAnalyticsUnknownUseragents extends Migration
{
public function up()
{
$this->forge->addField([
'id' => [
'type' => 'BIGINT',
'constraint' => 20,
'unsigned' => true,
'auto_increment' => true,
'comment' => 'The line ID',
],
'useragent' => [
'type' => 'VARCHAR',
'constraint' => 191,
'unique' => true,
'comment' => 'The unknown user-agent.',
],
'hits' => [
'type' => 'INT',
'constraint' => 10,
'default' => 1,
'comment' => 'Number of hits.',
],
]);
$this->forge->addKey('id', true);
// `created_at` and `updated_at` are created with SQL because Model class won’t be used for insertion (Stored Procedure will be used instead)
$this->forge->addField(
'`created_at` timestamp NOT NULL DEFAULT current_timestamp()'
);
$this->forge->addField(
'`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()'
);
$this->forge->createTable('analytics_unknown_useragents');
}
public function down()
{
$this->forge->dropTable('analytics_unknown_useragents');
}
}
<?php
/**
* Class AddAnalyticsWebsiteByBrowser
* Creates analytics_website_by_browser table in database
* @copyright 2020 Podlibre
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
* @link https://castopod.org/
*/
namespace App\Database\Migrations;
use CodeIgniter\Database\Migration;
class AddAnalyticsWebsiteByBrowser extends Migration
{
public function up()
{
$this->forge->addField([
'id' => [
'type' => 'BIGINT',
'constraint' => 20,
'unsigned' => true,
'auto_increment' => true,
'comment' => 'The line ID',
],
'podcast_id' => [
'type' => 'BIGINT',
'constraint' => 20,
'unsigned' => true,
'comment' => 'The podcast ID',
],
'browser' => [
'type' => 'VARCHAR',
'constraint' => 191,
'comment' => 'The Web Browser.',
],
'date' => [
'type' => 'date',
'comment' => 'Line date.',
],
'hits' => [
'type' => 'INT',
'constraint' => 10,
'default' => 1,
'comment' => 'Number of hits.',
],
]);
$this->forge->addKey('id', true);
$this->forge->addUniqueKey(['podcast_id', 'browser', 'date']);
$this->forge->addField(
'`created_at` timestamp NOT NULL DEFAULT current_timestamp()'
);
$this->forge->addField(
'`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()'
);
$this->forge->addForeignKey('podcast_id', 'podcasts', 'id');
$this->forge->createTable('analytics_website_by_browser');
}
public function down()
{
$this->forge->dropTable('analytics_website_by_browser');
}
}
<?php
/**
* Class AddAnalyticsWebsiteByCountry
* Creates analytics_website_by_country table in database
* @copyright 2020 Podlibre
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
* @link https://castopod.org/
*/
namespace App\Database\Migrations;
use CodeIgniter\Database\Migration;
class AddAnalyticsWebsiteByCountry extends Migration
{
public function up()
{
$this->forge->addField([
'id' => [
'type' => 'BIGINT',
'constraint' => 20,
'unsigned' => true,
'auto_increment' => true,
'comment' => 'The line ID',
],
'podcast_id' => [
'type' => 'BIGINT',
'constraint' => 20,
'unsigned' => true,
'comment' => 'The podcast ID',
],
'country_code' => [
'type' => 'VARCHAR',
'constraint' => 3,
'comment' => 'ISO 3166-1 code.',
],
'date' => [
'type' => 'date',
'comment' => 'Line date.',
],
'hits' => [
'type' => 'INT',
'constraint' => 10,
'default' => 1,
'comment' => 'Number of hits.',
],
]);
$this->forge->addKey('id', true);
$this->forge->addUniqueKey(['podcast_id', 'country_code', 'date']);
$this->forge->addField(
'`created_at` timestamp NOT NULL DEFAULT current_timestamp()'
);
$this->forge->addField(
'`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()'
);
$this->forge->addForeignKey('podcast_id', 'podcasts', 'id');
$this->forge->createTable('analytics_website_by_country');
}
public function down()
{
$this->forge->dropTable('analytics_website_by_country');
}
}
<?php
/**
* Class AddAnalyticsWebsiteByReferer
* Creates analytics_website_by_referer table in database
* @copyright 2020 Podlibre
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
* @link https://castopod.org/
*/
namespace App\Database\Migrations;
use CodeIgniter\Database\Migration;
class AddAnalyticsWebsiteByReferer extends Migration
{
public function up()
{
$this->forge->addField([
'id' => [
'type' => 'BIGINT',
'constraint' => 20,
'unsigned' => true,
'auto_increment' => true,
'comment' => 'The line ID',
],
'podcast_id' => [
'type' => 'BIGINT',
'constraint' => 20,
'unsigned' => true,
'comment' => 'The podcast ID',
],
'referer' => [
'type' => 'VARCHAR',
'constraint' => 191,
'comment' => 'Referer URL.',
],
'date' => [
'type' => 'date',
'comment' => 'Line date.',
],
'hits' => [
'type' => 'INT',
'constraint' => 10,
'default' => 1,
'comment' => 'Number of hits.',
],
]);
$this->forge->addKey('id', true);
$this->forge->addUniqueKey(['podcast_id', 'referer', 'date']);
$this->forge->addField(
'`created_at` timestamp NOT NULL DEFAULT current_timestamp()'
);
$this->forge->addField(
'`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()'
);
$this->forge->addForeignKey('podcast_id', 'podcasts', 'id');
$this->forge->createTable('analytics_website_by_referer');
}
public function down()
{
$this->forge->dropTable('analytics_website_by_referer');
}
}
<?php
/**
* Class AddAnalyticsPodcastsStoredProcedure
* Creates analytics_podcasts stored procedure in database
* @copyright 2020 Podlibre
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
* @link https://castopod.org/
*/
namespace App\Database\Migrations;
use CodeIgniter\Database\Migration;
class AddAnalyticsPodcastsStoredProcedure extends Migration
{
public function up()
{
// Creates Stored Procedure for data insertion
// Example: CALL analytics_podcasts(1,2,'FR','phone/android/Deezer');
$procedureName = $this->db->prefixTable('analytics_podcasts');
$episodesTableName = $this->db->prefixTable('analytics_episodes');
$createQuery = <<<EOD
CREATE PROCEDURE `$procedureName` (IN `p_podcast_id` BIGINT(20) UNSIGNED, IN `p_episode_id` BIGINT(20) UNSIGNED, IN `p_country_code` VARCHAR(3) CHARSET utf8mb4, IN `p_player` VARCHAR(191) CHARSET utf8mb4) MODIFIES SQL DATA
DETERMINISTIC
SQL SECURITY INVOKER
COMMENT 'Add one hit in podcast logs tables.'
BEGIN
INSERT INTO `{$procedureName}_by_country`(`podcast_id`, `country_code`, `date`)
VALUES (p_podcast_id, p_country_code, DATE(NOW()))
ON DUPLICATE KEY UPDATE `hits`=`hits`+1;
INSERT INTO `{$procedureName}_by_player`(`podcast_id`, `player`, `date`)
VALUES (p_podcast_id, p_player, DATE(NOW()))
ON DUPLICATE KEY UPDATE `hits`=`hits`+1;
INSERT INTO `{$episodesTableName}_by_country`(`podcast_id`, `episode_id`, `country_code`, `date`)
VALUES (p_podcast_id, p_episode_id, p_country_code, DATE(NOW()))
ON DUPLICATE KEY UPDATE `hits`=`hits`+1;
INSERT INTO `{$episodesTableName}_by_player`(`podcast_id`, `episode_id`, `player`, `date`)
VALUES (p_podcast_id, p_episode_id, p_player, DATE(NOW()))
ON DUPLICATE KEY UPDATE `hits`=`hits`+1;
END
EOD;
$this->db->query($createQuery);
}
public function down()
{
$procedureName = $this->db->prefixTable('analytics_podcasts');
$this->db->query("DROP PROCEDURE IF EXISTS `$procedureName`");
}
}
<?php
/**
* Class AddAnalyticsUnknownUseragentsStoredProcedure
* Creates analytics_unknown_useragents stored procedure in database
* @copyright 2020 Podlibre
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
* @link https://castopod.org/
*/
namespace App\Database\Migrations;
use CodeIgniter\Database\Migration;
class AddAnalyticsUnknownUseragentsStoredProcedure extends Migration
{
public function up()
{
// Creates Stored Procedure for data insertion
// Example: CALL analytics_unknown_useragents('Podcasts/1430.46 CFNetwork/1125.2 Darwin/19.4.0');
$procedureName = $this->db->prefixTable('analytics_unknown_useragents');
$createQuery = <<<EOD
CREATE PROCEDURE `$procedureName` (IN `p_useragent` VARCHAR(191) CHARSET utf8mb4) MODIFIES SQL DATA
DETERMINISTIC
SQL SECURITY INVOKER
COMMENT 'Add an unknown useragent to table $procedureName.'
INSERT INTO `$procedureName`(`useragent`)
VALUES (p_useragent)
ON DUPLICATE KEY UPDATE `hits`=`hits`+1
EOD;
$this->db->query($createQuery);
}
public function down()
{
$procedureName = $this->db->prefixTable('analytics_unknown_useragents');
$this->db->query("DROP PROCEDURE IF EXISTS `$procedureName`");
}
}
<?php
/**
* Class AddAnalyticsWebsiteStoredProcedure
* Creates analytics_website stored procedure in database
* @copyright 2020 Podlibre
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
* @link https://castopod.org/
*/
namespace App\Database\Migrations;
use CodeIgniter\Database\Migration;
class AddAnalyticsWebsiteStoredProcedure extends Migration
{
public function up()
{
// Creates Stored Procedure for data insertion
// Example: CALL analytics_website(1,'FR','Firefox');
$procedureName = $this->db->prefixTable('analytics_website');
$createQuery = <<<EOD
CREATE PROCEDURE `$procedureName` (IN `p_podcast_id` BIGINT(20) UNSIGNED, IN `p_country_code` VARCHAR(3) CHARSET utf8mb4, IN `p_browser` VARCHAR(191) CHARSET utf8mb4, IN `p_referer` VARCHAR(191) CHARSET utf8mb4) MODIFIES SQL DATA
DETERMINISTIC
SQL SECURITY INVOKER
COMMENT 'Add one hit in website logs tables.'
BEGIN
INSERT INTO {$procedureName}_by_country(`podcast_id`, `country_code`, `date`)
VALUES (p_podcast_id, p_country_code, DATE(NOW()))
ON DUPLICATE KEY UPDATE `hits`=`hits`+1;
INSERT INTO {$procedureName}_by_browser(`podcast_id`, `browser`, `date`)
VALUES (p_podcast_id, p_browser, DATE(NOW()))
ON DUPLICATE KEY UPDATE `hits`=`hits`+1;
INSERT INTO {$procedureName}_by_referer(`podcast_id`, `referer`, `date`)
VALUES (p_podcast_id, p_referer, DATE(NOW()))
ON DUPLICATE KEY UPDATE `hits`=`hits`+1;
END
EOD;
$this->db->query($createQuery);
}
public function down()
{
$procedureName = $this->db->prefixTable('analytics_website');
$this->db->query("DROP PROCEDURE IF EXISTS `$procedureName`");
}
}
<?php
/**
* Class AnalyticsEpisodesByCountry
* Entity for AnalyticsEpisodesByCountry
* @copyright 2020 Podlibre
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
* @link https://castopod.org/
*/
namespace App\Entities;
use CodeIgniter\Entity;
class AnalyticsEpisodesByCountry extends Entity
{
protected $casts = [
'podcast_id' => 'integer',
'episode_id' => 'integer',
'country_code' => 'string',
'date' => 'datetime',
'hits' => 'integer',
];
}
<?php
/**
* Class AnalyticsEpisodesByPlayer
* Entity for AnalyticsEpisodesByPlayer
* @copyright 2020 Podlibre
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
* @link https://castopod.org/
*/
namespace App\Entities;
use CodeIgniter\Entity;
class AnalyticsEpisodesByPlayer extends Entity
{
protected $casts = [
'podcast_id' => 'integer',
'episode_id' => 'integer',
'player' => 'string',
'date' => 'datetime',
'hits' => 'integer',
];
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment