From 5eba322cbd24191e05304df08c80af846977d99b Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Tue, 14 Oct 2025 11:05:17 +0200 Subject: New stats overview of dates with most unread articles (#8089) New view with direct links to dates with most unread articles: image --- app/Models/StatsDAO.php | 49 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) (limited to 'app/Models/StatsDAO.php') diff --git a/app/Models/StatsDAO.php b/app/Models/StatsDAO.php index 771a2c7ee..c10567951 100644 --- a/app/Models/StatsDAO.php +++ b/app/Models/StatsDAO.php @@ -5,6 +5,30 @@ class FreshRSS_StatsDAO extends Minz_ModelPdo { public const ENTRY_COUNT_PERIOD = 30; + /** Get the number of seconds to add to UTC to get the user's local time */ + protected function getTimezoneOffset(): int { + $timezone = new DateTimeZone(date_default_timezone_get()); + return $timezone->getOffset(new DateTime('now', new DateTimeZone('UTC'))); + } + + /** + * @param string $field to use for the date + * @param int $precision to apply to the timestamp (1 for seconds, 1000 for milliseconds, 1000000 for microseconds) + * @param 'day'|'month'|'year' $granularity of the date intervals + */ + protected function sqlDateToIsoGranularity(string $field, int $precision, string $granularity): string { + if (!preg_match('/^[a-zA-Z0-9_]+$/', $field)) { + throw new InvalidArgumentException('Invalid date field!'); + } + $offset = $this->getTimezoneOffset(); + return match ($granularity) { + 'day' => "FROM_UNIXTIME(($field / $precision) + $offset, '%Y-%m-%d')", + 'month' => "FROM_UNIXTIME(($field / $precision) + $offset, '%Y-%m')", + 'year' => "FROM_UNIXTIME(($field / $precision) + $offset, '%Y')", + default => throw new InvalidArgumentException('Invalid date granularity!'), + }; + } + protected function sqlFloor(string $s): string { return "FLOOR($s)"; } @@ -132,8 +156,9 @@ SQL; if ($feed) { $restrict = "WHERE e.id_feed = {$feed}"; } + $offset = $this->getTimezoneOffset(); $sql = << + */ + public function getMaxUnreadDates(string $field, string $granularity, int $max = 100): array { + $sql = <<sqlDateToIsoGranularity($field, precision: $field === 'id' ? 1000000 : 1, granularity: $granularity)} AS granularity, + COUNT(*) AS unread_count +FROM `_entry` +WHERE is_read = 0 +GROUP BY granularity +ORDER BY unread_count DESC, granularity DESC +LIMIT $max; +SQL; + $res = $this->fetchAssoc($sql); + /** @var list|null $res */ + return is_array($res) ? $res : []; + } } -- cgit v1.2.3