4
0

statsController.php 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. <?php
  2. /**
  3. * Controller to handle application statistics.
  4. */
  5. class FreshRSS_stats_Controller extends FreshRSS_ActionController {
  6. /**
  7. * This action is called before every other action in that class. It is
  8. * the common boiler plate for every action. It is triggered by the
  9. * underlying framework.
  10. */
  11. public function firstAction(): void {
  12. if (!FreshRSS_Auth::hasAccess()) {
  13. Minz_Error::error(403);
  14. }
  15. $this->_csp([
  16. 'default-src' => "'self'",
  17. 'img-src' => '* data:',
  18. 'style-src' => "'self' 'unsafe-inline'",
  19. ]);
  20. $catDAO = FreshRSS_Factory::createCategoryDao();
  21. $feedDAO = FreshRSS_Factory::createFeedDao();
  22. $catDAO->checkDefault();
  23. $feedDAO->updateTTL();
  24. $this->view->categories = $catDAO->listSortedCategories(false);
  25. $this->view->default_category = $catDAO->getDefault();
  26. FreshRSS_View::prependTitle(_t('admin.stats.title') . ' · ');
  27. }
  28. /**
  29. * This action handles the statistic main page.
  30. *
  31. * It displays the statistic main page.
  32. * The values computed to display the page are:
  33. * - repartition of read/unread/favorite/not favorite (repartition)
  34. * - number of article per day (entryCount)
  35. * - number of feed by category (feedByCategory)
  36. * - number of article by category (entryByCategory)
  37. * - list of most prolific feed (topFeed)
  38. */
  39. public function indexAction(): void {
  40. $statsDAO = FreshRSS_Factory::createStatsDAO();
  41. FreshRSS_View::appendScript(Minz_Url::display('/scripts/vendor/chart.min.js?' . @filemtime(PUBLIC_PATH . '/scripts/vendor/chart.min.js')));
  42. $this->view->repartition = $statsDAO->calculateEntryRepartition();
  43. $entryCount = $statsDAO->calculateEntryCount();
  44. $this->view->entryCount = $entryCount;
  45. $this->view->average = round(array_sum(array_values($entryCount)) / count($entryCount), 2);
  46. $feedByCategory_calculated = $statsDAO->calculateFeedByCategory();
  47. $feedByCategory = [];
  48. for ($i = 0; $i < count($feedByCategory_calculated); $i++) {
  49. $feedByCategory['label'][$i] = $feedByCategory_calculated[$i]['label'];
  50. $feedByCategory['data'][$i] = $feedByCategory_calculated[$i]['data'];
  51. }
  52. $this->view->feedByCategory = $feedByCategory;
  53. $entryByCategory_calculated = $statsDAO->calculateEntryByCategory();
  54. $entryByCategory = [];
  55. for ($i = 0; $i < count($entryByCategory_calculated); $i++) {
  56. $entryByCategory['label'][$i] = $entryByCategory_calculated[$i]['label'];
  57. $entryByCategory['data'][$i] = $entryByCategory_calculated[$i]['data'];
  58. }
  59. $this->view->entryByCategory = $entryByCategory;
  60. $this->view->topFeed = $statsDAO->calculateTopFeed();
  61. $last30DaysLabels = [];
  62. for ($i = 0; $i < 30; $i++) {
  63. $last30DaysLabels[$i] = date('d.m.Y', strtotime((-30 + $i) . ' days') ?: null);
  64. }
  65. $this->view->last30DaysLabels = $last30DaysLabels;
  66. }
  67. /**
  68. * This action handles the feed action on the idle statistic page.
  69. * set the 'from' parameter to remember that it had a redirection coming from stats controller,
  70. * to use the subscription controller to save it,
  71. * but shows the stats idle page
  72. */
  73. public function feedAction(): void {
  74. $id = '' . Minz_Request::param('id', '');
  75. $ajax = '' . Minz_Request::param('ajax', '');
  76. if ($ajax) {
  77. $url_redirect = array('c' => 'subscription', 'a' => 'feed', 'params' => array('id' => $id, 'from' => 'stats', 'ajax' => $ajax));
  78. } else {
  79. $url_redirect = array('c' => 'subscription', 'a' => 'feed', 'params' => array('id' => $id, 'from' => 'stats'));
  80. }
  81. Minz_Request::forward($url_redirect, true);
  82. }
  83. /**
  84. * This action handles the idle feed statistic page.
  85. *
  86. * It displays the list of idle feed for different period. The supported
  87. * periods are:
  88. * - last 5 years
  89. * - last 3 years
  90. * - last 2 years
  91. * - last year
  92. * - last 6 months
  93. * - last 3 months
  94. * - last month
  95. * - last week
  96. */
  97. public function idleAction(): void {
  98. FreshRSS_View::appendScript(Minz_Url::display('/scripts/feed.js?' . @filemtime(PUBLIC_PATH . '/scripts/feed.js')));
  99. $feed_dao = FreshRSS_Factory::createFeedDao();
  100. $statsDAO = FreshRSS_Factory::createStatsDAO();
  101. $feeds = $statsDAO->calculateFeedLastDate();
  102. $idleFeeds = array(
  103. 'last_5_year' => array(),
  104. 'last_3_year' => array(),
  105. 'last_2_year' => array(),
  106. 'last_year' => array(),
  107. 'last_6_month' => array(),
  108. 'last_3_month' => array(),
  109. 'last_month' => array(),
  110. 'last_week' => array(),
  111. );
  112. $now = new \DateTime();
  113. $feedDate = clone $now;
  114. $lastWeek = clone $now;
  115. $lastWeek->modify('-1 week');
  116. $lastMonth = clone $now;
  117. $lastMonth->modify('-1 month');
  118. $last3Month = clone $now;
  119. $last3Month->modify('-3 month');
  120. $last6Month = clone $now;
  121. $last6Month->modify('-6 month');
  122. $lastYear = clone $now;
  123. $lastYear->modify('-1 year');
  124. $last2Year = clone $now;
  125. $last2Year->modify('-2 year');
  126. $last3Year = clone $now;
  127. $last3Year->modify('-3 year');
  128. $last5Year = clone $now;
  129. $last5Year->modify('-5 year');
  130. foreach ($feeds as $feed) {
  131. $feedDAO = FreshRSS_Factory::createFeedDao();
  132. $feed['favicon'] = $feedDAO->searchById($feed['id'])->favicon();
  133. $feedDate->setTimestamp($feed['last_date']);
  134. if ($feedDate >= $lastWeek) {
  135. continue;
  136. }
  137. if ($feedDate < $last5Year) {
  138. $idleFeeds['last_5_year'][] = $feed;
  139. } elseif ($feedDate < $last3Year) {
  140. $idleFeeds['last_3_year'][] = $feed;
  141. } elseif ($feedDate < $last2Year) {
  142. $idleFeeds['last_2_year'][] = $feed;
  143. } elseif ($feedDate < $lastYear) {
  144. $idleFeeds['last_year'][] = $feed;
  145. } elseif ($feedDate < $last6Month) {
  146. $idleFeeds['last_6_month'][] = $feed;
  147. } elseif ($feedDate < $last3Month) {
  148. $idleFeeds['last_3_month'][] = $feed;
  149. } elseif ($feedDate < $lastMonth) {
  150. $idleFeeds['last_month'][] = $feed;
  151. } elseif ($feedDate < $lastWeek) {
  152. $idleFeeds['last_week'][] = $feed;
  153. }
  154. }
  155. $this->view->idleFeeds = $idleFeeds;
  156. $this->view->feeds = $feed_dao->listFeeds();
  157. $id = Minz_Request::param('id');
  158. $this->view->displaySlider = false;
  159. if (false !== $id) {
  160. $this->view->displaySlider = true;
  161. $feedDAO = FreshRSS_Factory::createFeedDao();
  162. $this->view->feed = $feedDAO->searchById($id);
  163. }
  164. }
  165. /**
  166. * This action handles the article repartition statistic page.
  167. *
  168. * It displays the number of article and the average of article for the
  169. * following periods:
  170. * - hour of the day
  171. * - day of the week
  172. * - month
  173. *
  174. * @todo verify that the metrics used here make some sense. Especially
  175. * for the average.
  176. */
  177. public function repartitionAction(): void {
  178. $statsDAO = FreshRSS_Factory::createStatsDAO();
  179. $categoryDAO = FreshRSS_Factory::createCategoryDao();
  180. $feedDAO = FreshRSS_Factory::createFeedDao();
  181. FreshRSS_View::appendScript(Minz_Url::display('/scripts/vendor/chart.min.js?' . @filemtime(PUBLIC_PATH . '/scripts/vendor/chart.min.js')));
  182. $id = Minz_Request::param('id', null);
  183. $this->view->categories = $categoryDAO->listCategories();
  184. $this->view->feed = $feedDAO->searchById($id);
  185. $this->view->days = $statsDAO->getDays();
  186. $this->view->months = $statsDAO->getMonths();
  187. $this->view->repartition = $statsDAO->calculateEntryRepartitionPerFeed($id);
  188. $this->view->repartitionHour = $statsDAO->calculateEntryRepartitionPerFeedPerHour($id);
  189. $this->view->averageHour = $statsDAO->calculateEntryAveragePerFeedPerHour($id);
  190. $this->view->repartitionDayOfWeek = $statsDAO->calculateEntryRepartitionPerFeedPerDayOfWeek($id);
  191. $this->view->averageDayOfWeek = $statsDAO->calculateEntryAveragePerFeedPerDayOfWeek($id);
  192. $this->view->repartitionMonth = $statsDAO->calculateEntryRepartitionPerFeedPerMonth($id);
  193. $this->view->averageMonth = $statsDAO->calculateEntryAveragePerFeedPerMonth($id);
  194. $hours24Labels = [];
  195. for ($i = 0; $i < 24; $i++) {
  196. $hours24Labels[$i] = $i . ':xx';
  197. }
  198. $this->view->hours24Labels = $hours24Labels;
  199. }
  200. }